Adds and updates vendor modules.
authordsc <david.schoonover@gmail.com>
Fri, 17 Feb 2012 22:43:08 +0000 (14:43 -0800)
committerdsc <david.schoonover@gmail.com>
Fri, 17 Feb 2012 22:43:08 +0000 (14:43 -0800)
static/vendor/dygraph.min.js [moved from static/vendor/dygraph-combined.js with 100% similarity]
static/vendor/jade.js [new file with mode: 0644]
static/vendor/jade.min.js [new file with mode: 0644]
static/vendor/jquery.mustache.js
static/vendor/jquery.mustache.min.js [new file with mode: 0644]
static/vendor/underscore-1.3.1.js [new file with mode: 0644]
static/vendor/underscore-1.3.1.min.js [new file with mode: 0644]
static/vendor/underscore.js
static/vendor/underscore.min.js
www/modules.yaml

diff --git a/static/vendor/jade.js b/static/vendor/jade.js
new file mode 100644 (file)
index 0000000..22072f1
--- /dev/null
@@ -0,0 +1,3140 @@
+(function() {
+
+// CommonJS require()
+
+function require(p){
+    var path = require.resolve(p)
+      , mod = require.modules[path];
+    if (!mod) throw new Error('failed to require "' + p + '"');
+    if (!mod.exports) {
+      mod.exports = {};
+      mod.call(mod.exports, mod, mod.exports, require.relative(path));
+    }
+    return mod.exports;
+  }
+
+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[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];
+        if ('..' == seg) path.pop();
+        else if ('.' != seg) path.push(seg);
+      }
+
+      return require(path.join('/'));
+    };
+  };
+
+
+require.register("compiler.js", function(module, exports, require){
+
+/*!
+ * Jade - Compiler
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var nodes = require('./nodes')
+  , filters = require('./filters')
+  , doctypes = require('./doctypes')
+  , selfClosing = require('./self-closing')
+  , inlineTags = require('./inline-tags')
+  , utils = require('./utils');
+
+ if (!Object.keys) {
+   Object.keys = function(obj){
+     var arr = [];
+     for (var key in obj) {
+       if (obj.hasOwnProperty(key)) {
+         arr.push(key);
+       }
+     }
+     return arr;
+   } 
+ }
+ if (!String.prototype.trimLeft) {
+   String.prototype.trimLeft = function(){
+     return this.replace(/^\s+/, '');
+   }
+ }
+
+
+
+/**
+ * Initialize `Compiler` with the given `node`.
+ *
+ * @param {Node} node
+ * @param {Object} options
+ * @api public
+ */
+
+var Compiler = module.exports = function Compiler(node, options) {
+  this.options = options = options || {};
+  this.node = node;
+  this.hasCompiledDoctype = false;
+  this.hasCompiledTag = false;
+  this.pp = options.pretty || false;
+  this.debug = false !== options.compileDebug;
+  this.indents = 0;
+  if (options.doctype) this.setDoctype(options.doctype);
+};
+
+/**
+ * Compiler prototype.
+ */
+
+Compiler.prototype = {
+  
+  /**
+   * Compile parse tree to JavaScript.
+   *
+   * @api public
+   */
+  
+  compile: function(){
+    this.buf = ['var interp;'];
+    this.lastBufferedIdx = -1
+    this.visit(this.node);
+    return this.buf.join('\n');
+  },
+
+  /**
+   * Sets the default doctype `name`. Sets terse mode to `true` when
+   * html 5 is used, causing self-closing tags to end with ">" vs "/>",
+   * and boolean attributes are not mirrored.
+   *
+   * @param {string} name
+   * @api public
+   */
+  
+  setDoctype: function(name){
+    var doctype = doctypes[(name || 'default').toLowerCase()];
+    doctype = doctype || '<!DOCTYPE ' + name + '>';
+    this.doctype = doctype;
+    this.terse = '5' == name || 'html' == name;
+    this.xml = 0 == this.doctype.indexOf('<?xml');
+  },
+  
+  /**
+   * Buffer the given `str` optionally escaped.
+   *
+   * @param {String} str
+   * @param {Boolean} esc
+   * @api public
+   */
+  
+  buffer: function(str, esc){
+    if (esc) str = utils.escape(str);
+    
+    if (this.lastBufferedIdx == this.buf.length) {
+      this.lastBuffered += str;
+      this.buf[this.lastBufferedIdx - 1] = "buf.push('" + this.lastBuffered + "');"
+    } else {
+      this.buf.push("buf.push('" + str + "');");
+      this.lastBuffered = str;
+      this.lastBufferedIdx = this.buf.length;
+    }    
+  },
+  
+  /**
+   * Visit `node`.
+   *
+   * @param {Node} node
+   * @api public
+   */
+  
+  visit: function(node){
+    var debug = this.debug;
+
+    if (debug) {
+      this.buf.push('__jade.unshift({ lineno: ' + node.line
+        + ', filename: ' + (node.filename
+          ? '"' + node.filename + '"'
+          : '__jade[0].filename')
+        + ' });');
+    }
+
+    // Massive hack to fix our context
+    // stack for - else[ if] etc
+    if (false === node.debug && this.debug) {
+      this.buf.pop();
+      this.buf.pop();
+    }
+
+    this.visitNode(node);
+
+    if (debug) this.buf.push('__jade.shift();');
+  },
+  
+  /**
+   * Visit `node`.
+   *
+   * @param {Node} node
+   * @api public
+   */
+  
+  visitNode: function(node){
+    var name = node.constructor.name
+      || node.constructor.toString().match(/function ([^(\s]+)()/)[1];
+    return this['visit' + name](node);
+  },
+
+  /**
+   * Visit case `node`.
+   *
+   * @param {Literal} node
+   * @api public
+   */
+
+  visitCase: function(node){
+    var _ = this.withinCase;
+    this.withinCase = true;
+    this.buf.push('switch (' + node.expr + '){');
+    this.visit(node.block);
+    this.buf.push('}');
+    this.withinCase = _;
+  },
+  
+  /**
+   * Visit when `node`.
+   *
+   * @param {Literal} node
+   * @api public
+   */
+
+  visitWhen: function(node){
+    if ('default' == node.expr) {
+      this.buf.push('default:');
+    } else {
+      this.buf.push('case ' + node.expr + ':');
+    }
+    this.visit(node.block);
+    this.buf.push('  break;');
+  },
+
+  /**
+   * Visit literal `node`.
+   *
+   * @param {Literal} node
+   * @api public
+   */
+
+  visitLiteral: function(node){
+    var str = node.str.replace(/\n/g, '\\\\n');
+    this.buffer(str);
+  },
+
+  /**
+   * Visit all nodes in `block`.
+   *
+   * @param {Block} block
+   * @api public
+   */
+
+  visitBlock: function(block){
+    var len = block.nodes.length;
+    for (var i = 0; i < len; ++i) {
+      this.visit(block.nodes[i]);
+    }
+  },
+  
+  /**
+   * Visit `doctype`. Sets terse mode to `true` when html 5
+   * is used, causing self-closing tags to end with ">" vs "/>",
+   * and boolean attributes are not mirrored.
+   *
+   * @param {Doctype} doctype
+   * @api public
+   */
+  
+  visitDoctype: function(doctype){
+    if (doctype && (doctype.val || !this.doctype)) {
+      this.setDoctype(doctype.val || 'default');
+    }
+
+    if (this.doctype) this.buffer(this.doctype);
+    this.hasCompiledDoctype = true;
+  },
+
+  /**
+   * Visit `mixin`, generating a function that
+   * may be called within the template.
+   *
+   * @param {Mixin} mixin
+   * @api public
+   */
+
+  visitMixin: function(mixin){
+    var name = mixin.name.replace(/-/g, '_') + '_mixin'
+      , args = mixin.args || '';
+
+    if (mixin.block) {
+      this.buf.push('var ' + name + ' = function(' + args + '){');
+      this.visit(mixin.block);
+      this.buf.push('}');
+    } else {
+      this.buf.push(name + '(' + args + ');');
+    }
+  },
+
+  /**
+   * Visit `tag` buffering tag markup, generating
+   * attributes, visiting the `tag`'s code and block.
+   *
+   * @param {Tag} tag
+   * @api public
+   */
+  
+  visitTag: function(tag){
+    this.indents++;
+    var name = tag.name;
+
+    if (!this.hasCompiledTag) {
+      if (!this.hasCompiledDoctype && 'html' == name) {
+        this.visitDoctype();
+      }
+      this.hasCompiledTag = true;
+    }
+
+    // pretty print
+    if (this.pp && inlineTags.indexOf(name) == -1) {
+      this.buffer('\\n' + Array(this.indents).join('  '));
+    }
+
+    if (~selfClosing.indexOf(name) && !this.xml) {
+      this.buffer('<' + name);
+      this.visitAttributes(tag.attrs);
+      this.terse
+        ? this.buffer('>')
+        : this.buffer('/>');
+    } else {
+      // Optimize attributes buffering
+      if (tag.attrs.length) {
+        this.buffer('<' + name);
+        if (tag.attrs.length) this.visitAttributes(tag.attrs);
+        this.buffer('>');
+      } else {
+        this.buffer('<' + name + '>');
+      }
+      if (tag.code) this.visitCode(tag.code);
+      if (tag.text) this.buffer(utils.text(tag.text.nodes[0].trimLeft()));
+      this.escape = 'pre' == tag.name;
+      this.visit(tag.block);
+
+      // pretty print
+      if (this.pp && !~inlineTags.indexOf(name) && !tag.textOnly) {
+        this.buffer('\\n' + Array(this.indents).join('  '));
+      }
+
+      this.buffer('</' + name + '>');
+    }
+    this.indents--;
+  },
+  
+  /**
+   * Visit `filter`, throwing when the filter does not exist.
+   *
+   * @param {Filter} filter
+   * @api public
+   */
+  
+  visitFilter: function(filter){
+    var fn = filters[filter.name];
+
+    // unknown filter
+    if (!fn) {
+      if (filter.isASTFilter) {
+        throw new Error('unknown ast filter "' + filter.name + ':"');
+      } else {
+        throw new Error('unknown filter ":' + filter.name + '"');
+      }
+    }
+    if (filter.isASTFilter) {
+      this.buf.push(fn(filter.block, this, filter.attrs));
+    } else {
+      var text = filter.block.nodes.join('');
+      this.buffer(utils.text(fn(text, filter.attrs)));
+    }
+  },
+  
+  /**
+   * Visit `text` node.
+   *
+   * @param {Text} text
+   * @api public
+   */
+  
+  visitText: function(text){
+    text = utils.text(text.nodes.join(''));
+    if (this.escape) text = escape(text);
+    this.buffer(text);
+    this.buffer('\\n');
+  },
+  
+  /**
+   * Visit a `comment`, only buffering when the buffer flag is set.
+   *
+   * @param {Comment} comment
+   * @api public
+   */
+  
+  visitComment: function(comment){
+    if (!comment.buffer) return;
+    if (this.pp) this.buffer('\\n' + Array(this.indents + 1).join('  '));
+    this.buffer('<!--' + utils.escape(comment.val) + '-->');
+  },
+  
+  /**
+   * Visit a `BlockComment`.
+   *
+   * @param {Comment} comment
+   * @api public
+   */
+  
+  visitBlockComment: function(comment){
+    if (!comment.buffer) return;
+    if (0 == comment.val.trim().indexOf('if')) {
+      this.buffer('<!--[' + comment.val.trim() + ']>');
+      this.visit(comment.block);
+      this.buffer('<![endif]-->');
+    } else {
+      this.buffer('<!--' + comment.val);
+      this.visit(comment.block);
+      this.buffer('-->');
+    }
+  },
+  
+  /**
+   * Visit `code`, respecting buffer / escape flags.
+   * If the code is followed by a block, wrap it in
+   * a self-calling function.
+   *
+   * @param {Code} code
+   * @api public
+   */
+  
+  visitCode: function(code){
+    // Wrap code blocks with {}.
+    // we only wrap unbuffered code blocks ATM
+    // since they are usually flow control
+
+    // Buffer code
+    if (code.buffer) {
+      var val = code.val.trimLeft();
+      this.buf.push('var __val__ = ' + val);
+      val = 'null == __val__ ? "" : __val__';
+      if (code.escape) val = 'escape(' + val + ')';
+      this.buf.push("buf.push(" + val + ");");
+    } else {
+      this.buf.push(code.val);
+    }
+
+    // Block support
+    if (code.block) {
+      if (!code.buffer) this.buf.push('{');
+      this.visit(code.block);
+      if (!code.buffer) this.buf.push('}');
+    }
+  },
+  
+  /**
+   * Visit `each` block.
+   *
+   * @param {Each} each
+   * @api public
+   */
+  
+  visitEach: function(each){
+    this.buf.push(''
+      + '// iterate ' + each.obj + '\n'
+      + '(function(){\n'
+      + '  if (\'number\' == typeof ' + each.obj + '.length) {\n'
+      + '    for (var ' + each.key + ' = 0, $$l = ' + each.obj + '.length; ' + each.key + ' < $$l; ' + each.key + '++) {\n'
+      + '      var ' + each.val + ' = ' + each.obj + '[' + each.key + '];\n');
+
+    this.visit(each.block);
+
+    this.buf.push(''
+      + '    }\n'
+      + '  } else {\n'
+      + '    for (var ' + each.key + ' in ' + each.obj + ') {\n'
+       + '      if (' + each.obj + '.hasOwnProperty(' + each.key + ')){'
+      + '      var ' + each.val + ' = ' + each.obj + '[' + each.key + '];\n');
+
+    this.visit(each.block);
+
+     this.buf.push('      }\n');
+
+    this.buf.push('   }\n  }\n}).call(this);\n');
+  },
+  
+  /**
+   * Visit `attrs`.
+   *
+   * @param {Array} attrs
+   * @api public
+   */
+  
+  visitAttributes: function(attrs){
+    var buf = []
+      , classes = [];
+
+    if (this.terse) buf.push('terse: true');
+
+    attrs.forEach(function(attr){
+      if (attr.name == 'class') {
+        classes.push('(' + attr.val + ')');
+      } else {
+        var pair = "'" + attr.name + "':(" + attr.val + ')';
+        buf.push(pair);
+      }
+    });
+
+    if (classes.length) {
+      classes = classes.join(" + ' ' + ");
+      buf.push("class: " + classes);
+    }
+
+    buf = buf.join(', ').replace('class:', '"class":');
+
+    this.buf.push("buf.push(attrs({ " + buf + " }));");
+  }
+};
+
+/**
+ * Escape the given string of `html`.
+ *
+ * @param {String} html
+ * @return {String}
+ * @api private
+ */
+
+function escape(html){
+  return String(html)
+    .replace(/&(?!\w+;)/g, '&amp;')
+    .replace(/</g, '&lt;')
+    .replace(/>/g, '&gt;')
+    .replace(/"/g, '&quot;');
+}
+
+}); // module: compiler.js
+
+require.register("doctypes.js", function(module, exports, require){
+
+/*!
+ * Jade - doctypes
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+module.exports = {
+    '5': '<!DOCTYPE html>'
+  , 'xml': '<?xml version="1.0" encoding="utf-8" ?>'
+  , 'default': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
+  , '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">'
+};
+}); // module: doctypes.js
+
+require.register("filters.js", function(module, exports, require){
+
+/*!
+ * Jade - filters
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+module.exports = {
+  
+  /**
+   * Wrap text with CDATA block.
+   */
+  
+  cdata: function(str){
+    return '<![CDATA[\\n' + str + '\\n]]>';
+  },
+  
+  /**
+   * Transform sass to css, wrapped in style tags.
+   */
+  
+  sass: function(str){
+    str = str.replace(/\\n/g, '\n');
+    var sass = require('sass').render(str).replace(/\n/g, '\\n');
+    return '<style type="text/css">' + sass + '</style>'; 
+  },
+  
+  /**
+   * Transform stylus to css, wrapped in style tags.
+   */
+  
+  stylus: function(str, options){
+    var ret;
+    str = str.replace(/\\n/g, '\n');
+    var stylus = require('stylus');
+    stylus(str, options).render(function(err, css){
+      if (err) throw err;
+      ret = css.replace(/\n/g, '\\n');
+    });
+    return '<style type="text/css">' + ret + '</style>'; 
+  },
+  
+  /**
+   * Transform less to css, wrapped in style tags.
+   */
+  
+  less: function(str){
+    var ret;
+    str = str.replace(/\\n/g, '\n');
+    require('less').render(str, function(err, css){
+      if (err) throw err;
+      ret = '<style type="text/css">' + css.replace(/\n/g, '\\n') + '</style>';  
+    });
+    return ret;
+  },
+  
+  /**
+   * Transform markdown to html.
+   */
+  
+  markdown: function(str){
+    var md;
+
+    // support markdown / discount
+    try {
+      md = require('markdown');
+    } catch (err){
+      try {
+        md = require('discount');
+      } catch (err) {
+        try {
+          md = require('markdown-js');
+        } catch (err) {
+          try {
+            md = require('marked');
+          } catch (err) {
+            throw new
+              Error('Cannot find markdown library, install markdown, discount, or marked.');
+          }
+        }
+      }
+    }
+
+    str = str.replace(/\\n/g, '\n');
+    return md.parse(str).replace(/\n/g, '\\n').replace(/'/g,'&#39;');
+  },
+  
+  /**
+   * Transform coffeescript to javascript.
+   */
+
+  coffeescript: function(str){
+    str = str.replace(/\\n/g, '\n');
+    var js = require('coffee-script').compile(str).replace(/\n/g, '\\n');
+    return '<script type="text/javascript">\\n' + js + '</script>';
+  }
+};
+
+}); // module: filters.js
+
+require.register("inline-tags.js", function(module, exports, require){
+
+/*!
+ * Jade - inline tags
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+module.exports = [
+    'a'
+  , 'abbr'
+  , 'acronym'
+  , 'b'
+  , 'br'
+  , 'code'
+  , 'em'
+  , 'font'
+  , 'i'
+  , 'img'
+  , 'ins'
+  , 'kbd'
+  , 'map'
+  , 'samp'
+  , 'small'
+  , 'span'
+  , 'strong'
+  , 'sub'
+  , 'sup'
+];
+}); // module: inline-tags.js
+
+require.register("jade.js", function(module, exports, require){
+/*!
+ * Jade
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var Parser = require('./parser')
+  , Lexer = require('./lexer')
+  , Compiler = require('./compiler')
+  , runtime = require('./runtime')
+
+/**
+ * Library version.
+ */
+
+exports.version = '0.20.1';
+
+/**
+ * Expose self closing tags.
+ */
+
+exports.selfClosing = require('./self-closing');
+
+/**
+ * Default supported doctypes.
+ */
+
+exports.doctypes = require('./doctypes');
+
+/**
+ * Text filters.
+ */
+
+exports.filters = require('./filters');
+
+/**
+ * Utilities.
+ */
+
+exports.utils = require('./utils');
+
+/**
+ * Expose `Compiler`.
+ */
+
+exports.Compiler = Compiler;
+
+/**
+ * Expose `Parser`.
+ */
+
+exports.Parser = Parser;
+
+/**
+ * Expose `Lexer`.
+ */
+
+exports.Lexer = Lexer;
+
+/**
+ * Nodes.
+ */
+
+exports.nodes = require('./nodes');
+
+/**
+ * Jade runtime helpers.
+ */
+
+exports.runtime = runtime;
+
+/**
+ * Template function cache.
+ */
+
+exports.cache = {};
+
+/**
+ * Parse the given `str` of jade and return a function body.
+ *
+ * @param {String} str
+ * @param {Object} options
+ * @return {String}
+ * @api private
+ */
+
+function parse(str, options){
+  try {
+    // Parse
+    var parser = new Parser(str, options.filename, options);
+
+    // Compile
+    var compiler = new (options.compiler || Compiler)(parser.parse(), options)
+      , js = compiler.compile();
+
+    // Debug compiler
+    if (options.debug) {
+      console.error('\nCompiled Function:\n\n\033[90m%s\033[0m', js.replace(/^/gm, '  '));
+    }
+
+    return ''
+      + '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);
+  }
+}
+
+/**
+ * Compile a `Function` representation of the given jade `str`.
+ *
+ * Options:
+ * 
+ *   - `compileDebug` when `false` debugging code is stripped from the compiled template
+ *   - `client` when `true` the helper functions `escape()` etc will reference `jade.escape()`
+ *      for use with the Jade client-side runtime.js
+ *
+ * @param {String} str
+ * @param {Options} options
+ * @return {Function}
+ * @api public
+ */
+
+exports.compile = function(str, options){
+  var options = options || {}
+    , client = options.client
+    , filename = options.filename
+      ? JSON.stringify(options.filename)
+      : 'undefined'
+    , fn;
+
+  if (options.compileDebug !== false) {
+    fn = [
+        'var __jade = [{ lineno: 1, filename: ' + filename + ' }];'
+      , 'try {'
+      , parse(String(str), options)
+      , '} catch (err) {'
+      , '  rethrow(err, __jade[0].filename, __jade[0].lineno);'
+      , '}'
+    ].join('\n');
+  } else {
+    fn = parse(String(str), options);
+  }
+
+  if (client) {
+    fn = 'var attrs = jade.attrs, escape = jade.escape, rethrow = jade.rethrow;\n' + fn;
+  }
+
+  fn = new Function('locals, attrs, escape, rethrow', fn);
+
+  if (client) return fn;
+
+  return function(locals){
+    return fn(locals, runtime.attrs, runtime.escape, runtime.rethrow);
+  };
+};
+
+/**
+ * Render the given `str` of jade and invoke
+ * the callback `fn(err, str)`.
+ *
+ * Options:
+ *
+ *   - `cache` enable template caching
+ *   - `filename` filename required for `include` / `extends` and caching
+ *
+ * @param {String} str
+ * @param {Object|Function} options or fn
+ * @param {Function} fn
+ * @api public
+ */
+
+exports.render = function(str, options, fn){
+  // swap args
+  if ('function' == typeof options) {
+    fn = options, options = {};
+  }
+
+  // cache requires .filename
+  if (options.cache && !options.filename) {
+    return fn(new Error('the "filename" option is required for caching'));
+  }
+
+  try {
+    var path = options.filename;
+    var 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);
+  }
+};
+
+/**
+ * Render a Jade file at the given `path` and callback `fn(err, str)`.
+ *
+ * @param {String} path
+ * @param {Object|Function} options or callback
+ * @param {Function} fn
+ * @api public
+ */
+
+exports.renderFile = function(path, options, fn){
+  var key = path + ':string';
+
+  if ('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);
+  }
+};
+
+/**
+ * Express support.
+ */
+
+exports.__express = exports.renderFile;
+
+}); // module: jade.js
+
+require.register("lexer.js", function(module, exports, require){
+
+/*!
+ * Jade - Lexer
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Initialize `Lexer` with the given `str`.
+ *
+ * Options:
+ *
+ *   - `colons` allow colons for attr delimiters
+ *
+ * @param {String} str
+ * @param {Object} options
+ * @api private
+ */
+
+var 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 = false;
+};
+
+/**
+ * Lexer prototype.
+ */
+
+Lexer.prototype = {
+  
+  /**
+   * Construct a token with the given `type` and `val`.
+   *
+   * @param {String} type
+   * @param {String} val
+   * @return {Object}
+   * @api private
+   */
+  
+  tok: function(type, val){
+    return {
+        type: type
+      , line: this.lineno
+      , val: val
+    }
+  },
+  
+  /**
+   * Consume the given `len` of input.
+   *
+   * @param {Number} len
+   * @api private
+   */
+  
+  consume: function(len){
+    this.input = this.input.substr(len);
+  },
+  
+  /**
+   * Scan for `type` with the given `regexp`.
+   *
+   * @param {String} type
+   * @param {RegExp} regexp
+   * @return {Object}
+   * @api private
+   */
+  
+  scan: function(regexp, type){
+    var captures;
+    if (captures = regexp.exec(this.input)) {
+      this.consume(captures[0].length);
+      return this.tok(type, captures[1]);
+    }
+  },
+  
+  /**
+   * Defer the given `tok`.
+   *
+   * @param {Object} tok
+   * @api private
+   */
+  
+  defer: function(tok){
+    this.deferredTokens.push(tok);
+  },
+  
+  /**
+   * Lookahead `n` tokens.
+   *
+   * @param {Number} n
+   * @return {Object}
+   * @api private
+   */
+  
+  lookahead: function(n){
+    var fetch = n - this.stash.length;
+    while (fetch-- > 0) this.stash.push(this.next());
+    return this.stash[--n];
+  },
+  
+  /**
+   * Return the indexOf `start` / `end` delimiters.
+   *
+   * @param {String} start
+   * @param {String} end
+   * @return {Number}
+   * @api private
+   */
+  
+  indexOfDelimiters: function(start, end){
+    var str = this.input
+      , nstart = 0
+      , nend = 0
+      , pos = 0;
+    for (var i = 0, len = str.length; i < len; ++i) {
+      if (start == str[i]) {
+        ++nstart;
+      } else if (end == str[i]) {
+        if (++nend == nstart) {
+          pos = i;
+          break;
+        }
+      }
+    }
+    return pos;
+  },
+  
+  /**
+   * Stashed token.
+   */
+  
+  stashed: function() {
+    return this.stash.length
+      && this.stash.shift();
+  },
+  
+  /**
+   * Deferred token.
+   */
+  
+  deferred: function() {
+    return this.deferredTokens.length 
+      && this.deferredTokens.shift();
+  },
+  
+  /**
+   * end-of-source.
+   */
+  
+  eos: function() {
+    if (this.input.length) return;
+    if (this.indentStack.length) {
+      this.indentStack.shift();
+      return this.tok('outdent');
+    } else {
+      return this.tok('eos');
+    }
+  },
+
+  /**
+   * Comment.
+   */
+  
+  comment: function() {
+    var captures;
+    if (captures = /^ *\/\/(-)?([^\n]*)/.exec(this.input)) {
+      this.consume(captures[0].length);
+      var tok = this.tok('comment', captures[2]);
+      tok.buffer = '-' != captures[1];
+      return tok;
+    }
+  },
+  
+  /**
+   * Tag.
+   */
+  
+  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;
+    }
+  },
+  
+  /**
+   * Filter.
+   */
+  
+  filter: function() {
+    return this.scan(/^:(\w+)/, 'filter');
+  },
+  
+  /**
+   * Doctype.
+   */
+  
+  doctype: function() {
+    return this.scan(/^(?:!!!|doctype) *([^\n]+)?/, 'doctype');
+  },
+
+  /**
+   * Id.
+   */
+  
+  id: function() {
+    return this.scan(/^#([\w-]+)/, 'id');
+  },
+  
+  /**
+   * Class.
+   */
+  
+  className: function() {
+    return this.scan(/^\.([\w-]+)/, 'class');
+  },
+  
+  /**
+   * Text.
+   */
+  
+  text: function() {
+    return this.scan(/^(?:\| ?)?([^\n]+)/, 'text');
+  },
+
+  /**
+   * Extends.
+   */
+  
+  extends: function() {
+    return this.scan(/^extends +([^\n]+)/, 'extends');
+  },
+
+  /**
+   * Block prepend.
+   */
+  
+  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);
+      tok.mode = mode;
+      return tok;
+    }
+  },
+  
+  /**
+   * Block append.
+   */
+  
+  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);
+      tok.mode = mode;
+      return tok;
+    }
+  },
+
+  /**
+   * Block.
+   */
+  
+  block: function() {
+    var captures;
+    if (captures = /^block +(?:(prepend|append) +)?([^\n]+)/.exec(this.input)) {
+      this.consume(captures[0].length);
+      var mode = captures[1] || 'replace'
+        , name = captures[2]
+        , tok = this.tok('block', name);
+      tok.mode = mode;
+      return tok;
+    }
+  },
+
+  /**
+   * Yield.
+   */
+  
+  yield: function() {
+    return this.scan(/^yield */, 'yield');
+  },
+
+  /**
+   * Include.
+   */
+  
+  include: function() {
+    return this.scan(/^include +([^\n]+)/, 'include');
+  },
+
+  /**
+   * Case.
+   */
+  
+  case: function() {
+    return this.scan(/^case +([^\n]+)/, 'case');
+  },
+
+  /**
+   * When.
+   */
+  
+  when: function()