Skip to content

Instantly share code, notes, and snippets.

@elliotf
Last active December 16, 2015 21:59
Show Gist options
  • Save elliotf/5503389 to your computer and use it in GitHub Desktop.
Save elliotf/5503389 to your computer and use it in GitHub Desktop.
compiled js template benchmarks
// version 0.4.3
var Haml;
(function () {
var matchers, self_close_tags, embedder, forceXML, escaperName, escapeHtmlByDefault;
function html_escape(text) {
return (text + "").
replace(/&/g, "&").
replace(/</g, "&lt;").
replace(/>/g, "&gt;").
replace(/\"/g, "&quot;");
}
function render_attribs(attribs) {
var key, value, result = [];
for (key in attribs) {
if (key !== '_content' && attribs.hasOwnProperty(key)) {
switch (attribs[key]) {
case 'undefined':
case 'false':
case 'null':
case '""':
break;
default:
try {
value = JSON.parse("[" + attribs[key] +"]")[0];
if (value === true) {
value = key;
} else if (typeof value === 'string' && embedder.test(value)) {
value = '" +\n' + parse_interpol(html_escape(value)) + ' +\n"';
} else {
value = html_escape(value);
}
result.push(" " + key + '=\\"' + value + '\\"');
} catch (e) {
result.push(" " + key + '=\\"" + '+escaperName+'(' + attribs[key] + ') + "\\"');
}
}
}
}
return result.join("");
}
// 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 type="text/javascript">\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;
}
// version 0.30.0
var jade=function(){function require(p){var path=require.resolve(p),mod=require.modules[path];if(!mod)throw new Error('failed to require "'+p+'"');return mod.exports||(mod.exports={},mod.call(mod.exports,mod,mod.exports,require.relative(path))),mod.exports}return require.modules={},require.resolve=function(path){var orig=path,reg=path+".js",index=path+"/index.js";return require.modules[reg]&&reg||require.modules[index]&&index||orig},require.register=function(path,fn){require.modules[path]=fn},require.relative=function(parent){return function(p){if("."!=p.charAt(0))return require(p);var path=parent.split("/"),segs=p.split("/");path.pop();for(var i=0;i<segs.length;i++){var seg=segs[i];".."==seg?path.pop():"."!=seg&&path.push(seg)}return require(path.join("/"))}},require.register("compiler.js",function(module,exports,require){function isConstant(val){if(/^ *("([^"\\]*(\\.[^"\\]*)*)"|'([^'\\]*(\\.[^'\\]*)*)'|true|false|null|undefined) *$/i.test(val))return!0;if(!isNaN(Number(val)))return!0;var matches;return(matches=/^ *\[(.*)\] *$/.exec(val))?matches[1].split(",").every(isConstant):!1}var nodes=require("./nodes"),filters=require("./filters"),doctypes=require("./doctypes"),selfClosing=require("./self-closing"),runtime=require("./runtime"),utils=require("./utils"),parseJSExpression=require("character-parser").parseMax;Object.keys||(Object.keys=function(obj){var arr=[];for(var key in obj)obj.hasOwnProperty(key)&&arr.push(key);return arr}),String.prototype.trimLeft||(String.prototype.trimLeft=function(){return this.replace(/^\s+/,"")});var Compiler=module.exports=function Compiler(node,options){this.options=options=options||{},this.node=node,this.hasCompiledDoctype=!1,this.hasCompiledTag=!1,this.pp=options.pretty||!1,this.debug=!1!==options.compileDebug,this.indents=0,this.parentIndents=0,options.doctype&&this.setDoctype(options.doctype)};Compiler.prototype={compile:function(){return this.buf=[],this.pp&&this.buf.push("jade.indent = [];"),this.lastBufferedIdx=-1,this.visit(this.node),this.buf.join("\n")},setDoctype:function(name){name=name&&name.toLowerCase()||"default",this.doctype=doctypes[name]||"<!DOCTYPE "+name+">",this.terse=this.doctype.toLowerCase()=="<!doctype html>",this.xml=0==this.doctype.indexOf("<?xml")},buffer:function(str,interpolate){var self=this;if(interpolate){var match=/(\\)?([#!]){((?:.|\n)*)$/.exec(str);if(match){this.buffer(str.substr(0,match.index),!1);if(match[1]){this.buffer(match[2]+"{",!1),this.buffer(match[3],!0);return}try{var rest=match[3],range=parseJSExpression(rest),code=("!"==match[2]?"":"jade.escape")+"((jade.interp = "+range.src+") == null ? '' : jade.interp)"}catch(ex){throw ex}this.bufferExpression(code),this.buffer(rest.substr(range.end+1),!0);return}}str=JSON.stringify(str),str=str.substr(1,str.length-2),this.lastBufferedIdx==this.buf.length?(this.lastBufferedType==="code"&&(this.lastBuffered+=' + "'),this.lastBufferedType="text",this.lastBuffered+=str,this.buf[this.lastBufferedIdx-1]="buf.push("+this.bufferStartChar+this.lastBuffered+'");'):(this.buf.push('buf.push("'+str+'");'),this.lastBufferedType="text",this.bufferStartChar='"',this.lastBuffered=str,this.lastBufferedIdx=this.buf.length)},bufferExpression:function(src){this.lastBufferedIdx==this.buf.length?(this.lastBufferedType==="text"&&(this.lastBuffered+='"'),this.lastBufferedType="code",this.lastBuffered+=" + ("+src+")",this.buf[this.lastBufferedIdx-1]="buf.push("+this.bufferStartChar+this.lastBuffered+");"):(this.buf.push("buf.push("+src+");"),this.lastBufferedType="code",this.bufferStartChar="",this.lastBuffered="("+src+")",this.lastBufferedIdx=this.buf.length)},prettyIndent:function(offset,newline){offset=offset||0,newline=newline?"\n":"",this.buffer(newline+Array(this.indents+offset).join(" ")),this.parentIndents&&this.buf.push("buf.push.apply(buf, jade.indent);")},visit:function(node){var debug=this.debug;debug&&this.buf.push("jade.debug.unshift({ lineno: "+node.line+", filename: "+(node.filename?JSON.stringify(node.filename):"jade.debug[0].filename")+" });"),!1===node.debug&&this.debug&&(this.buf.pop(),this.buf.pop()),this.visitNode(node),debug&&this.buf.push("jade.debug.shift();")},visitNode:function(node){var name=node.constructor.name||node.constructor.toString().match(/function ([^(\s]+)()/)[1];return this["visit"+name](node)},visitCase:function(node){var _=this.withinCase;this.withinCase=!0,this.buf.push("switch ("+node.expr+"){"),this.visit(node.block),this.buf.push("}"),this.withinCase=_},visitWhen:function(node){"default"==node.expr?this.buf.push("default:"):this.buf.push("case "+node.expr+":"),this.visit(node.block),this.buf.push(" break;")},visitLiteral:function(node){this.buffer(node.str)},visitBlock:function(block){var len=block.nodes.length,escape=this.escape,pp=this.pp;if(this.parentIndents&&block.mode){pp&&this.buf.push("jade.indent.push('"+Array(this.indents+1).join(" ")+"');"),this.buf.push("block && block();"),pp&&this.buf.push("jade.indent.pop();");return}pp&&len>1&&!escape&&block.nodes[0].isText&&block.nodes[1].isText&&this.prettyIndent(1,!0);for(var i=0;i<len;++i)pp&&i>0&&!escape&&block.nodes[i].isText&&block.nodes[i-1].isText&&this.prettyIndent(1,!1),this.visit(block.nodes[i]),block.nodes[i+1]&&block.nodes[i].isText&&block.nodes[i+1].isText&&this.buffer("\n")},visitDoctype:function(doctype){doctype&&(doctype.val||!this.doctype)&&this.setDoctype(doctype.val||"default"),this.doctype&&this.buffer(this.doctype),this.hasCompiledDoctype=!0},visitMixin:function(mixin){var name=mixin.name.replace(/-/g,"_")+"_mixin",args=mixin.args||"",block=mixin.block,attrs=mixin.attrs,pp=this.pp;if(mixin.call){pp&&this.buf.push("jade.indent.push('"+Array(this.indents+1).join(" ")+"');");if(block||attrs.length){this.buf.push(name+".call({");if(block){this.buf.push("block: function(){"),this.parentIndents++;var _indents=this.indents;this.indents=0,this.visit(mixin.block),this.indents=_indents,this.parentIndents--,attrs.length?this.buf.push("},"):this.buf.push("}")}if(attrs.length){var val=this.attrs(attrs);val.inherits?this.buf.push("attributes: jade.merge({"+val.buf+"}, attributes), escaped: jade.merge("+val.escaped+", escaped, true)"):this.buf.push("attributes: {"+val.buf+"}, escaped: "+val.escaped)}args?this.buf.push("}, "+args+");"):this.buf.push("});")}else this.buf.push(name+"("+args+");");pp&&this.buf.push("jade.indent.pop();")}else this.buf.push("var "+name+" = function("+args+"){"),this.buf.push("var block = this.block, attributes = this.attributes || {}, escaped = this.escaped || {};"),this.parentIndents++,this.visit(block),this.parentIndents--,this.buf.push("};")},visitTag:function(tag){function bufferName(){tag.buffer?self.bufferExpression(name):self.buffer(name)}this.indents++;var name=tag.name,pp=this.pp,self=this;this.hasCompiledTag||(!this.hasCompiledDoctype&&"html"==name&&this.visitDoctype(),this.hasCompiledTag=!0),pp&&!tag.isInline()&&this.prettyIndent(0,!0),(~selfClosing.indexOf(name)||tag.selfClosing)&&!this.xml?(this.buffer("<"),bufferName(),this.visitAttributes(tag.attrs),this.terse?this.buffer(">"):this.buffer("/>")):(tag.attrs.length?(this.buffer("<"),bufferName(),tag.attrs.length&&this.visitAttributes(tag.attrs),this.buffer(">")):(this.buffer("<"),bufferName(),this.buffer(">")),tag.code&&this.visitCode(tag.code),this.escape="pre"==tag.name,this.visit(tag.block),pp&&!tag.isInline()&&"pre"!=tag.name&&!tag.canInline()&&this.prettyIndent(0,!0),this.buffer("</"),bufferName(),this.buffer(">")),this.indents--},visitFilter:function(filter){var text=filter.block.nodes.map(function(node){return node.val}).join("\n");filter.attrs=filter.attrs||{},filter.attrs.filename=this.options.filename,this.buffer(filters(filter.name,text,filter.attrs),!0)},visitText:function(text){this.buffer(text.val,!0)},visitComment:function(comment){if(!comment.buffer)return;this.pp&&this.prettyIndent(1,!0),this.buffer("<!--"+comment.val+"-->")},visitBlockComment:function(comment){if(!comment.buffer)return;0==comment.val.trim().indexOf("if")?(this.buffer("<!--["+comment.val.trim()+"]>"),this.visit(comment.block),this.buffer("<![endif]-->")):(this.buffer("<!--"+comment.val),this.visit(comment.block),this.buffer("-->"))},visitCode:function(code){if(code.buffer){var val=code.val.trimLeft();val="null == (jade.interp = "+val+') ? "" : jade.interp',code.escape&&(val="jade.escape("+val+")"),this.bufferExpression(val)}else this.buf.push(code.val);code.block&&(code.buffer||this.buf.push("{"),this.visit(code.block),code.buffer||this.buf.push("}"))},visitEach:function(each){this.buf.push("// iterate "+each.obj+"\n"+";(function(){\n"+" var $$obj = "+each.obj+";\n"+" if ('number' == typeof $$obj.length) {\n"),each.alternative&&this.buf.push(" if ($$obj.length) {"),this.buf.push(" for (var "+each.key+" = 0, $$l = $$obj.length; "+each.key+" < $$l; "+each.key+"++) {\n"+" var "+each.val+" = $$obj["+each.key+"];\n"),this.visit(each.block),this.buf.push(" }\n"),each.alternative&&(this.buf.push(" } else {"),this.visit(each.alternative),this.buf.push(" }")),this.buf.push(" } else {\n var $$l = 0;\n for (var "+each.key+" in $$obj) {\n"+" $$l++;"+" if ($$obj.hasOwnProperty("+each.key+")){"+" var "+each.val+" = $$obj["+each.key+"];\n"),this.visit(each.block),this.buf.push(" }\n"),this.buf.push(" }\n"),each.alternative&&(this.buf.push(" if ($$l === 0) {"),this.visit(each.alternative),this.buf.push(" }")),this.buf.push(" }\n}).call(this);\n")},visitAttributes:function(attrs){var val=this.attrs(attrs);val.inherits?this.bufferExpression("jade.attrs(jade.merge({ "+val.buf+" }, attributes), jade.merge("+val.escaped+", escaped, true))"):val.constant?(eval("var buf={"+val.buf+"};"),this.buffer(runtime.attrs(buf,JSON.parse(val.escaped)))):this.bufferExpression("jade.attrs({ "+val.buf+" }, "+val.escaped+")")},attrs:function(attrs){var buf=[],classes=[],escaped={},constant=attrs.every(function(attr){return isConstant(attr.val)}),inherits=!1;return this.terse&&buf.push("terse: true"),attrs.forEach(function(attr){if(attr.name=="attributes")return inherits=!0;escaped[attr.name]=attr.escaped;if(attr.name=="class")classes.push("("+attr.val+")");else{var pair="'"+attr.name+"':("+attr.val+")";buf.push(pair)}}),classes.length&&(classes=classes.join(" + ' ' + "),buf.push('"class": '+classes)),{buf:buf.join(", "),escaped:JSON.stringify(escaped),inherits:inherits,constant:constant}}}}),require.register("doctypes.js",function(module,exports,require){module.exports={5:"<!DOCTYPE html>","default":"<!DOCTYPE html>",xml:'<?xml version="1.0" encoding="utf-8" ?>',transitional:'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',strict:'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',frameset:'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',1.1:'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',basic:'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">',mobile:'<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">'}}),require.register("filters.js",function(module,exports,require){function filter(name,str,options){if(typeof filter[name]=="function")var res=filter[name](str,options);else{if(!transformers[name])throw new Error('unknown filter ":'+name+'"');var res=transformers[name].renderSync(str,options);transformers[name].outputFormat==="js"?res='<script type="text/javascript">\n'+res+"</script>":transformers[name].outputFormat==="css"?res='<style type="text/css">'+res+"</style>":transformers[name].outputFormat==="xml"&&(res=res.replace(/'/g,"&#39;"))}return res}var transformers=require("transformers");module.exports=filter,filter.exists=function(name,str,options){return typeof filter[name]=="function"||transformers[name]}}),require.register("inline-tags.js",function(module,exports,require){module.exports=["a","abbr","acronym","b","br","code","em","font","i","img","ins","kbd","map","samp","small","span","strong","sub","sup"]}),require.register("jade.js",function(module,exports,require){function parse(str,options){try{var parser=new Parser(str,options.filename,options),compiler=new(options.compiler||Compiler)(parser.parse(),options),js=compiler.compile();return options.debug&&console.error("\nCompiled Function:\n\n%s",js.replace(/^/gm," ")),"var buf = [];\n"+(options.self?"var self = locals || {};\n"+js:"with (locals || {}) {\n"+js+"\n}\n")+'return buf.join("");'}catch(err){parser=parser.context(),runtime.rethrow(err,parser.filename,parser.lexer.lineno)}}function stripBOM(str){return 65279==str.charCodeAt(0)?str.substring(1):str}var Parser=require("./parser"),Lexer=require("./lexer"),Compiler=require("./compiler"),runtime=require("./runtime");exports.version="0.30.0",exports.selfClosing=require("./self-closing"),exports.doctypes=require("./doctypes"),exports.filters=require("./filters"),exports.utils=require("./utils"),exports.Compiler=Compiler,exports.Parser=Parser,exports.Lexer=Lexer,exports.nodes=require("./nodes"),exports.runtime=runtime,exports.cache={},exports.compile=function(str,options){var options=options||{},filename=options.filename?JSON.stringify(options.filename):"undefined",fn;return str=stripBOM(String(str)),options.compileDebug!==!1?fn=["jade.debug = [{ lineno: 1, filename: "+filename+" }];","try {",parse(str,options),"} catch (err) {"," jade.rethrow(err, jade.debug[0].filename, jade.debug[0].lineno);","}"].join("\n"):fn=parse(str,options),options.client?new Function("locals",fn):(fn=new Function("locals, jade",fn),function(locals){return fn(locals,Object.create(runtime))})},exports.render=function(str,options,fn){"function"==typeof options&&(fn=options,options={});if(options.cache&&!options.filename)return fn(new Error('the "filename" option is required for caching'));try{var path=options.filename,tmpl=options.cache?exports.cache[path]||(exports.cache[path]=exports.compile(str,options)):exports.compile(str,options);fn(null,tmpl(options))}catch(err){fn(err)}},exports.renderFile=function(path,options,fn){var key=path+":string";"function"==typeof options&&(fn=options,options={});try{options.filename=path;var str=options.cache?exports.cache[key]||(exports.cache[key]=fs.readFileSync(path,"utf8")):fs.readFileSync(path,"utf8");exports.render(str,options,fn)}catch(err){fn(err)}},exports.__express=exports.renderFile}),require.register("lexer.js",function(module,exports,require){var utils=require("./utils"),parseJSExpression=require("character-parser").parseMax,Lexer=module.exports=function Lexer(str,options){options=options||{},this.input=str.replace(/\r\n|\r/g,"\n"),this.colons=options.colons,this.deferredTokens=[],this.lastIndents=0,this.lineno=1,this.stash=[],this.indentStack=[],this.indentRe=null,this.pipeless=!1};Lexer.prototype={tok:function(type,val){return{type:type,line:this.lineno,val:val}},consume:function(len){this.input=this.input.substr(len)},scan:function(regexp,type){var captures;if(captures=regexp.exec(this.input))return this.consume(captures[0].length),this.tok(type,captures[1])},defer:function(tok){this.deferredTokens.push(tok)},lookahead:function(n){var fetch=n-this.stash.length;while(fetch-->0)this.stash.push(this.next());return this.stash[--n]},bracketExpression:function(skip){skip=skip||0;var start=this.input[skip];if(start!="("&&start!="{"&&start!="[")throw new Error("unrecognized start character");var end={"(":")","{":"}","[":"]"}[start],range=parseJSExpression(this.input,{start:skip+1});if(this.input[range.end]!==end)throw new Error("start character "+start+" does not match end character "+this.input[range.end]);return range},stashed:function(){return this.stash.length&&this.stash.shift()},deferred:function(){return this.deferredTokens.length&&this.deferredTokens.shift()},eos:function(){if(this.input.length)return;return this.indentStack.length?(this.indentStack.shift(),this.tok("outdent")):this.tok("eos")},blank:function(){var captures;if(captures=/^\n *\n/.exec(this.input))return this.consume(captures[0].length-1),++this.lineno,this.pipeless?this.tok("text",""):this.next()},comment:function(){var captures;if(captures=/^ *\/\/(-)?([^\n]*)/.exec(this.input)){this.consume(captures[0].length);var tok=this.tok("comment",captures[2]);return tok.buffer="-"!=captures[1],tok}},interpolation:function(){if(/^#\{/.test(this.input)){var match;try{match=this.bracketExpression(1)}catch(ex){return}return this.consume(match.end+1),this.tok("interpolation",match.src)}},tag:function(){var captures;if(captures=/^(\w[-:\w]*)(\/?)/.exec(this.input)){this.consume(captures[0].length);var tok,name=captures[1];if(":"==name[name.length-1]){name=name.slice(0,-1),tok=this.tok("tag",name),this.defer(this.tok(":"));while(" "==this.input[0])this.input=this.input.substr(1)}else tok=this.tok("tag",name);return tok.selfClosing=!!captures[2],tok}},filter:function(){return this.scan(/^:(\w+)/,"filter")},doctype:function(){return this.scan(/^(?:!!!|doctype) *([^\n]+)?/,"doctype")},id:function(){return this.scan(/^#([\w-]+)/,"id")},className:function(){return this.scan(/^\.([\w-]+)/,"class")},text:function(){return this.scan(/^(?:\| ?| ?)?([^\n]+)/,"text")},"extends":function(){return this.scan(/^extends? +([^\n]+)/,"extends")},prepend:function(){var captures;if(captures=/^prepend +([^\n]+)/.exec(this.input)){this.consume(captures[0].length);var mode="prepend",name=captures[1],tok=this.tok("block",name);return tok.mode=mode,tok}},append:function(){var captures;if(captures=/^append +([^\n]+)/.exec(this.input)){this.consume(captures[0].length);var mode="append",name=captures[1],tok=this.tok("block",name);return tok.mode=mode,tok}},block:function(){var captures;if(captures=/^block\b *(?:(prepend|append) +)?([^\n]*)/.exec(this.input)){this.consume(captures[0].length);var mode=captures[1]||"replace",name=captures[2],tok=this.tok("block",name);return tok.mode=mode,tok}},yield:function(){return this.scan(/^yield */,"yield")},include:function(){return this.scan(/^include +([^\n]+)/,"include")},"case":function(){return this.scan(/^case +([^\n]+)/,"case")},when:function(){return this.scan(/^when +([^:\n]+)/,"when")},"default":function(){return this.scan(/^default */,"default")},assignment:function(){var captures;if(captures=/^(\w+) += *([^;\n]+)( *;? *)/.exec(this.input)){this.consume(captures[0].length);var name=captures[1],val=captures[2];return this.tok("code","var "+name+" = ("+val+");")}},call:function(){var captures;if(captures=/^\+([-\w]+)/.exec(this.input)){this.consume(captures[0].length);var tok=this.tok("call",captures[1]);if(captures=/^ *\(/.exec(this.input))try{var range=this.bracketExpression(captures[0].length-1);/^ *[-\w]+ *=/.test(range.src)||(this.consume(range.end+1),tok.args=range.src)}catch(ex){}return tok}},mixin:function(){var captures;if(captures=/^mixin +([-\w]+)(?: *\((.*)\))?/.exec(this.input)){this.consume(captures[0].length);var tok=this.tok("mixin",captures[1]);return tok.args=captures[2],tok}},conditional:function(){var captures;if(captures=/^(if|unless|else if|else)\b([^\n]*)/.exec(this.input)){this.consume(captures[0].length);var type=captures[1],js=captures[2];switch(type){case"if":js="if ("+js+")";break;case"unless":js="if (!("+js+"))";break;case"else if":js="else if ("+js+")";break;case"else":js="else"}return this.tok("code",js)}},"while":function(){var captures;if(captures=/^while +([^\n]+)/.exec(this.input))return this.consume(captures[0].length),this.tok("code","while ("+captures[1]+")")},each:function(){var captures;if(captures=/^(?:- *)?(?:each|for) +(\w+)(?: *, *(\w+))? * in *([^\n]+)/.exec(this.input)){this.consume(captures[0].length);var tok=this.tok("each",captures[1]);return tok.key=captures[2]||"$index",tok.code=captures[3],tok}},code:function(){var captures;if(captures=/^(!?=|-)[ \t]*([^\n]+)/.exec(this.input)){this.consume(captures[0].length);var flags=captures[1];captures[1]=captures[2];var tok=this.tok("code",captures[1]);return tok.escape=flags.charAt(0)==="=",tok.buffer=flags.charAt(0)==="="||flags.charAt(1)==="=",tok}},attrs:function(){if("("==this.input.charAt(0)){var index=this.bracketExpression().end,str=this.input.substr(1,index-1),tok=this.tok("attrs"),len=str.length,colons=this.colons,states=["key"],escapedAttr,key="",val="",quote,c,p;function state(){return states[states.length-1]}function interpolate(attr){return attr.replace(/(\\)?#\{(.+)/g,function(_,escape,expr){if(escape)return _;try{var range=parseJSExpression(expr);return expr[range.end]!=="}"?_.substr(0,2)+interpolate(_.substr(2)):quote+" + ("+range.src+") + "+quote+interpolate(expr.substr(range.end+1))}catch(ex){return _.substr(0,2)+interpolate(_.substr(2))}})}this.consume(index+1),tok.attrs={},tok.escaped={};function parse(c){var real=c;colons&&":"==c&&(c="=");switch(c){case",":case"\n":switch(state()){case"expr":case"array":case"string":case"object":val+=c;break;default:states.push("key"),val=val.trim(),key=key.trim();if(""==key)return;key=key.replace(/^['"]|['"]$/g,"").replace("!",""),tok.escaped[key]=escapedAttr,tok.attrs[key]=""==val?!0:interpolate(val),key=val=""}break;case"=":switch(state()){case"key char":key+=real;break;case"val":case"expr":case"array":case"string":case"object":val+=real;break;default:escapedAttr="!"!=p,states.push("val")}break;case"(":("val"==state()||"expr"==state())&&states.push("expr"),val+=c;break;case")":("expr"==state()||"val"==state())&&states.pop(),val+=c;break;case"{":"val"==state()&&states.push("object"),val+=c;break;case"}":"object"==state()&&states.pop(),val+=c;break;case"[":"val"==state()&&states.push("array"),val+=c;break;case"]":"array"==state()&&states.pop(),val+=c;break;case'"':case"'":switch(state()){case"key":states.push("key char");break;case"key char":states.pop();break;case"string":c==quote&&states.pop(),val+=c;break;default:states.push("string"),val+=c,quote=c}break;case"":break;default:switch(state()){case"key":case"key char":key+=c;break;default:val+=c}}p=c}for(var i=0;i<len;++i)parse(str.charAt(i));return parse(","),"/"==this.input.charAt(0)&&(this.consume(1),tok.selfClosing=!0),tok}},indent:function(){var captures,re;this.indentRe?captures=this.indentRe.exec(this.input):(re=/^\n(\t*) */,captures=re.exec(this.input),captures&&!captures[1].length&&(re=/^\n( *)/,captures=re.exec(this.input)),captures&&captures[1].length&&(this.indentRe=re));if(captures){var tok,indents=captures[1].length;++this.lineno,this.consume(indents+1);if(" "==this.input[0]||" "==this.input[0])throw new Error("Invalid indentation, you can use tabs or spaces but not both");if("\n"==this.input[0])return this.tok("newline");if(this.indentStack.length&&indents<this.indentStack[0]){while(this.indentStack.length&&this.indentStack[0]>indents)this.stash.push(this.tok("outdent")),this.indentStack.shift();tok=this.stash.pop()}else indents&&indents!=this.indentStack[0]?(this.indentStack.unshift(indents),tok=this.tok("indent",indents)):tok=this.tok("newline");return tok}},pipelessText:function(){if(this.pipeless){if("\n"==this.input[0])return;var i=this.input.indexOf("\n");-1==i&&(i=this.input.length);var str=this.input.substr(0,i);return this.consume(str.length),this.tok("text",str)}},colon:function(){return this.scan(/^: */,":")},advance:function(){return this.stashed()||this.next()},next:function(){return this.deferred()||this.blank()||this.eos()||this.pipelessText()||this.yield()||this.doctype()||this.interpolation()||this["case"]()||this.when()||this["default"]()||this["extends"]()||this.append()||this.prepend()||this.block()||this.include()||this.mixin()||this.call()||this.conditional()||this.each()||this["while"]()||this.assignment()||this.tag()||this.filter()||this.code()||this.id()||this.className()||this.attrs()||this.indent()||this.comment()||this.colon()||this.text()}}}),require.register("nodes/attrs.js",function(module,exports,require){var Node=require("./node"),Block=require("./block"),Attrs=module.exports=function Attrs(){this.attrs=[]};Attrs.prototype=new Node,Attrs.prototype.constructor=Attrs,Attrs.prototype.setAttribute=function(name,val,escaped){return this.attrs.push({name:name,val:val,escaped:escaped}),this},Attrs.prototype.removeAttribute=function(name){for(var i=0,len=this.attrs.length;i<len;++i)this.attrs[i]&&this.attrs[i].name==name&&delete this.attrs[i]},Attrs.prototype.getAttribute=function(name){for(var i=0,len=this.attrs.length;i<len;++i)if(this.attrs[i]&&this.attrs[i].name==name)return this.attrs[i].val}}),require.register("nodes/block-comment.js",function(module,exports,require){var Node=require("./node"),BlockComment=module.exports=function BlockComment(val,block,buffer){this.block=block,this.val=val,this.buffer=buffer};BlockComment.prototype=new Node,BlockComment.prototype.constructor=BlockComment}),require.register("nodes/block.js",function(module,exports,require){var Node=require("./node"),Block=module.exports=function Block(node){this.nodes=[],node&&this.push(node)};Block.prototype=new Node,Block.prototype.constructor=Block,Block.prototype.isBlock=!0,Block.prototype.replace=function(other){other.nodes=this.nodes},Block.prototype.push=function(node){return this.nodes.push(node)},Block.prototype.isEmpty=function(){return 0==this.nodes.length},Block.prototype.unshift=function(node){return this.nodes.unshift(node)},Block.prototype.includeBlock=function(){var ret=this,node;for(var i=0,len=this.nodes.length;i<len;++i){node=this.nodes[i];if(node.yield)return node;if(node.textOnly)continue;node.includeBlock?ret=node.includeBlock():node.block&&!node.block.isEmpty()&&(ret=node.block.includeBlock());if(ret.yield)return ret}return ret},Block.prototype.clone=function(){var clone=new Block;for(var i=0,len=this.nodes.length;i<len;++i)clone.push(this.nodes[i].clone());return clone}}),require.register("nodes/case.js",function(module,exports,require){var Node=require("./node"),Case=exports=module.exports=function Case(expr,block){this.expr=expr,this.block=block};Case.prototype=new Node,Case.prototype.constructor=Case;var When=exports.When=function When(expr,block){this.expr=expr,this.block=block,this.debug=!1};When.prototype=new Node,When.prototype.constructor=When}),require.register("nodes/code.js",function(module,exports,require){var Node=require("./node"),Code=module.exports=function Code(val,buffer,escape){this.val=val,this.buffer=buffer,this.escape=escape,val.match(/^ *else/)&&(this.debug=!1)};Code.prototype=new Node,Code.prototype.constructor=Code}),require.register("nodes/comment.js",function(module,exports,require){var Node=require("./node"),Comment=module.exports=function Comment(val,buffer){this.val=val,this.buffer=buffer};Comment.prototype=new Node,Comment.prototype.constructor=Comment}),require.register("nodes/doctype.js",function(module,exports,require){var Node=require("./node"),Doctype=module.exports=function Doctype(val){this.val=val};Doctype.prototype=new Node,Doctype.prototype.constructor=Doctype}),require.register("nodes/each.js",function(module,exports,require){var Node=require("./node"),Each=module.exports=function Each(obj,val,key,block){this.obj=obj,this.val=val,this.key=key,this.block=block};Each.prototype=new Node,Each.prototype.constructor=Each}),require.register("nodes/filter.js",function(module,exports,require){var Node=require("./node"),Block=require("./block"),Filter=module.exports=function Filter(name,block,attrs){this.name=name,this.block=block,this.attrs=attrs};Filter.prototype=new Node,Filter.prototype.constructor=Filter}),require.register("nodes/index.js",function(module,exports,require){exports.Node=require("./node"),exports.Tag=require("./tag"),exports.Code=require("./code"),exports.Each=require("./each"),exports.Case=require("./case"),exports.Text=require("./text"),exports.Block=require("./block"),exports.Mixin=require("./mixin"),exports.Filter=require("./filter"),exports.Comment=require("./comment"),exports.Literal=require("./literal"),exports.BlockComment=require("./block-comment"),exports.Doctype=require("./doctype")}),require.register("nodes/literal.js",function(module,exports,require){var Node=require("./node"),Literal=module.exports=function Literal(str){this.str=str};Literal.prototype=new Node,Literal.prototype.constructor=Literal}),require.register("nodes/mixin.js",function(module,exports,require){var Attrs=require("./attrs"),Mixin=module.exports=function Mixin(name,args,block,call){this.name=name,this.args=args,this.block=block,this.attrs=[],this.call=call};Mixin.prototype=new Attrs,Mixin.prototype.constructor=Mixin}),require.register("nodes/node.js",function(module,exports,require){var Node=module.exports=function Node(){};Node.prototype.clone=function(){return this}}),require.register("nodes/tag.js",function(module,exports,require){var Attrs=require("./attrs"),Block=require("./block"),inlineTags=require("../inline-tags"),Tag=module.exports=function Tag(name,block){this.name=name,this.attrs=[],this.block=block||new Block};Tag.prototype=new Attrs,Tag.prototype.constructor=Tag,Tag.prototype.clone=function(){var clone=new Tag(this.name,this.block.clone());return clone.line=this.line,clone.attrs=this.attrs,clone.textOnly=this.textOnly,clone},Tag.prototype.isInline=function(){return~inlineTags.indexOf(this.name)},Tag.prototype.canInline=function(){function isInline(node){return node.isBlock?node.nodes.every(isInline):node.isText||node.isInline&&node.isInline()}var nodes=this.block.nodes;if(!nodes.length)return!0;if(1==nodes.length)return isInline(nodes[0]);if(this.block.nodes.every(isInline)){for(var i=1,len=nodes.length;i<len;++i)if(nodes[i-1].isText&&nodes[i].isText)return!1;return!0}return!1}}),require.register("nodes/text.js",function(module,exports,require){var Node=require("./node"),Text=module.exports=function Text(line){this.val="","string"==typeof line&&(this.val=line)};Text.prototype=new Node,Text.prototype.constructor=Text,Text.prototype.isText=!0}),require.register("parser.js",function(module,exports,require){var Lexer=require("./lexer"),nodes=require("./nodes"),utils=require("./utils"),filters=require("./filters"),path=require("path"),extname=path.extname,Parser=exports=module.exports=function Parser(str,filename,options){this.input=str,this.lexer=new Lexer(str,options),this.filename=filename,this.blocks=[],this.mixins={},this.options=options,this.contexts=[this]},textOnly=exports.textOnly=["script","style"];Parser.prototype={context:function(parser){if(!parser)return this.contexts.pop();this.contexts.push(parser)},advance:function(){return this.lexer.advance()},skip:function(n){while(n--)this.advance()},peek:function(){return this.lookahead(1)},line:function(){return this.lexer.lineno},lookahead:function(n){return this.lexer.lookahead(n)},parse:function(){var block=new nodes.Block,parser;block.line=this.line();while("eos"!=this.peek().type)"newline"==this.peek().type?this.advance():block.push(this.parseExpr());if(parser=this.extending){this.context(parser);var ast=parser.parse();this.context();for(var name in this.mixins)ast.unshift(this.mixins[name]);return ast}return this.handleBlocks(),block},handleBlocks:function(){this.blocks.reverse();var blocksHash={};for(var i in this.blocks)if(!{}.hasOwnProperty.call(blocksHash,[this.blocks[i].name]))blocksHash[this.blocks[i].name]=this.blocks[i];else{switch(this.blocks[i].mode){case"append":blocksHash[this.blocks[i].name].nodes=blocksHash[this.blocks[i].name].nodes.concat(this.blocks[i].nodes);break;case"prepend":blocksHash[this.blocks[i].name].nodes=this.blocks[i].nodes.concat(blocksHash[this.blocks[i].name].nodes);break;default:blocksHash[this.blocks[i].name].nodes=this.blocks[i].nodes}this.blocks[i]=blocksHash[this.blocks[i].name]}},expect:function(type){if(this.peek().type===type)return this.advance();throw new Error('expected "'+type+'", but got "'+this.peek().type+'"')},accept:function(type){if(this.peek().type===type)return this.advance()},parseExpr:function(){switch(this.peek().type){case"tag":return this.parseTag();case"mixin":return this.parseMixin();case"block":return this.parseBlock();case"case":return this.parseCase();case"when":return this.parseWhen();case"default":return this.parseDefault();case"extends":return this.parseExtends();case"include":return this.parseInclude();case"doctype":return this.parseDoctype();case"filter":return this.parseFilter();case"comment":return this.parseComment();case"text":return this.parseText();case"each":return this.parseEach();case"code":return this.parseCode();case"call":return this.parseCall();case"interpolation":return this.parseInterpolation();case"yield":this.advance();var block=new nodes.Block;return block.yield=!0,block;case"id":case"class":var tok=this.advance();return this
.lexer.defer(this.lexer.tok("tag","div")),this.lexer.defer(tok),this.parseExpr();default:throw new Error('unexpected token "'+this.peek().type+'"')}},parseText:function(){var tok=this.expect("text"),node=new nodes.Text(tok.val);return node.line=this.line(),node},parseBlockExpansion:function(){return":"==this.peek().type?(this.advance(),new nodes.Block(this.parseExpr())):this.block()},parseCase:function(){var val=this.expect("case").val,node=new nodes.Case(val);return node.line=this.line(),node.block=this.block(),node},parseWhen:function(){var val=this.expect("when").val;return new nodes.Case.When(val,this.parseBlockExpansion())},parseDefault:function(){return this.expect("default"),new nodes.Case.When("default",this.parseBlockExpansion())},parseCode:function(){var tok=this.expect("code"),node=new nodes.Code(tok.val,tok.buffer,tok.escape),block,i=1;node.line=this.line();while(this.lookahead(i)&&"newline"==this.lookahead(i).type)++i;return block="indent"==this.lookahead(i).type,block&&(this.skip(i-1),node.block=this.block()),node},parseComment:function(){var tok=this.expect("comment"),node;return"indent"==this.peek().type?node=new nodes.BlockComment(tok.val,this.block(),tok.buffer):node=new nodes.Comment(tok.val,tok.buffer),node.line=this.line(),node},parseDoctype:function(){var tok=this.expect("doctype"),node=new nodes.Doctype(tok.val);return node.line=this.line(),node},parseFilter:function(){var tok=this.expect("filter"),attrs=this.accept("attrs"),block;this.lexer.pipeless=!0,block=this.parseTextBlock(),this.lexer.pipeless=!1;var node=new nodes.Filter(tok.val,block,attrs&&attrs.attrs);return node.line=this.line(),node},parseEach:function(){var tok=this.expect("each"),node=new nodes.Each(tok.code,tok.val,tok.key);return node.line=this.line(),node.block=this.block(),this.peek().type=="code"&&this.peek().val=="else"&&(this.advance(),node.alternative=this.block()),node},resolvePath:function(path,purpose){var p=require("path"),dirname=p.dirname,basename=p.basename,join=p.join;if(path[0]!=="/"&&!this.filename)throw new Error('the "filename" option is required to use "'+purpose+'" with "relative" paths');if(path[0]==="/"&&!this.options.basedir)throw new Error('the "basedir" option is required to use "'+purpose+'" with "absolute" paths');return path=join(path[0]==="/"?this.options.basedir:dirname(this.filename),path),basename(path).indexOf(".")===-1&&(path+=".jade"),path},parseExtends:function(){var fs=require("fs"),path=this.resolvePath(this.expect("extends").val.trim(),"extends");".jade"!=path.substr(-5)&&(path+=".jade");var str=fs.readFileSync(path,"utf8"),parser=new Parser(str,path,this.options);return parser.blocks=this.blocks.reverse(),parser.contexts=this.contexts,this.extending=parser,new nodes.Literal("")},parseBlock:function(){var block=this.expect("block"),mode=block.mode,name=block.val.trim();return block="indent"==this.peek().type?this.block():new nodes.Block(new nodes.Literal("")),block.mode=mode,block.name=name,this.blocks.push(block),block},parseInclude:function(){var fs=require("fs"),path=this.resolvePath(this.expect("include").val.trim(),"include");if(".jade"!=path.substr(-5)){var str=fs.readFileSync(path,"utf8").replace(/\r/g,""),ext=extname(path).slice(1);return filters.exists(ext)&&(str=filters(ext,str,{filename:path})),new nodes.Literal(str)}var str=fs.readFileSync(path,"utf8"),parser=new Parser(str,path,this.options);parser.blocks=utils.merge([],this.blocks),parser.mixins=this.mixins,this.context(parser);var ast=parser.parse();return this.context(),ast.filename=path,"indent"==this.peek().type&&ast.includeBlock().push(this.block()),ast},parseCall:function(){var tok=this.expect("call"),name=tok.val,args=tok.args,mixin=new nodes.Mixin(name,args,new nodes.Block,!0);return this.tag(mixin),mixin.block.isEmpty()&&(mixin.block=null),mixin},parseMixin:function(){var tok=this.expect("mixin"),name=tok.val,args=tok.args,mixin;return"indent"==this.peek().type?(mixin=new nodes.Mixin(name,args,this.block(),!1),this.mixins[name]=mixin,mixin):new nodes.Mixin(name,args,null,!0)},parseTextBlock:function(){var block=new nodes.Block;block.line=this.line();var spaces=this.expect("indent").val;null==this._spaces&&(this._spaces=spaces);var indent=Array(spaces-this._spaces+1).join(" ");while("outdent"!=this.peek().type)switch(this.peek().type){case"newline":this.advance();break;case"indent":this.parseTextBlock().nodes.forEach(function(node){block.push(node)});break;default:var text=new nodes.Text(indent+this.advance().val);text.line=this.line(),block.push(text)}return spaces==this._spaces&&(this._spaces=null),this.expect("outdent"),block},block:function(){var block=new nodes.Block;block.line=this.line(),this.expect("indent");while("outdent"!=this.peek().type)"newline"==this.peek().type?this.advance():block.push(this.parseExpr());return this.expect("outdent"),block},parseInterpolation:function(){var tok=this.advance(),tag=new nodes.Tag(tok.val);return tag.buffer=!0,this.tag(tag)},parseTag:function(){var i=2;"attrs"==this.lookahead(i).type&&++i;var tok=this.advance(),tag=new nodes.Tag(tok.val);return tag.selfClosing=tok.selfClosing,this.tag(tag)},tag:function(tag){var dot;tag.line=this.line();e:for(;;)switch(this.peek().type){case"id":case"class":var tok=this.advance();tag.setAttribute(tok.type,"'"+tok.val+"'");continue;case"attrs":var tok=this.advance(),obj=tok.attrs,escaped=tok.escaped,names=Object.keys(obj);tok.selfClosing&&(tag.selfClosing=!0);for(var i=0,len=names.length;i<len;++i){var name=names[i],val=obj[name];tag.setAttribute(name,val,escaped[name])}continue;default:break e}"."==this.peek().val&&(dot=tag.textOnly=!0,this.advance());switch(this.peek().type){case"text":tag.block.push(this.parseText());break;case"code":tag.code=this.parseCode();break;case":":this.advance(),tag.block=new nodes.Block,tag.block.push(this.parseExpr())}while("newline"==this.peek().type)this.advance();tag.textOnly=tag.textOnly||~textOnly.indexOf(tag.name);if("script"==tag.name){var type=tag.getAttribute("type");!dot&&type&&"text/javascript"!=type.replace(/^['"]|['"]$/g,"")&&(tag.textOnly=!1)}if("indent"==this.peek().type)if(tag.textOnly)this.lexer.pipeless=!0,tag.block=this.parseTextBlock(),this.lexer.pipeless=!1;else{var block=this.block();if(tag.block)for(var i=0,len=block.nodes.length;i<len;++i)tag.block.push(block.nodes[i]);else tag.block=block}return tag}}}),require.register("runtime.js",function(module,exports,require){function nulls(val){return val!=null}Array.isArray||(Array.isArray=function(arr){return"[object Array]"==Object.prototype.toString.call(arr)}),Object.keys||(Object.keys=function(obj){var arr=[];for(var key in obj)obj.hasOwnProperty(key)&&arr.push(key);return arr}),exports.merge=function merge(a,b){var ac=a["class"],bc=b["class"];if(ac||bc)ac=ac||[],bc=bc||[],Array.isArray(ac)||(ac=[ac]),Array.isArray(bc)||(bc=[bc]),ac=ac.filter(nulls),bc=bc.filter(nulls),a["class"]=ac.concat(bc).join(" ");for(var key in b)key!="class"&&(a[key]=b[key]);return a},exports.attrs=function attrs(obj,escaped){var buf=[],terse=obj.terse;delete obj.terse;var keys=Object.keys(obj),len=keys.length;if(len){buf.push("");for(var i=0;i<len;++i){var key=keys[i],val=obj[key];"boolean"==typeof val||null==val?val&&(terse?buf.push(key):buf.push(key+'="'+key+'"')):0==key.indexOf("data")&&"string"!=typeof val?buf.push(key+"='"+JSON.stringify(val)+"'"):"class"==key&&Array.isArray(val)?buf.push(key+'="'+exports.escape(val.join(" "))+'"'):escaped&&escaped[key]?buf.push(key+'="'+exports.escape(val)+'"'):buf.push(key+'="'+val+'"')}}return buf.join(" ")},exports.escape=function escape(html){return String(html).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")},exports.rethrow=function rethrow(err,filename,lineno){if(!filename)throw err;if(typeof window!="undefined")throw err;var context=3,str=require("fs").readFileSync(filename,"utf8"),lines=str.split("\n"),start=Math.max(lineno-context,0),end=Math.min(lines.length,lineno+context),context=lines.slice(start,end).map(function(line,i){var curr=i+start+1;return(curr==lineno?" > ":" ")+curr+"| "+line}).join("\n");throw err.path=filename,err.message=(filename||"Jade")+":"+lineno+"\n"+context+"\n\n"+err.message,err}}),require.register("self-closing.js",function(module,exports,require){module.exports=["meta","img","link","input","source","area","base","col","br","hr"]}),require.register("utils.js",function(module,exports,require){exports.merge=function(a,b){for(var key in b)a[key]=b[key];return a}}),require("jade")}();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment