Вход Регистрация
Файл: error-kitty/node_modules/mocha/node_modules/jade/jade.js
Строк: 2755
(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.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];
        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')
  , runtime = require('./runtime')
  , 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;
  this.parentIndents = 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;'];
    if (this.pp) this.buf.push("var __indent = [];");
    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;
    }
  },

  /**
   * Buffer an indent based on the current `indent`
   * property and an additional `offset`.
   *
   * @param {Number} offset
   * @param {Boolean} newline
   * @api public
   */
  
  prettyIndent: function(offset, newline){
    offset = offset || 0;
    newline = newline ? '
\n' : '';
    this.buffer(newline + Array(this.indents + offset).join('  '));
    if (this.parentIndents)
      this.buf.push("buf.push.apply(buf, __indent);");
  },

  /**
   * 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
          ? JSON.stringify(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
      , escape = this.escape
      , pp = this.pp
    
    // Block keyword has a special meaning in mixins
    if (this.parentIndents && block.mode) {
      if (pp) this.buf.push("__indent.push('" + Array(this.indents + 1).join('  ') + "');")
      this.buf.push('
block && block();');
      if (pp) this.buf.push("__indent.pop();")
      return;
    }
    
    // Pretty print multi-line text
    if (pp && len > 1 && !escape && block.nodes[0].isText && block.nodes[1].isText)
      this.prettyIndent(1, true);
    
    for (var i = 0; i < len; ++i) {
      // Pretty print text
      if (pp && i > 0 && !escape && block.nodes[i].isText && block.nodes[i-1].isText)
        this.prettyIndent(1, false);
      
      this.visit(block.nodes[i]);
      // Multiple text nodes are separated by newlines
      if (block.nodes[i+1] && block.nodes[i].isText && block.nodes[i+1].isText)
        this.buffer('
\n');
    }
  },

  /**
   * 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 || ''
      , block = mixin.block
      , attrs = mixin.attrs
      , pp = this.pp;

    if (mixin.call) {
      if (pp) this.buf.push("__indent.push('" + Array(this.indents + 1).join('  ') + "');")
      if (block || attrs.length) {
        
        this.buf.push(name + '
.call({');
        
        if (block) {
          this.buf.push('
block: function(){');
          
          // Render block with no indents, dynamically added when rendered
          this.parentIndents++;
          var _indents = this.indents;
          this.indents = 0;
          this.visit(mixin.block);
          this.indents = _indents;
          this.parentIndents--;
          
          if (attrs.length) {
            this.buf.push('
},');
          } else {
            this.buf.push('
}');
          }
        }
        
        if (attrs.length) {
          var val = this.attrs(attrs);
          if (val.inherits) {
            this.buf.push('
attributesmerge({' + val.buf
                + '
}, attributes), escapedmerge(' + val.escaped + 'escapedtrue)');
          } else {
            this.buf.push('
attributes: {' + val.buf + '}, escaped' + val.escaped);
          }
        }
        
        if (args) {
          this.buf.push('
}, ' + args + ');');
        } else {
          this.buf.push('
});');
        }
        
      } else {
        this.buf.push(name + '
(' + args + ');');
      }
      if (pp) this.buf.push("__indent.pop();")
    } else {
      this.buf.push('
var ' + name + ' = function(' + args + '){');
      this.buf.push('
var block this.blockattributes this.attributes || {}, escaped this.escaped || {};');
      this.parentIndents++;
      this.visit(block);
      this.parentIndents--;
      this.buf.push('
};');
    }
  },

  /**
   * Visit `tag` buffering tag markup, generating
   * attributes, visiting the `tag`'
s code and block.
   *
   * @
param {Tagtag
   
* @api public
   */

  
visitTag: function(tag){
    
this.indents++;
    var 
name tag.name
      
pp this.pp;

    if (
tag.buffername "' + (" name ") + '";

    if (!
this.hasCompiledTag) {
      if (!
this.hasCompiledDoctype && 'html' == name) {
        
this.visitDoctype();
      }
      
this.hasCompiledTag true;
    }

    
// pretty print
    
if (pp && !tag.isInline())
      
this.prettyIndent(0true);

    if ((~
selfClosing.indexOf(name) || tag.selfClosing) && !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.lengththis.visitAttributes(tag.attrs);
        
this.buffer('>');
      } else {
        
this.buffer('<' name '>');
      }
      if (
tag.codethis.visitCode(tag.code);
      
this.escape 'pre' == tag.name;
      
this.visit(tag.block);

      
// pretty print
      
if (pp && !tag.isInline() && 'pre' != tag.name && !tag.canInline())
        
this.prettyIndent(0true);

      
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.blockthisfilter.attrs));
    } else {
      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(utils.text(fn(textfilter.attrs)));
    }
  },

  
/**
   * Visit `text` node.
   *
   * @param {Text} text
   * @api public
   */

  
visitText: function(text){
    
text utils.text(text.val.replace(/\/g'\\'));
    if (
this.escapetext escape(text);
    
this.buffer(text);
  },

  
/**
   * 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.ppthis.prettyIndent(1true);
    
this.buffer('<!--' utils.escape(comment.val) + '-->');
  },

  
/**
   * Visit a `BlockComment`.
   *
   * @param {Comment} comment
   * @api public
   */

  
visitBlockComment: function(comment){
    if (!
comment.buffer) return;
    if (
== 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.escapeval 'escape(' val ')';
      
this.buf.push("buf.push(" val ");");
    } else {
      
this.buf.push(code.val);
    }

    
// Block support
    
if (code.block) {
      if (!
code.bufferthis.buf.push('{');
      
this.visit(code.block);
      if (!
code.bufferthis.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 
val this.attrs(attrs);
    if (
val.inherits) {
      
this.buf.push("buf.push(attrs(merge({ " val.buf +
          
" }, attributes), merge(" val.escaped ", escaped, true)));");
    } else if (
val.constant) {
      eval(
'var buf={' val.buf '};');
      
this.buffer(runtime.attrs(bufJSON.parse(val.escaped)), true);
    } else {
      
this.buf.push("buf.push(attrs({ " val.buf " }, " val.escaped "));");
    }
  },

  
/**
   * Compile attributes.
   */

  
attrs: function(attrs){
    var 
buf = []
      , 
classes = []
      , 
escaped = {}
      , 
constant attrs.every(function(attr){ return isConstant(attr.val) })
      , 
inherits false;

    if (
this.tersebuf.push('terse: true');

    
attrs.forEach(function(attr){
      if (
attr.name == 'attributes') return inherits true;
      
escaped[attr.name] = attr.escaped;
      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);
    }

    return {
      
bufbuf.join(', ').replace('class:''"class":'),
      
escapedJSON.stringify(escaped),
      
inheritsinherits,
      
constantconstant
    
};
  }
};

/**
 * Check if expression can be evaluated to a constant
 *
 * @param {String} expression
 * @return {Boolean}
 * @api private
 */

function isConstant(val){
  
// Check strings/literals
  
if (/^ *("([^"\]*(\.[^"\]*)*)"|'([^'\]*(\.[^'\]*)*)'|true|false|null|undefined) *$/i.test(val))
    return 
true;
  
  
// Check numbers
  
if (!isNaN(Number(val)))
    return 
true;
  
  
// Check arrays
  
var matches;
  if (
matches = /^ *[(.*)] *$/.exec(val))
    return 
matches[1].split(',').every(isConstant);
  
  return 
false;
}

/**
 * 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>'
  , '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">'
};
}); 
// module: doctypes.js

require.register("filters.js", function(moduleexports, 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(stroptions){
    var 
ret;
    
str str.replace(/\n/g'n');
    var 
stylus = require('stylus');
    
stylus(stroptions).render(function(errcss){
      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(errcss){
      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(/\/g'\\').replace(/n/g'\n');
    return 
'<script type="text/javascript">\n' js '</script>';
  }
};

}); 
// module: filters.js

require.register("inline-tags.js", function(moduleexports, 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(moduleexports, 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.26.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(stroptions){
  try {
    
// Parse
    
var parser = new Parser(stroptions.filenameoptions);

    
// Compile
    
var compiler = new (options.compiler || Compiler)(parser.parse(), options)
      , 
js compiler.compile();

    
// Debug compiler
    
if (options.debug) {
      
console.error('nCompiled Function:nn33[90m%s33[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(errparser.filenameparser.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(stroptions){
  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 'attrs = attrs || jade.attrs; escape = escape || jade.escape; rethrow = rethrow || jade.rethrow; merge = merge || jade.merge;n' fn;
  }

  
fn = new Function('locals, attrs, escape, rethrow, merge'fn);

  if (
client) return fn;

  return function(
locals){
    return 
fn(localsruntime.attrsruntime.escaperuntime.rethrowruntime.merge);
  };
};

/**
 * 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(stroptionsfn){
  
// swap args
  
if ('function' == typeof options) {
    
fn optionsoptions = {};
  }

  
// 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(stroptions))
      : 
exports.compile(stroptions);
    
fn(nulltmpl(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(pathoptionsfn){
  var 
key path ':string';

  if (
'function' == typeof options) {
    
fn optionsoptions = {};
  }

  try {
    
options.filename path;
    var 
str options.cache
      
exports.cache[key] || (exports.cache[key] = fs.readFileSync(path'utf8'))
      : 
fs.readFileSync(path'utf8');
    
exports.render(stroptionsfn);
  } catch (
err) {
    
fn(err);
  }
};

/**
 * Express support.
 */

exports.__express exports.renderFile;

}); 
// module: jade.js

require.register("lexer.js", function(moduleexports, 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(stroptions) {
  
options options || {};
  
this.input str.replace(/rn|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(typeval){
    return {
        
typetype
      
linethis.lineno
      
valval
    
}
  },
  
  
/**
   * 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(regexptype){
    var 
captures;
    if (
captures regexp.exec(this.input)) {
      
this.consume(captures[0].length);
      return 
this.tok(typecaptures[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 this.stash.length;
    while (
fetch-- > 0this.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(startend){
    var 
str this.input
      
nstart 0
      
nend 0
      
pos 0;
    for (var 
0len str.lengthlen; ++i) {
      if (
start == str.charAt(i)) {
        ++
nstart;
      } else if (
end == str.charAt(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');
    }
  },

  
/**
   * Blank line.
   */
  
  
blank: function() {
    var 
captures;
    if (
captures = /^*n/.exec(this.input)) {
      
this.consume(captures[0].length 1);
      if (
this.pipeless) return this.tok('text''');
      return 
this.next();
    }
  },

  
/**
   * 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;
    }
  },

  
/**
   * Interpolated tag.
   */

  
interpolation: function() {
    var 
captures;
    if (
captures = /^#{(.*?)}/.exec(this.input)) {
      
this.consume(captures[0].length);
      return 
this.tok('interpolation'captures[1]);
    }
  },

  
/**
   * Tag.
   */
  
  
tag: function() {
    var 
captures;
    if (
captures = /^(w[-:w]*)(/?)/.exec(this.input)) {
      
this.consume(captures[0].length);
      var 
tokname 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);
      }
      
tok.selfClosing = !! captures[2];
      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 = /^blockb *(?:(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() {
    return 
this.scan(/^when +([^:n]+)/, 'when');
  },

  
/**
   * Default.
   */
  
  
"default": function() {
    return 
this.scan(/^default */, 'default');
  },

  
/**
   * Assignment.
   */
  
  
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 mixin.
   */
  
  
call: function(){
    var 
captures;
    if (
captures = /^+([-w]+)/.exec(this.input)) {
      
this.consume(captures[0].length);
      var 
tok this.tok('call'captures[1]);
      
      
// Check for args (not attributes)
      
if (captures = /^ *((.*?))/.exec(this.input)) {
        if (!/^ *[-
w]+ *=/.test(captures[1])) {
          
this.consume(captures[0].length);
          
tok.args captures[1];
        }
      }
      
      return 
tok;
    }
  },

  
/**
   * Mixin.
   */

  
mixin: function(){
    var 
captures;
    if (
captures = /^mixin +([-w]+)(?: *((.*)))?/.exec(this.input)) {
      
this.consume(captures[0].length);
      var 
tok this.tok('mixin'captures[1]);
      
tok.args captures[2];
      return 
tok;
    }
  },

  
/**
   * Conditional.
   */
  
  
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'; break;
      }

      return 
this.tok('code'js);
    }
  },

  
/**
   * While.
   */
  
  
"while": function() {
    var 
captures;
    if (
captures = /^while +([^n]+)/.exec(this.input)) {
      
this.consume(captures[0].length);
      return 
this.tok('code''while (' captures[1] + ')');
    }
  },

  
/**
   * Each.
   */
  
  
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]);
      
tok.key captures[2] || '$index';
      
tok.code captures[3];
      return 
tok;
    }
  },
  
  
/**
   * Code.
   */
  
  
code: function() {
    var 
captures;
    if (
captures = /^(!?=|-)([^n]+)/.exec(this.input)) {
      
this.consume(captures[0].length);
      var 
flags captures[1];
      
captures[1] = captures[2];
      var 
tok this.tok('code'captures[1]);
      
tok.escape flags[0] === '=';
      
tok.buffer flags[0] === '=' || flags[1] === '=';
      return 
tok;
    }
  },
  
  
/**
   * Attributes.
   */
  
  
attrs: function() {
    if (
'(' == this.input.charAt(0)) {
      var 
index this.indexOfDelimiters('('')')
        , 
str this.input.substr(1index-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(_, expr){
          
return quote " + (" expr ") + " quote;
        });
      }

      
this.consume(index 1);
      
tok.attrs = {};
      
tok.escaped = {};

      function 
parse(c) {
        var 
real c;
        
// TODO: remove when people fix ":"
        
if (colons && ':' == 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
                  ? true
                  : 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 '(':
            if ('val' == state()
              || 'expr' == state()) states.push('expr');
            val += c;
            break;
          case ')':
            if ('expr' == state()
              || 'val' == state()) states.pop();
            val += c;
            break;
          case '{':
            if ('val' == state()) states.push('object');
            val += c;
            break;
          case '}':
            if ('object' == state()) states.pop();
            val += c;
            break;
          case '[':
            if ('val' == state()) states.push('array');
            val += c;
            break;
          case ']':
            if ('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':
                if (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));
      }

      parse(',');

      if ('/' == this.input.charAt(0)) {
        this.consume(1);
        tok.selfClosing = true;
      }

      return tok;
    }
  },
  
  /**
   * Indent | Outdent | Newline.
   */
  
  indent: function() {
    var captures, re;

    // established regexp
    if (this.indentRe) {
      captures = this.indentRe.exec(this.input);
    // determine regexp
    } else {
      // tabs
      re = /^n(t*) */;
      captures = re.exec(this.input);

      // spaces
      if (captures && !captures[1].length) {
        re = /^n( *)/;
        captures = re.exec(this.input);
      }

      // established
      if (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] || 't' == this.input[0]) {
        throw new Error('Invalid indentation, you can use tabs or spaces but not both');
      }

      // blank line
      if ('n' == this.input[0]) return this.tok('newline');

      // outdent
      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();
      // indent
      } else if (indents && indents != this.indentStack[0]) {
        this.indentStack.unshift(indents);
        tok = this.tok('indent', indents);
      // newline
      } else {
        tok = this.tok('newline');
      }

      return tok;
    }
  },

  /**
   * Pipe-less text consumed only when 
   * pipeless is true;
   */

  pipelessText: function() {
    if (this.pipeless) {
      if ('n' == this.input[0]) return;
      var i = this.input.indexOf('n');
      if (-1 == i) i = this.input.length;
      var str = this.input.substr(0, i);
      this.consume(str.length);
      return this.tok('text', str);
    }
  },

  /**
   * ':'
   */

  colon: function() {
    return this.scan(/^: */, ':');
  },

  /**
   * Return the next token object, or those
   * previously stashed by lookahead.
   *
   * @return {Object}
   * @api private
   */
  
  advance: function(){
    return this.stashed()
      || this.next();
  },
  
  /**
   * Return the next token object.
   *
   * @return {Object}
   * @api private
   */
  
  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();
  }
};

}); // module: lexer.js

require.register("
nodes/attrs.js", function(module, exports, require){

/*!
 * Jade - nodes - Attrs
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var Node = require('./node'),
    Block = require('./block');

/**
 * Initialize a `Attrs` node.
 *
 * @api public
 */

var Attrs = module.exports = function Attrs() {
  this.attrs = [];
};

/**
 * Inherit from `Node`.
 */

Attrs.prototype = new Node;
Attrs.prototype.constructor = Attrs;


/**
 * Set attribute `name` to `val`, keep in mind these become
 * part of a raw js object literal, so to quote a value you must
 * '"
quote me"', otherwise or example 'user.name' is literal JavaScript.
 *
 * @param {String} name
 * @param {String} val
 * @param {Boolean} escaped
 * @return {Tag} for chaining
 * @api public
 */

Attrs.prototype.setAttribute = function(name, val, escaped){
  this.attrs.push({ name: name, val: val, escaped: escaped });
  return this;
};

/**
 * Remove attribute `name` when present.
 *
 * @param {String} name
 * @api public
 */

Attrs.prototype.removeAttribute = function(name){
  for (var i = 0, len = this.attrs.length; i < len; ++i) {
    if (this.attrs[i] && this.attrs[i].name == name) {
      delete this.attrs[i];
    }
  }
};

/**
 * Get attribute value by `name`.
 *
 * @param {String} name
 * @return {String}
 * @api public
 */

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;
    }
  }
};

}); // module: nodes/attrs.js

require.register("
nodes/block-comment.js", function(module, exports, require){

/*!
 * Jade - nodes - BlockComment
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var Node = require('./node');

/**
 * Initialize a `BlockComment` with the given `block`.
 *
 * @param {String} val
 * @param {Block} block
 * @param {Boolean} buffer
 * @api public
 */

var BlockComment = module.exports = function BlockComment(val, block, buffer) {
  this.block = block;
  this.val = val;
  this.buffer = buffer;
};

/**
 * Inherit from `Node`.
 */

BlockComment.prototype = new Node;
BlockComment.prototype.constructor = BlockComment;

}); // module: nodes/block-comment.js

require.register("
nodes/block.js", function(module, exports, require){

/*!
 * Jade - nodes - Block
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var Node = require('./node');

/**
 * Initialize a new `Block` with an optional `node`.
 *
 * @param {Node} node
 * @api public
 */

var Block = module.exports = function Block(node){
  this.nodes = [];
  if (node) this.push(node);
};

/**
 * Inherit from `Node`.
 */

Block.prototype = new Node;
Block.prototype.constructor = Block;


/**
 * Block flag.
 */

Block.prototype.isBlock = true;

/**
 * Replace the nodes in `other` with the nodes
 * in `this` block.
 *
 * @param {Block} other
 * @api private
 */

Block.prototype.replace = function(other){
  other.nodes = this.nodes;
};

/**
 * Pust the given `node`.
 *
 * @param {Node} node
 * @return {Number}
 * @api public
 */

Block.prototype.push = function(node){
  return this.nodes.push(node);
};

/**
 * Check if this block is empty.
 *
 * @return {Boolean}
 * @api public
 */

Block.prototype.isEmpty = function(){
  return 0 == this.nodes.length;
};

/**
 * Unshift the given `node`.
 *
 * @param {Node} node
 * @return {Number}
 * @api public
 */

Block.prototype.unshift = function(node){
  return this.nodes.unshift(node);
};

/**
 * Return the "
last" block, or the first `yield` node.
 *
 * @return {Block}
 * @api private
 */

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;
    else if (node.textOnly) continue;
    else if (node.includeBlock) ret = node.includeBlock();
    else if (node.block && !node.block.isEmpty()) ret = node.block.includeBlock();
  }

  return ret;
};

/**
 * Return a clone of this block.
 *
 * @return {Block}
 * @api private
 */

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;
};


}); // module: nodes/block.js

require.register("
nodes/case.js", function(module, exports, require){

/*!
 * Jade - nodes - Case
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var Node = require('./node');

/**
 * Initialize a new `Case` with `expr`.
 *
 * @param {String} expr
 * @api public
 */

var Case = exports = module.exports = function Case(expr, block){
  this.expr = expr;
  this.block = block;
};

/**
 * Inherit from `Node`.
 */

Case.prototype = new Node;
Case.prototype.constructor = Case;


var When = exports.When = function When(expr, block){
  this.expr = expr;
  this.block = block;
  this.debug = false;
};

/**
 * Inherit from `Node`.
 */

When.prototype = new Node;
When.prototype.constructor = When;



}); // module: nodes/case.js

require.register("
nodes/code.js", function(module, exports, require){

/*!
 * Jade - nodes - Code
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var Node = require('./node');

/**
 * Initialize a `Code` node with the given code `val`.
 * Code may also be optionally buffered and escaped.
 *
 * @param {String} val
 * @param {Boolean} buffer
 * @param {Boolean} escape
 * @api public
 */

var Code = module.exports = function Code(val, buffer, escape) {
  this.val = val;
  this.buffer = buffer;
  this.escape = escape;
  if (val.match(/^ *else/)) this.debug = false;
};

/**
 * Inherit from `Node`.
 */

Code.prototype = new Node;
Code.prototype.constructor = Code;

}); // module: nodes/code.js

require.register("
nodes/comment.js", function(module, exports, require){

/*!
 * Jade - nodes - Comment
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var Node = require('./node');

/**
 * Initialize a `Comment` with the given `val`, optionally `buffer`,
 * otherwise the comment may render in the output.
 *
 * @param {String} val
 * @param {Boolean} buffer
 * @api public
 */

var Comment = module.exports = function Comment(val, buffer) {
  this.val = val;
  this.buffer = buffer;
};

/**
 * Inherit from `Node`.
 */

Comment.prototype = new Node;
Comment.prototype.constructor = Comment;

}); // module: nodes/comment.js

require.register("
nodes/doctype.js", function(module, exports, require){

/*!
 * Jade - nodes - Doctype
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var Node = require('./node');

/**
 * Initialize a `Doctype` with the given `val`. 
 *
 * @param {String} val
 * @api public
 */

var Doctype = module.exports = function Doctype(val) {
  this.val = val;
};

/**
 * Inherit from `Node`.
 */

Doctype.prototype = new Node;
Doctype.prototype.constructor = Doctype;

}); // module: nodes/doctype.js

require.register("
nodes/each.js", function(module, exports, require){

/*!
 * Jade - nodes - Each
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var Node = require('./node');

/**
 * Initialize an `Each` node, representing iteration
 *
 * @param {String} obj
 * @param {String} val
 * @param {String} key
 * @param {Block} block
 * @api public
 */

var Each = module.exports = function Each(obj, val, key, block) {
  this.obj = obj;
  this.val = val;
  this.key = key;
  this.block = block;
};

/**
 * Inherit from `Node`.
 */

Each.prototype = new Node;
Each.prototype.constructor = Each;

}); // module: nodes/each.js

require.register("
nodes/filter.js", function(module, exports, require){

/*!
 * Jade - nodes - Filter
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var Node = require('./node')
  , Block = require('./block');

/**
 * Initialize a `Filter` node with the given 
 * filter `name` and `block`.
 *
 * @param {String} name
 * @param {Block|Node} block
 * @api public
 */

var Filter = module.exports = function Filter(name, block, attrs) {
  this.name = name;
  this.block = block;
  this.attrs = attrs;
  this.isASTFilter = !block.nodes.every(function(node){ return node.isText });
};

/**
 * Inherit from `Node`.
 */

Filter.prototype = new Node;
Filter.prototype.constructor = Filter;

}); // module: nodes/filter.js

require.register("
nodes/index.js", function(module, exports, require){

/*!
 * Jade - nodes
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

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');

}); // module: nodes/index.js

require.register("
nodes/literal.js", function(module, exports, require){

/*!
 * Jade - nodes - Literal
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var Node = require('./node');

/**
 * Initialize a `Literal` node with the given `str.
 *
 * @param {String} str
 * @api public
 */

var Literal = module.exports = function Literal(str) {
  this.str = str
    .replace(/\/g, "
\\")
    .replace(/n|rn/g, "
\n")
    .replace(/'/g, "
\'");
};

/**
 * Inherit from `Node`.
 */

Literal.prototype = new Node;
Literal.prototype.constructor = Literal;


}); // module: nodes/literal.js

require.register("nodes/mixin.js", function(module, exports, require){

/*!
 * Jade - nodes - Mixin
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var Attrs = require('
./attrs');

/**
 * Initialize a new `Mixin` with `name` and `block`.
 *
 * @param {String} name
 * @param {String} args
 * @param {Block} block
 * @api public
 */

var Mixin = module.exports = function Mixin(name, args, block, call){
  this.name = name;
  this.args = args;
  this.block = block;
  this.attrs = [];
  this.call = call;
};

/**
 * Inherit from `Attrs`.
 */

Mixin.prototype = new Attrs;
Mixin.prototype.constructor = Mixin;



}); // module: nodes/mixin.js

require.register("nodes/node.js", function(module, exports, require){

/*!
 * Jade - nodes - Node
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Initialize a `Node`.
 *
 * @api public
 */

var Node = module.exports = function Node(){};

/**
 * Clone this node (return itself)
 *
 * @return {Node}
 * @api private
 */

Node.prototype.clone = function(){
  return this;
};

}); // module: nodes/node.js

require.register("nodes/tag.js", function(module, exports, require){

/*!
 * Jade - nodes - Tag
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var Attrs = require('
./attrs'),
    Block = require('
./block'),
    inlineTags = require('
../inline-tags');

/**
 * Initialize a `Tag` node with the given tag `name` and optional `block`.
 *
 * @param {String} name
 * @param {Block} block
 * @api public
 */

var Tag = module.exports = function Tag(name, block) {
  this.name = name;
  this.attrs = [];
  this.block = block || new Block;
};

/**
 * Inherit from `Attrs`.
 */

Tag.prototype = new Attrs;
Tag.prototype.constructor = Tag;


/**
 * Clone this tag.
 *
 * @return {Tag}
 * @api private
 */

Tag.prototype.clone = function(){
  var clone = new Tag(this.name, this.block.clone());
  clone.line = this.line;
  clone.attrs = this.attrs;
  clone.textOnly = this.textOnly;
  return clone;
};

/**
 * Check if this tag is an inline tag.
 *
 * @return {Boolean}
 * @api private
 */

Tag.prototype.isInline = function(){
  return ~inlineTags.indexOf(this.name);
};

/**
 * Check if this tag'
s contents can be inlined.  Used for pretty printing.
 *
 * @return {
Boolean}
 * @
api private
 */

Tag.prototype.canInline = function(){
  var 
nodes this.block.nodes;

  function 
isInline(node){
    
// Recurse if the node is a block
    
if (node.isBlock) return node.nodes.every(isInline);
    return 
node.isText || (node.isInline && node.isInline());
  }
  
  
// Empty tag
  
if (!nodes.length) return true;
  
  
// Text-only or inline-only tag
  
if (== nodes.length) return isInline(nodes[0]);
  
  
// Multi-line inline-only tag
  
if (this.block.nodes.every(isInline)) {
    for (var 
1len nodes.lengthlen; ++i) {
      if (
nodes[i-1].isText && nodes[i].isText)
        return 
false;
    }
    return 
true;
  }
  
  
// Mixed tag
  
return false;
};
}); 
// module: nodes/tag.js

require.register("nodes/text.js", function(moduleexports, require){

/*!
 * Jade - nodes - Text
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var Node = require('./node');

/**
 * Initialize a `Text` node with optional `line`.
 *
 * @param {String} line
 * @api public
 */

var Text module.exports = function Text(line) {
  
this.val '';
  if (
'string' == typeof linethis.val line;
};

/**
 * Inherit from `Node`.
 */

Text.prototype = new Node;
Text.prototype.constructor Text;


/**
 * Flag as text.
 */

Text.prototype.isText true;
}); 
// module: nodes/text.js

require.register("parser.js", function(moduleexports, require){

/*!
 * Jade - Parser
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var Lexer = require('./lexer')
  , 
nodes = require('./nodes');

/**
 * Initialize `Parser` with the given input `str` and `filename`.
 *
 * @param {String} str
 * @param {String} filename
 * @param {Object} options
 * @api public
 */

var Parser exports module.exports = function Parser(strfilenameoptions){
  
this.input str;
  
this.lexer = new Lexer(stroptions);
  
this.filename filename;
  
this.blocks = {};
  
this.mixins = {};
  
this.options options;
  
this.contexts = [this];
};

/**
 * Tags that may not contain tags.
 */

var textOnly exports.textOnly = ['script''style'];

/**
 * Parser prototype.
 */

Parser.prototype = {

  
/**
   * Push `parser` onto the context stack,
   * or pop and return a `Parser`.
   */

  
context: function(parser){
    if (
parser) {
      
this.contexts.push(parser);
    } else {
      return 
this.contexts.pop();
    }
  },

  
/**
   * Return the next token object.
   *
   * @return {Object}
   * @api private
   */

  
advance: function(){
    return 
this.lexer.advance();
  },

  
/**
   * Skip `n` tokens.
   *
   * @param {Number} n
   * @api private
   */

  
skip: function(n){
    while (
n--) this.advance();
  },
  
  
/**
   * Single token lookahead.
   *
   * @return {Object}
   * @api private
   */
  
  
peek: function() {
    return 
this.lookahead(1);
  },
  
  
/**
   * Return lexer lineno.
   *
   * @return {Number}
   * @api private
   */
  
  
line: function() {
    return 
this.lexer.lineno;
  },
  
  
/**
   * `n` token lookahead.
   *
   * @param {Number} n
   * @return {Object}
   * @api private
   */
  
  
lookahead: function(n){
    return 
this.lexer.lookahead(n);
  },
  
  
/**
   * Parse input returning a string of js for evaluation.
   *
   * @return {String}
   * @api public
   */
  
  
parse: function(){
    var 
block = new nodes.Blockparser;
    
block.line this.line();

    while (
'eos' != this.peek().type) {
      if (
'newline' == this.peek().type) {
        
this.advance();
      } else {
        
block.push(this.parseExpr());
      }
    }

    if (
parser this.extending) {
      
this.context(parser);
      var 
ast parser.parse();
      
this.context();
      
// hoist mixins
      
for (var name in this.mixins)
        
ast.unshift(this.mixins[name]);
      return 
ast;
    }

    return 
block;
  },
  
  
/**
   * Expect the given type, or throw an exception.
   *
   * @param {String} type
   * @api private
   */
  
  
expect: function(type){
    if (
this.peek().type === type) {
      return 
this.advance();
    } else {
      throw new 
Error('expected "' type '", but got "' this.peek().type '"');
    }
  },
  
  
/**
   * Accept the given `type`.
   *
   * @param {String} type
   * @api private
   */
  
  
accept: function(type){
    if (
this.peek().type === type) {
      return 
this.advance();
    }
  },
  
  
/**
   *   tag
   * | doctype
   * | mixin
   * | include
   * | filter
   * | comment
   * | text
   * | each
   * | code
   * | yield
   * | id
   * | class
   * | interpolation
   */
  
  
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;
        
block.yield = true;
        return 
block;
      case 
'id':
      case 
'class':
        var 
tok this.advance();
        
this.lexer.defer(this.lexer.tok('tag''div'));
        
this.lexer.defer(tok);
        return 
this.parseExpr();
      default:
        throw new 
Error('unexpected token "' this.peek().type '"');
    }
  },
  
  
/**
   * Text
   */
  
  
parseText: function(){
    var 
tok this.expect('text')
      , 
node = new nodes.Text(tok.val);
    
node.line this.line();
    return 
node;
  },

  
/**
   *   ':' expr
   * | block
   */

  
parseBlockExpansion: function(){
    if (
':' == this.peek().type) {
      
this.advance();
      return new 
nodes.Block(this.parseExpr());
    } else {
      return 
this.block();
    }
  },

  
/**
   * case
   */

  
parseCase: function(){
    var 
val this.expect('case').val
      
node = new nodes.Case(val);
    
node.line this.line();
    
node.block this.block();
    return 
node;
  },

  
/**
   * when
   */

  
parseWhen: function(){
    var 
val this.expect('when').val
    
return new nodes.Case.When(valthis.parseBlockExpansion());
  },
  
  
/**
   * default
   */

  
parseDefault: function(){
    
this.expect('default');
    return new 
nodes.Case.When('default'this.parseBlockExpansion());
  },

  
/**
   * code
   */
  
  
parseCode: function(){
    var 
tok this.expect('code')
      , 
node = new nodes.Code(tok.valtok.buffertok.escape)
      , 
block
      
1;
    
node.line this.line();
    while (
this.lookahead(i) && 'newline' == this.lookahead(i).type) ++i;
    
block 'indent' == this.lookahead(i).type;
    if (
block) {
      
this.skip(i-1);
      
node.block this.block();
    }
    return 
node;
  },
  
  
/**
   * comment
   */
  
  
parseComment: function(){
    var 
tok this.expect('comment')
      , 
node;

    if (
'indent' == this.peek().type) {
      
node = new nodes.BlockComment(tok.valthis.block(), tok.buffer);
    } else {
      
node = new nodes.Comment(tok.valtok.buffer);
    }

    
node.line this.line();
    return 
node;
  },
  
  
/**
   * doctype
   */
  
  
parseDoctype: function(){
    var 
tok this.expect('doctype')
      , 
node = new nodes.Doctype(tok.val);
    
node.line this.line();
    return 
node;
  },
  
  
/**
   * filter attrs? text-block
   */
  
  
parseFilter: function(){
    var 
block
      
tok this.expect('filter')
      , 
attrs this.accept('attrs');

    
this.lexer.pipeless true;
    
block this.parseTextBlock();
    
this.lexer.pipeless false;

    var 
node = new nodes.Filter(tok.valblockattrs && attrs.attrs);
    
node.line this.line();
    return 
node;
  },
  
  
/**
   * tag ':' attrs? block
   */
  
  
parseASTFilter: function(){
    var 
block
      
tok this.expect('tag')
      , 
attrs this.accept('attrs');

    
this.expect(':');
    
block this.block();

    var 
node = new nodes.Filter(tok.valblockattrs && attrs.attrs);
    
node.line this.line();
    return 
node;
  },
  
  
/**
   * each block
   */
  
  
parseEach: function(){
    var 
tok this.expect('each')
      , 
node = new nodes.Each(tok.codetok.valtok.key);
    
node.line this.line();
    
node.block this.block();
    return 
node;
  },

  
/**
   * 'extends' name
   */

  
parseExtends: function(){
    var 
path = require('path')
      , 
fs = require('fs')
      , 
dirname path.dirname
      
basename path.basename
      
join path.join;

    if (!
this.filename)
      throw new 
Error('the "filename" option is required to extend templates');

    var 
path this.expect('extends').val.trim()
      , 
dir dirname(this.filename);

    var 
path join(dirpath '.jade')
      , 
str fs.readFileSync(path'utf8')
      , 
parser = new Parser(strpaththis.options);

    
parser.blocks this.blocks;
    
parser.contexts this.contexts;
    
this.extending parser;

    
// TODO: null node
    
return new nodes.Literal('');
  },

  
/**
   * 'block' name block
   */

  
parseBlock: function(){
    var 
block this.expect('block')
      , 
mode block.mode
      
name block.val.trim();

    
block 'indent' == this.peek().type
      
this.block()
      : new 
nodes.Block(new nodes.Literal(''));

    var 
prev this.blocks[name];

    if (
prev) {
      switch (
prev.mode) {
        case 
'append':
          
block.nodes block.nodes.concat(prev.nodes);
          
prev block;
          break;
        case 
'prepend':
          
block.nodes prev.nodes.concat(block.nodes);
          
prev block;
          break;
      }
    }

    
block.mode mode;
    return 
this.blocks[name] = prev || block;
  },

  
/**
   * include block?
   */

  
parseInclude: function(){
    var 
path = require('path')
      , 
fs = require('fs')
      , 
dirname path.dirname
      
basename path.basename
      
join path.join;

    var 
path this.expect('include').val.trim()
      , 
dir dirname(this.filename);

    if (!
this.filename)
      throw new 
Error('the "filename" option is required to use includes');

    
// no extension
    
if (!~basename(path).indexOf('.')) {
      
path += '.jade';
    }

    
// non-jade
    
if ('.jade' != path.substr(-5)) {
      var 
path join(dirpath)
        , 
str fs.readFileSync(path'utf8');
      return new 
nodes.Literal(str);
    }

    var 
path join(dirpath)
      , 
str fs.readFileSync(path'utf8')
     , 
parser = new Parser(strpaththis.options);
    
parser.blocks this.blocks;
    
parser.mixins this.mixins;

    
this.context(parser);
    var 
ast parser.parse();
    
this.context();
    
ast.filename path;

    if (
'indent' == this.peek().type) {
      
ast.includeBlock().push(this.block());
    }

    return 
ast;
  },

  
/**
   * call ident block
   */

  
parseCall: function(){
    var 
tok this.expect('call')
      , 
name tok.val
      
args tok.args
      
mixin = new nodes.Mixin(nameargs, new nodes.Blocktrue);

    
this.tag(mixin);
    if (
mixin.block.isEmpty()) mixin.block null;
    return 
mixin;
  },

  
/**
   * mixin block
   */

  
parseMixin: function(){
    var 
tok this.expect('mixin')
      , 
name tok.val
      
args tok.args
      
mixin;

    
// definition
    
if ('indent' == this.peek().type) {
      
mixin = new nodes.Mixin(nameargsthis.block(), false);
      
this.mixins[name] = mixin;
      return 
mixin;
    
// call
    
} else {
      return new 
nodes.Mixin(nameargsnulltrue);
    }
  },

  
/**
   * indent (text | newline)* outdent
   */

  
parseTextBlock: function(){
    var 
block = new nodes.Block;
    
block.line this.line();
    var 
spaces this.expect('indent').val;
    if (
null == this._spacesthis._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);
      }
    }

    if (
spaces == this._spacesthis._spaces null;
    
this.expect('outdent');
    return 
block;
  },

  
/**
   * indent expr* outdent
   */
  
  
block: function(){
    var 
block = new nodes.Block;
    
block.line this.line();
    
this.expect('indent');
    while (
'outdent' != this.peek().type) {
      if (
'newline' == this.peek().type) {
        
this.advance();
      } else {
        
block.push(this.parseExpr());
      }
    }
    
this.expect('outdent');
    return 
block;
  },

  
/**
   * interpolation (attrs | class | id)* (text | code | ':')? newline* block?
   */
  
  
parseInterpolation: function(){
    var 
tok this.advance();
    var 
tag = new nodes.Tag(tok.val);
    
tag.buffer true;
    return 
this.tag(tag);
  },

  
/**
   * tag (attrs | class | id)* (text | code | ':')? newline* block?
   */
  
  
parseTag: function(){
    
// ast-filter look-ahead
    
var 2;
    if (
'attrs' == this.lookahead(i).type) ++i;
    if (
':' == this.lookahead(i).type) {
      if (
'indent' == this.lookahead(++i).type) {
        return 
this.parseASTFilter();
      }
    }

    var 
tok this.advance()
      , 
tag = new nodes.Tag(tok.val);

    
tag.selfClosing tok.selfClosing;

    return 
this.tag(tag);
  },

  
/**
   * Parse tag.
   */

  
tag: function(tag){
    var 
dot;

    
tag.line this.line();

    
// (attrs | class | id)*
    
out:
      while (
true) {
        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);

            if (
tok.selfClosingtag.selfClosing true;

            for (var 
0len names.lengthlen; ++i) {
              var 
name names[i]
                , 
val obj[name];
              
tag.setAttribute(namevalescaped[name]);
            }
            continue;
          default:
            break 
out;
        }
      }

    
// check immediate '.'
    
if ('.' == this.peek().val) {
      
dot tag.textOnly true;
      
this.advance();
    }

    
// (text | code | ':')?
    
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());
        break;
    }

    
// newline*
    
while ('newline' == this.peek().typethis.advance();

    
tag.textOnly tag.textOnly || ~textOnly.indexOf(tag.name);

    
// script special-case
    
if ('script' == tag.name) {
      var 
type tag.getAttribute('type');
      if (!
dot && type && 'text/javascript' != type.replace(/^['"]|['"]$/g, '')) {
        tag.textOnly = false;
      }
    }

    // block?
    if ('indent' == this.peek().type) {
      if (tag.textOnly) {
        this.lexer.pipeless = true;
        tag.block = this.parseTextBlock();
        this.lexer.pipeless = false;
      } 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;
  }
};

}); // module: parser.js

require.register("
runtime.js", function(module, exports, require){

/*!
 * Jade - runtime
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Lame Array.isArray() polyfill for now.
 */

if (!Array.isArray) {
  Array.isArray = function(arr){
    return '[object Array]' == Object.prototype.toString.call(arr);
  };
}

/**
 * Lame Object.keys() polyfill for now.
 */

if (!Object.keys) {
  Object.keys = function(obj){
    var arr = [];
    for (var key in obj) {
      if (obj.hasOwnProperty(key)) {
        arr.push(key);
      }
    }
    return arr;
  }
}

/**
 * Merge two attribute objects giving precedence
 * to values in object `b`. Classes are special-cased
 * allowing for arrays and merging/joining appropriately
 * resulting in a string.
 *
 * @param {Object} a
 * @param {Object} b
 * @return {Object} a
 * @api private
 */

exports.merge = function merge(a, b) {
  var ac = a['class'];
  var bc = b['class'];

  if (ac || bc) {
    ac = ac || [];
    bc = bc || [];
    if (!Array.isArray(ac)) ac = [ac];
    if (!Array.isArray(bc)) bc = [bc];
    ac = ac.filter(nulls);
    bc = bc.filter(nulls);
    a['class'] = ac.concat(bc).join(' ');
  }

  for (var key in b) {
    if (key != 'class') {
      a[key] = b[key];
    }
  }

  return a;
};

/**
 * Filter null `val`s.
 *
 * @param {Mixed} val
 * @return {Mixed}
 * @api private
 */

function nulls(val) {
  return val != null;
}

/**
 * Render the given attributes object.
 *
 * @param {Object} obj
 * @param {Object} escaped
 * @return {String}
 * @api private
 */

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];

      if ('boolean' == typeof val || null == val) {
        if (val) {
          terse
            ? buf.push(key)
            : buf.push(key + '="' + key + '"');
        }
      } else if (0 == key.indexOf('data') && 'string' != typeof val) {
        buf.push(key + "
='" + JSON.stringify(val) + "'");
      } else if ('class' == key && Array.isArray(val)) {
        buf.push(key + '="' + exports.escape(val.join(' ')) + '"');
      } else if (escaped && escaped[key]) {
        buf.push(key + '="' + exports.escape(val) + '"');
      } else {
        buf.push(key + '="' + val + '"');
      }
    }
  }

  return buf.join(' ');
};

/**
 * Escape the given string of `html`.
 *
 * @param {String} html
 * @return {String}
 * @api private
 */

exports.escape = function escape(html){
  return String(html)
    .replace(/&(?!(w+|#d+);)/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"
/g'&quot;');
};

/**
 * Re-throw the given `err` in context to the
 * the jade in `filename` at the given `lineno`.
 *
 * @param {Error} err
 * @param {String} filename
 * @param {String} lineno
 * @api private
 */

exports.rethrow = function rethrow(errfilenamelineno){
  if (!
filename) throw err;

  var 
context 3
    
str = require('fs').readFileSync(filename'utf8')
    , 
lines str.split('n')
    , 
start Math.max(lineno context0)
    , 
end Math.min(lines.lengthlineno context);

  
// Error context
  
var context lines.slice(startend).map(function(linei){
    var 
curr start 1;
    return (
curr == lineno '  > ' '    ')
      + 
curr
      
'| '
      
line;
  }).
join('n');

  
// Alter exception message
  
err.path filename;
  
err.message = (filename || 'Jade') + ':' lineno
    
'n' context 'nn' err.message;
  throw 
err;
};

}); 
// module: runtime.js

require.register("self-closing.js", function(moduleexports, require){

/*!
 * Jade - self closing tags
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

module.exports = [
    
'meta'
  
'img'
  
'link'
  
'input'
  
'source'
  
'area'
  
'base'
  
'col'
  
'br'
  
'hr'
];
}); 
// module: self-closing.js

require.register("utils.js", function(moduleexports, require){

/*!
 * Jade - utils
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Convert interpolation in the given string to JavaScript.
 *
 * @param {String} str
 * @return {String}
 * @api private
 */

var interpolate exports.interpolate = function(str){
  return 
str.replace(/(\)?([#!]){(.*?)}/g, function(str, escape, flag, code){
    
return escape
      
str
      
"' + "
        
+ ('!' == flag '' 'escape')
        + 
"((interp = " code.replace(/\'/g, "'")
        + "
) == null '' interp) + '";
  });
};

/**
 * Escape single quotes in `str`.
 *
 * @param {String} str
 * @return {String}
 * @api private
 */

var escape = exports.escape = function(str) {
  return str.replace(/'
/g"\'");
};

/**
 * Interpolate, and escape the given `str`.
 *
 * @param {String} str
 * @return {String}
 * @api private
 */

exports.text = function(str){
  return 
interpolate(escape(str));
};
}); 
// module: utils.js

window.jade = require("jade");
})();
Онлайн: 0
Реклама