aboutsummaryrefslogtreecommitdiffstats
path: root/node_modules/ejs
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/ejs')
-rw-r--r--node_modules/ejs/.gitmodules0
-rw-r--r--node_modules/ejs/.npmignore4
-rw-r--r--node_modules/ejs/.travis.yml7
-rw-r--r--node_modules/ejs/History.md138
-rw-r--r--node_modules/ejs/Makefile23
-rw-r--r--node_modules/ejs/Readme.md188
-rw-r--r--node_modules/ejs/benchmark.js14
-rw-r--r--node_modules/ejs/ejs.js647
-rw-r--r--node_modules/ejs/ejs.min.js1
-rw-r--r--node_modules/ejs/examples/client.html24
-rw-r--r--node_modules/ejs/examples/functions.ejs9
-rw-r--r--node_modules/ejs/examples/functions.js22
-rw-r--r--node_modules/ejs/examples/list.ejs7
-rw-r--r--node_modules/ejs/examples/list.js14
-rw-r--r--node_modules/ejs/index.js2
-rw-r--r--node_modules/ejs/lib/ejs.js357
-rw-r--r--node_modules/ejs/lib/filters.js201
-rw-r--r--node_modules/ejs/lib/utils.js24
-rw-r--r--node_modules/ejs/package.json51
-rw-r--r--node_modules/ejs/support/compile.js177
-rw-r--r--node_modules/ejs/test/ejs.js306
-rw-r--r--node_modules/ejs/test/fixtures/backslash.ejs1
-rw-r--r--node_modules/ejs/test/fixtures/backslash.html1
-rw-r--r--node_modules/ejs/test/fixtures/comments.ejs5
-rw-r--r--node_modules/ejs/test/fixtures/comments.html4
-rw-r--r--node_modules/ejs/test/fixtures/double-quote.ejs1
-rw-r--r--node_modules/ejs/test/fixtures/double-quote.html1
-rw-r--r--node_modules/ejs/test/fixtures/error.ejs5
-rw-r--r--node_modules/ejs/test/fixtures/error.out8
-rw-r--r--node_modules/ejs/test/fixtures/fail.ejs1
-rw-r--r--node_modules/ejs/test/fixtures/include.css.ejs1
-rw-r--r--node_modules/ejs/test/fixtures/include.css.html3
-rw-r--r--node_modules/ejs/test/fixtures/include.ejs5
-rw-r--r--node_modules/ejs/test/fixtures/include.html9
-rw-r--r--node_modules/ejs/test/fixtures/includes/menu-item.ejs1
-rw-r--r--node_modules/ejs/test/fixtures/includes/menu/item.ejs1
-rw-r--r--node_modules/ejs/test/fixtures/menu.ejs11
-rw-r--r--node_modules/ejs/test/fixtures/menu.html3
-rw-r--r--node_modules/ejs/test/fixtures/messed.ejs1
-rw-r--r--node_modules/ejs/test/fixtures/messed.html1
-rw-r--r--node_modules/ejs/test/fixtures/newlines.ejs5
-rw-r--r--node_modules/ejs/test/fixtures/newlines.html9
-rw-r--r--node_modules/ejs/test/fixtures/no.newlines.ejs5
-rw-r--r--node_modules/ejs/test/fixtures/no.newlines.html5
-rw-r--r--node_modules/ejs/test/fixtures/para.ejs1
-rw-r--r--node_modules/ejs/test/fixtures/pet.ejs1
-rw-r--r--node_modules/ejs/test/fixtures/single-quote.ejs1
-rw-r--r--node_modules/ejs/test/fixtures/single-quote.html1
-rw-r--r--node_modules/ejs/test/fixtures/style.css3
-rw-r--r--node_modules/ejs/test/fixtures/user.ejs1
50 files changed, 2311 insertions, 0 deletions
diff --git a/node_modules/ejs/.gitmodules b/node_modules/ejs/.gitmodules
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/node_modules/ejs/.gitmodules
diff --git a/node_modules/ejs/.npmignore b/node_modules/ejs/.npmignore
new file mode 100644
index 0000000..020ddac
--- /dev/null
+++ b/node_modules/ejs/.npmignore
@@ -0,0 +1,4 @@
+# ignore any vim files:
+*.sw[a-z]
+vim/.netrwhist
+node_modules
diff --git a/node_modules/ejs/.travis.yml b/node_modules/ejs/.travis.yml
new file mode 100644
index 0000000..1ccd299
--- /dev/null
+++ b/node_modules/ejs/.travis.yml
@@ -0,0 +1,7 @@
+language: node_js
+node_js:
+ - 0.11
+ - 0.10
+ - 0.9
+ - 0.6
+ - 0.8
diff --git a/node_modules/ejs/History.md b/node_modules/ejs/History.md
new file mode 100644
index 0000000..df3ccf6
--- /dev/null
+++ b/node_modules/ejs/History.md
@@ -0,0 +1,138 @@
+
+0.8.5 / 2013-11-21
+==================
+
+ * fix: Escape apostrophe & don't over-match existing entities
+ * fix function name changed by uglify
+ * fixes require, closes #78
+
+0.8.4 / 2013-05-08
+==================
+
+ * fix support for colons in filter arguments
+ * fix double callback when the callback throws
+ * rename escape option
+
+0.8.3 / 2012-09-13
+==================
+
+ * allow pre-compiling into a standalone function [seanmonstar]
+
+0.8.2 / 2012-08-16
+==================
+
+ * fix include "open" / "close" options. Closes #64
+
+0.8.1 / 2012-08-11
+==================
+
+ * fix comments. Closes #62 [Nate Silva]
+
+0.8.0 / 2012-07-25
+==================
+
+ * add `<% include file %>` support
+ * fix wrapping of custom require in build step. Closes #57
+
+0.7.3 / 2012-04-25
+==================
+
+ * Added repository to package.json [isaacs]
+
+0.7.1 / 2012-03-26
+==================
+
+ * Fixed exception when using express in production caused by typo. [slaskis]
+
+0.7.0 / 2012-03-24
+==================
+
+ * Added newline consumption support (`-%>`) [whoatemydomain]
+
+0.6.1 / 2011-12-09
+==================
+
+ * Fixed `ejs.renderFile()`
+
+0.6.0 / 2011-12-09
+==================
+
+ * Changed: you no longer need `{ locals: {} }`
+
+0.5.0 / 2011-11-20
+==================
+
+ * Added express 3.x support
+ * Added ejs.renderFile()
+ * Added 'json' filter
+ * Fixed tests for 0.5.x
+
+0.4.3 / 2011-06-20
+==================
+
+ * Fixed stacktraces line number when used multiline js expressions [Octave]
+
+0.4.2 / 2011-05-11
+==================
+
+ * Added client side support
+
+0.4.1 / 2011-04-21
+==================
+
+ * Fixed error context
+
+0.4.0 / 2011-04-21
+==================
+
+ * Added; ported jade's error reporting to ejs. [slaskis]
+
+0.3.1 / 2011-02-23
+==================
+
+ * Fixed optional `compile()` options
+
+0.3.0 / 2011-02-14
+==================
+
+ * Added 'json' filter [Yuriy Bogdanov]
+ * Use exported version of parse function to allow monkey-patching [Anatoliy Chakkaev]
+
+0.2.1 / 2010-10-07
+==================
+
+ * Added filter support
+ * Fixed _cache_ option. ~4x performance increase
+
+0.2.0 / 2010-08-05
+==================
+
+ * Added support for global tag config
+ * Added custom tag support. Closes #5
+ * Fixed whitespace bug. Closes #4
+
+0.1.0 / 2010-08-04
+==================
+
+ * Faster implementation [ashleydev]
+
+0.0.4 / 2010-08-02
+==================
+
+ * Fixed single quotes for content outside of template tags. [aniero]
+ * Changed; `exports.compile()` now expects only "locals"
+
+0.0.3 / 2010-07-15
+==================
+
+ * Fixed single quotes
+
+0.0.2 / 2010-07-09
+==================
+
+ * Fixed newline preservation
+
+0.0.1 / 2010-07-09
+==================
+
+ * Initial release
diff --git a/node_modules/ejs/Makefile b/node_modules/ejs/Makefile
new file mode 100644
index 0000000..a687a0a
--- /dev/null
+++ b/node_modules/ejs/Makefile
@@ -0,0 +1,23 @@
+
+SRC = $(shell find lib -name "*.js" -type f)
+UGLIFY_FLAGS = --no-mangle
+
+all: ejs.min.js
+
+test:
+ @./node_modules/.bin/mocha \
+ --reporter spec
+
+ejs.js: $(SRC)
+ @node support/compile.js $^
+
+ejs.min.js: ejs.js
+ @uglifyjs $(UGLIFY_FLAGS) $< > $@ \
+ && du ejs.min.js \
+ && du ejs.js
+
+clean:
+ rm -f ejs.js
+ rm -f ejs.min.js
+
+.PHONY: test \ No newline at end of file
diff --git a/node_modules/ejs/Readme.md b/node_modules/ejs/Readme.md
new file mode 100644
index 0000000..ab0a3dd
--- /dev/null
+++ b/node_modules/ejs/Readme.md
@@ -0,0 +1,188 @@
+# EJS
+
+Embedded JavaScript templates.
+
+[![Build Status](https://travis-ci.org/visionmedia/ejs.png)](https://travis-ci.org/visionmedia/ejs)
+
+## Installation
+
+ $ npm install ejs
+
+## Features
+
+ * Complies with the [Express](http://expressjs.com) view system
+ * Static caching of intermediate JavaScript
+ * Unbuffered code for conditionals etc `<% code %>`
+ * Escapes html by default with `<%= code %>`
+ * Unescaped buffering with `<%- code %>`
+ * Supports tag customization
+ * Filter support for designer-friendly templates
+ * Includes
+ * Client-side support
+ * Newline slurping with `<% code -%>` or `<% -%>` or `<%= code -%>` or `<%- code -%>`
+
+## Example
+
+ <% if (user) { %>
+ <h2><%= user.name %></h2>
+ <% } %>
+
+## Try out a live example now
+
+<a href="https://runnable.com/ejs" target="_blank"><img src="https://runnable.com/external/styles/assets/runnablebtn.png" style="width:67px;height:25px;"></a>
+
+## Usage
+
+ ejs.compile(str, options);
+ // => Function
+
+ ejs.render(str, options);
+ // => str
+
+## Options
+
+ - `cache` Compiled functions are cached, requires `filename`
+ - `filename` Used by `cache` to key caches
+ - `scope` Function execution context
+ - `debug` Output generated function body
+ - `compileDebug` When `false` no debug instrumentation is compiled
+ - `client` Returns standalone compiled function
+ - `open` Open tag, defaulting to "<%"
+ - `close` Closing tag, defaulting to "%>"
+ - * All others are template-local variables
+
+## Includes
+
+ Includes are relative to the template with the `include` statement,
+ for example if you have "./views/users.ejs" and "./views/user/show.ejs"
+ you would use `<% include user/show %>`. The included file(s) are literally
+ included into the template, _no_ IO is performed after compilation, thus
+ local variables are available to these included templates.
+
+```
+<ul>
+ <% users.forEach(function(user){ %>
+ <% include user/show %>
+ <% }) %>
+</ul>
+```
+
+## Custom delimiters
+
+Custom delimiters can also be applied globally:
+
+ var ejs = require('ejs');
+ ejs.open = '{{';
+ ejs.close = '}}';
+
+Which would make the following a valid template:
+
+ <h1>{{= title }}</h1>
+
+## Filters
+
+EJS conditionally supports the concept of "filters". A "filter chain"
+is a designer friendly api for manipulating data, without writing JavaScript.
+
+Filters can be applied by supplying the _:_ modifier, so for example if we wish to take the array `[{ name: 'tj' }, { name: 'mape' }, { name: 'guillermo' }]` and output a list of names we can do this simply with filters:
+
+Template:
+
+ <p><%=: users | map:'name' | join %></p>
+
+Output:
+
+ <p>Tj, Mape, Guillermo</p>
+
+Render call:
+
+ ejs.render(str, {
+ users: [
+ { name: 'tj' },
+ { name: 'mape' },
+ { name: 'guillermo' }
+ ]
+ });
+
+Or perhaps capitalize the first user's name for display:
+
+ <p><%=: users | first | capitalize %></p>
+
+## Filter list
+
+Currently these filters are available:
+
+ - first
+ - last
+ - capitalize
+ - downcase
+ - upcase
+ - sort
+ - sort_by:'prop'
+ - size
+ - length
+ - plus:n
+ - minus:n
+ - times:n
+ - divided_by:n
+ - join:'val'
+ - truncate:n
+ - truncate_words:n
+ - replace:pattern,substitution
+ - prepend:val
+ - append:val
+ - map:'prop'
+ - reverse
+ - get:'prop'
+
+## Adding filters
+
+ To add a filter simply add a method to the `.filters` object:
+
+```js
+ejs.filters.last = function(obj) {
+ return obj[obj.length - 1];
+};
+```
+
+## Layouts
+
+ Currently EJS has no notion of blocks, only compile-time `include`s,
+ however you may still utilize this feature to implement "layouts" by
+ simply including a header and footer like so:
+
+```html
+<% include head %>
+<h1>Title</h1>
+<p>My page</p>
+<% include foot %>
+```
+
+## client-side support
+
+ include `./ejs.js` or `./ejs.min.js` and `require("ejs").compile(str)`.
+
+## License
+
+(The MIT License)
+
+Copyright (c) 2009-2010 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/node_modules/ejs/benchmark.js b/node_modules/ejs/benchmark.js
new file mode 100644
index 0000000..7b267e1
--- /dev/null
+++ b/node_modules/ejs/benchmark.js
@@ -0,0 +1,14 @@
+
+
+var ejs = require('./lib/ejs'),
+ str = '<% if (foo) { %><p><%= foo %></p><% } %>',
+ times = 50000;
+
+console.log('rendering ' + times + ' times');
+
+var start = new Date;
+while (times--) {
+ ejs.render(str, { cache: true, filename: 'test', locals: { foo: 'bar' }});
+}
+
+console.log('took ' + (new Date - start) + 'ms'); \ No newline at end of file
diff --git a/node_modules/ejs/ejs.js b/node_modules/ejs/ejs.js
new file mode 100644
index 0000000..ab44a80
--- /dev/null
+++ b/node_modules/ejs/ejs.js
@@ -0,0 +1,647 @@
+ejs = (function(){
+
+// CommonJS require()
+
+function require(p){
+ if ('fs' == p) return {};
+ if ('path' == p) return {};
+ 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.substr(0, 1)) 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("ejs.js", function(module, exports, require){
+
+/*!
+ * EJS
+ * Copyright(c) 2012 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var utils = require('./utils')
+ , path = require('path')
+ , dirname = path.dirname
+ , extname = path.extname
+ , join = path.join
+ , fs = require('fs')
+ , read = fs.readFileSync;
+
+/**
+ * Filters.
+ *
+ * @type Object
+ */
+
+var filters = exports.filters = require('./filters');
+
+/**
+ * Intermediate js cache.
+ *
+ * @type Object
+ */
+
+var cache = {};
+
+/**
+ * Clear intermediate js cache.
+ *
+ * @api public
+ */
+
+exports.clearCache = function(){
+ cache = {};
+};
+
+/**
+ * Translate filtered code into function calls.
+ *
+ * @param {String} js
+ * @return {String}
+ * @api private
+ */
+
+function filtered(js) {
+ return js.substr(1).split('|').reduce(function(js, filter){
+ var parts = filter.split(':')
+ , name = parts.shift()
+ , args = parts.join(':') || '';
+ if (args) args = ', ' + args;
+ return 'filters.' + name + '(' + js + args + ')';
+ });
+};
+
+/**
+ * Re-throw the given `err` in context to the
+ * `str` of ejs, `filename`, and `lineno`.
+ *
+ * @param {Error} err
+ * @param {String} str
+ * @param {String} filename
+ * @param {String} lineno
+ * @api private
+ */
+
+function rethrow(err, str, filename, lineno){
+ var lines = str.split('\n')
+ , start = Math.max(lineno - 3, 0)
+ , end = Math.min(lines.length, lineno + 3);
+
+ // Error context
+ var context = lines.slice(start, end).map(function(line, i){
+ var curr = i + start + 1;
+ return (curr == lineno ? ' >> ' : ' ')
+ + curr
+ + '| '
+ + line;
+ }).join('\n');
+
+ // Alter exception message
+ err.path = filename;
+ err.message = (filename || 'ejs') + ':'
+ + lineno + '\n'
+ + context + '\n\n'
+ + err.message;
+
+ throw err;
+}
+
+/**
+ * Parse the given `str` of ejs, returning the function body.
+ *
+ * @param {String} str
+ * @return {String}
+ * @api public
+ */
+
+var parse = exports.parse = function(str, options){
+ var options = options || {}
+ , open = options.open || exports.open || '<%'
+ , close = options.close || exports.close || '%>'
+ , filename = options.filename
+ , compileDebug = options.compileDebug !== false
+ , buf = "";
+
+ buf += 'var buf = [];';
+ if (false !== options._with) buf += '\nwith (locals || {}) { (function(){ ';
+ buf += '\n buf.push(\'';
+
+ var lineno = 1;
+
+ var consumeEOL = false;
+ for (var i = 0, len = str.length; i < len; ++i) {
+ var stri = str[i];
+ if (str.slice(i, open.length + i) == open) {
+ i += open.length
+
+ var prefix, postfix, line = (compileDebug ? '__stack.lineno=' : '') + lineno;
+ switch (str[i]) {
+ case '=':
+ prefix = "', escape((" + line + ', ';
+ postfix = ")), '";
+ ++i;
+ break;
+ case '-':
+ prefix = "', (" + line + ', ';
+ postfix = "), '";
+ ++i;
+ break;
+ default:
+ prefix = "');" + line + ';';
+ postfix = "; buf.push('";
+ }
+
+ var end = str.indexOf(close, i)
+ , js = str.substring(i, end)
+ , start = i
+ , include = null
+ , n = 0;
+
+ if ('-' == js[js.length-1]){
+ js = js.substring(0, js.length - 2);
+ consumeEOL = true;
+ }
+
+ if (0 == js.trim().indexOf('include')) {
+ var name = js.trim().slice(7).trim();
+ if (!filename) throw new Error('filename option is required for includes');
+ var path = resolveInclude(name, filename);
+ include = read(path, 'utf8');
+ include = exports.parse(include, { filename: path, _with: false, open: open, close: close, compileDebug: compileDebug });
+ buf += "' + (function(){" + include + "})() + '";
+ js = '';
+ }
+
+ while (~(n = js.indexOf("\n", n))) n++, lineno++;
+ if (js.substr(0, 1) == ':') js = filtered(js);
+ if (js) {
+ if (js.lastIndexOf('//') > js.lastIndexOf('\n')) js += '\n';
+ buf += prefix;
+ buf += js;
+ buf += postfix;
+ }
+ i += end - start + close.length - 1;
+
+ } else if (stri == "\\") {
+ buf += "\\\\";
+ } else if (stri == "'") {
+ buf += "\\'";
+ } else if (stri == "\r") {
+ // ignore
+ } else if (stri == "\n") {
+ if (consumeEOL) {
+ consumeEOL = false;
+ } else {
+ buf += "\\n";
+ lineno++;
+ }
+ } else {
+ buf += stri;
+ }
+ }
+
+ if (false !== options._with) buf += "'); })();\n} \nreturn buf.join('');";
+ else buf += "');\nreturn buf.join('');";
+ return buf;
+};
+
+/**
+ * Compile the given `str` of ejs into a `Function`.
+ *
+ * @param {String} str
+ * @param {Object} options
+ * @return {Function}
+ * @api public
+ */
+
+var compile = exports.compile = function(str, options){
+ options = options || {};
+ var escape = options.escape || utils.escape;
+
+ var input = JSON.stringify(str)
+ , compileDebug = options.compileDebug !== false
+ , client = options.client
+ , filename = options.filename
+ ? JSON.stringify(options.filename)
+ : 'undefined';
+
+ if (compileDebug) {
+ // Adds the fancy stack trace meta info
+ str = [
+ 'var __stack = { lineno: 1, input: ' + input + ', filename: ' + filename + ' };',
+ rethrow.toString(),
+ 'try {',
+ exports.parse(str, options),
+ '} catch (err) {',
+ ' rethrow(err, __stack.input, __stack.filename, __stack.lineno);',
+ '}'
+ ].join("\n");
+ } else {
+ str = exports.parse(str, options);
+ }
+
+ if (options.debug) console.log(str);
+ if (client) str = 'escape = escape || ' + escape.toString() + ';\n' + str;
+
+ try {
+ var fn = new Function('locals, filters, escape, rethrow', str);
+ } catch (err) {
+ if ('SyntaxError' == err.name) {
+ err.message += options.filename
+ ? ' in ' + filename
+ : ' while compiling ejs';
+ }
+ throw err;
+ }
+
+ if (client) return fn;
+
+ return function(locals){
+ return fn.call(this, locals, filters, escape, rethrow);
+ }
+};
+
+/**
+ * Render the given `str` of ejs.
+ *
+ * Options:
+ *
+ * - `locals` Local variables object
+ * - `cache` Compiled functions are cached, requires `filename`
+ * - `filename` Used by `cache` to key caches
+ * - `scope` Function execution context
+ * - `debug` Output generated function body
+ * - `open` Open tag, defaulting to "<%"
+ * - `close` Closing tag, defaulting to "%>"
+ *
+ * @param {String} str
+ * @param {Object} options
+ * @return {String}
+ * @api public
+ */
+
+exports.render = function(str, options){
+ var fn
+ , options = options || {};
+
+ if (options.cache) {
+ if (options.filename) {
+ fn = cache[options.filename] || (cache[options.filename] = compile(str, options));
+ } else {
+ throw new Error('"cache" option requires "filename".');
+ }
+ } else {
+ fn = compile(str, options);
+ }
+
+ options.__proto__ = options.locals;
+ return fn.call(options.scope, options);
+};
+
+/**
+ * Render an EJS 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 = {};
+ }
+
+ options.filename = path;
+
+ var str;
+ try {
+ str = options.cache
+ ? cache[key] || (cache[key] = read(path, 'utf8'))
+ : read(path, 'utf8');
+ } catch (err) {
+ fn(err);
+ return;
+ }
+ fn(null, exports.render(str, options));
+};
+
+/**
+ * Resolve include `name` relative to `filename`.
+ *
+ * @param {String} name
+ * @param {String} filename
+ * @return {String}
+ * @api private
+ */
+
+function resolveInclude(name, filename) {
+ var path = join(dirname(filename), name);
+ var ext = extname(name);
+ if (!ext) path += '.ejs';
+ return path;
+}
+
+// express support
+
+exports.__express = exports.renderFile;
+
+/**
+ * Expose to require().
+ */
+
+if (require.extensions) {
+ require.extensions['.ejs'] = function (module, filename) {
+ filename = filename || module.filename;
+ var options = { filename: filename, client: true }
+ , template = fs.readFileSync(filename).toString()
+ , fn = compile(template, options);
+ module._compile('module.exports = ' + fn.toString() + ';', filename);
+ };
+} else if (require.registerExtension) {
+ require.registerExtension('.ejs', function(src) {
+ return compile(src, {});
+ });
+}
+
+}); // module: ejs.js
+
+require.register("filters.js", function(module, exports, require){
+/*!
+ * EJS - Filters
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * First element of the target `obj`.
+ */
+
+exports.first = function(obj) {
+ return obj[0];
+};
+
+/**
+ * Last element of the target `obj`.
+ */
+
+exports.last = function(obj) {
+ return obj[obj.length - 1];
+};
+
+/**
+ * Capitalize the first letter of the target `str`.
+ */
+
+exports.capitalize = function(str){
+ str = String(str);
+ return str[0].toUpperCase() + str.substr(1, str.length);
+};
+
+/**
+ * Downcase the target `str`.
+ */
+
+exports.downcase = function(str){
+ return String(str).toLowerCase();
+};
+
+/**
+ * Uppercase the target `str`.
+ */
+
+exports.upcase = function(str){
+ return String(str).toUpperCase();
+};
+
+/**
+ * Sort the target `obj`.
+ */
+
+exports.sort = function(obj){
+ return Object.create(obj).sort();
+};
+
+/**
+ * Sort the target `obj` by the given `prop` ascending.
+ */
+
+exports.sort_by = function(obj, prop){
+ return Object.create(obj).sort(function(a, b){
+ a = a[prop], b = b[prop];
+ if (a > b) return 1;
+ if (a < b) return -1;
+ return 0;
+ });
+};
+
+/**
+ * Size or length of the target `obj`.
+ */
+
+exports.size = exports.length = function(obj) {
+ return obj.length;
+};
+
+/**
+ * Add `a` and `b`.
+ */
+
+exports.plus = function(a, b){
+ return Number(a) + Number(b);
+};
+
+/**
+ * Subtract `b` from `a`.
+ */
+
+exports.minus = function(a, b){
+ return Number(a) - Number(b);
+};
+
+/**
+ * Multiply `a` by `b`.
+ */
+
+exports.times = function(a, b){
+ return Number(a) * Number(b);
+};
+
+/**
+ * Divide `a` by `b`.
+ */
+
+exports.divided_by = function(a, b){
+ return Number(a) / Number(b);
+};
+
+/**
+ * Join `obj` with the given `str`.
+ */
+
+exports.join = function(obj, str){
+ return obj.join(str || ', ');
+};
+
+/**
+ * Truncate `str` to `len`.
+ */
+
+exports.truncate = function(str, len, append){
+ str = String(str);
+ if (str.length > len) {
+ str = str.slice(0, len);
+ if (append) str += append;
+ }
+ return str;
+};
+
+/**
+ * Truncate `str` to `n` words.
+ */
+
+exports.truncate_words = function(str, n){
+ var str = String(str)
+ , words = str.split(/ +/);
+ return words.slice(0, n).join(' ');
+};
+
+/**
+ * Replace `pattern` with `substitution` in `str`.
+ */
+
+exports.replace = function(str, pattern, substitution){
+ return String(str).replace(pattern, substitution || '');
+};
+
+/**
+ * Prepend `val` to `obj`.
+ */
+
+exports.prepend = function(obj, val){
+ return Array.isArray(obj)
+ ? [val].concat(obj)
+ : val + obj;
+};
+
+/**
+ * Append `val` to `obj`.
+ */
+
+exports.append = function(obj, val){
+ return Array.isArray(obj)
+ ? obj.concat(val)
+ : obj + val;
+};
+
+/**
+ * Map the given `prop`.
+ */
+
+exports.map = function(arr, prop){
+ return arr.map(function(obj){
+ return obj[prop];
+ });
+};
+
+/**
+ * Reverse the given `obj`.
+ */
+
+exports.reverse = function(obj){
+ return Array.isArray(obj)
+ ? obj.reverse()
+ : String(obj).split('').reverse().join('');
+};
+
+/**
+ * Get `prop` of the given `obj`.
+ */
+
+exports.get = function(obj, prop){
+ return obj[prop];
+};
+
+/**
+ * Packs the given `obj` into json string
+ */
+exports.json = function(obj){
+ return JSON.stringify(obj);
+};
+
+}); // module: filters.js
+
+require.register("utils.js", function(module, exports, require){
+
+/*!
+ * EJS
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Escape the given string of `html`.
+ *
+ * @param {String} html
+ * @return {String}
+ * @api private
+ */
+
+exports.escape = function(html){
+ return String(html)
+ .replace(/&(?!#?[a-zA-Z0-9]+;)/g, '&amp;')
+ .replace(/</g, '&lt;')
+ .replace(/>/g, '&gt;')
+ .replace(/'/g, '&#39;')
+ .replace(/"/g, '&quot;');
+};
+
+
+}); // module: utils.js
+
+ return require("ejs");
+})(); \ No newline at end of file
diff --git a/node_modules/ejs/ejs.min.js b/node_modules/ejs/ejs.min.js
new file mode 100644
index 0000000..cce06af
--- /dev/null
+++ b/node_modules/ejs/ejs.min.js
@@ -0,0 +1 @@
+ejs=function(){function require(p){if("fs"==p)return{};if("path"==p)return{};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.substr(0,1))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("ejs.js",function(module,exports,require){var utils=require("./utils"),path=require("path"),dirname=path.dirname,extname=path.extname,join=path.join,fs=require("fs"),read=fs.readFileSync;var filters=exports.filters=require("./filters");var cache={};exports.clearCache=function(){cache={}};function filtered(js){return js.substr(1).split("|").reduce(function(js,filter){var parts=filter.split(":"),name=parts.shift(),args=parts.join(":")||"";if(args)args=", "+args;return"filters."+name+"("+js+args+")"})}function rethrow(err,str,filename,lineno){var lines=str.split("\n"),start=Math.max(lineno-3,0),end=Math.min(lines.length,lineno+3);var context=lines.slice(start,end).map(function(line,i){var curr=i+start+1;return(curr==lineno?" >> ":" ")+curr+"| "+line}).join("\n");err.path=filename;err.message=(filename||"ejs")+":"+lineno+"\n"+context+"\n\n"+err.message;throw err}var parse=exports.parse=function(str,options){var options=options||{},open=options.open||exports.open||"<%",close=options.close||exports.close||"%>",filename=options.filename,compileDebug=options.compileDebug!==false,buf="";buf+="var buf = [];";if(false!==options._with)buf+="\nwith (locals || {}) { (function(){ ";buf+="\n buf.push('";var lineno=1;var consumeEOL=false;for(var i=0,len=str.length;i<len;++i){var stri=str[i];if(str.slice(i,open.length+i)==open){i+=open.length;var prefix,postfix,line=(compileDebug?"__stack.lineno=":"")+lineno;switch(str[i]){case"=":prefix="', escape(("+line+", ";postfix=")), '";++i;break;case"-":prefix="', ("+line+", ";postfix="), '";++i;break;default:prefix="');"+line+";";postfix="; buf.push('"}var end=str.indexOf(close,i),js=str.substring(i,end),start=i,include=null,n=0;if("-"==js[js.length-1]){js=js.substring(0,js.length-2);consumeEOL=true}if(0==js.trim().indexOf("include")){var name=js.trim().slice(7).trim();if(!filename)throw new Error("filename option is required for includes");var path=resolveInclude(name,filename);include=read(path,"utf8");include=exports.parse(include,{filename:path,_with:false,open:open,close:close,compileDebug:compileDebug});buf+="' + (function(){"+include+"})() + '";js=""}while(~(n=js.indexOf("\n",n)))n++,lineno++;if(js.substr(0,1)==":")js=filtered(js);if(js){if(js.lastIndexOf("//")>js.lastIndexOf("\n"))js+="\n";buf+=prefix;buf+=js;buf+=postfix}i+=end-start+close.length-1}else if(stri=="\\"){buf+="\\\\"}else if(stri=="'"){buf+="\\'"}else if(stri=="\r"){}else if(stri=="\n"){if(consumeEOL){consumeEOL=false}else{buf+="\\n";lineno++}}else{buf+=stri}}if(false!==options._with)buf+="'); })();\n} \nreturn buf.join('');";else buf+="');\nreturn buf.join('');";return buf};var compile=exports.compile=function(str,options){options=options||{};var escape=options.escape||utils.escape;var input=JSON.stringify(str),compileDebug=options.compileDebug!==false,client=options.client,filename=options.filename?JSON.stringify(options.filename):"undefined";if(compileDebug){str=["var __stack = { lineno: 1, input: "+input+", filename: "+filename+" };",rethrow.toString(),"try {",exports.parse(str,options),"} catch (err) {"," rethrow(err, __stack.input, __stack.filename, __stack.lineno);","}"].join("\n")}else{str=exports.parse(str,options)}if(options.debug)console.log(str);if(client)str="escape = escape || "+escape.toString()+";\n"+str;try{var fn=new Function("locals, filters, escape, rethrow",str)}catch(err){if("SyntaxError"==err.name){err.message+=options.filename?" in "+filename:" while compiling ejs"}throw err}if(client)return fn;return function(locals){return fn.call(this,locals,filters,escape,rethrow)}};exports.render=function(str,options){var fn,options=options||{};if(options.cache){if(options.filename){fn=cache[options.filename]||(cache[options.filename]=compile(str,options))}else{throw new Error('"cache" option requires "filename".')}}else{fn=compile(str,options)}options.__proto__=options.locals;return fn.call(options.scope,options)};exports.renderFile=function(path,options,fn){var key=path+":string";if("function"==typeof options){fn=options,options={}}options.filename=path;var str;try{str=options.cache?cache[key]||(cache[key]=read(path,"utf8")):read(path,"utf8")}catch(err){fn(err);return}fn(null,exports.render(str,options))};function resolveInclude(name,filename){var path=join(dirname(filename),name);var ext=extname(name);if(!ext)path+=".ejs";return path}exports.__express=exports.renderFile;if(require.extensions){require.extensions[".ejs"]=function(module,filename){filename=filename||module.filename;var options={filename:filename,client:true},template=fs.readFileSync(filename).toString(),fn=compile(template,options);module._compile("module.exports = "+fn.toString()+";",filename)}}else if(require.registerExtension){require.registerExtension(".ejs",function(src){return compile(src,{})})}});require.register("filters.js",function(module,exports,require){exports.first=function(obj){return obj[0]};exports.last=function(obj){return obj[obj.length-1]};exports.capitalize=function(str){str=String(str);return str[0].toUpperCase()+str.substr(1,str.length)};exports.downcase=function(str){return String(str).toLowerCase()};exports.upcase=function(str){return String(str).toUpperCase()};exports.sort=function(obj){return Object.create(obj).sort()};exports.sort_by=function(obj,prop){return Object.create(obj).sort(function(a,b){a=a[prop],b=b[prop];if(a>b)return 1;if(a<b)return-1;return 0})};exports.size=exports.length=function(obj){return obj.length};exports.plus=function(a,b){return Number(a)+Number(b)};exports.minus=function(a,b){return Number(a)-Number(b)};exports.times=function(a,b){return Number(a)*Number(b)};exports.divided_by=function(a,b){return Number(a)/Number(b)};exports.join=function(obj,str){return obj.join(str||", ")};exports.truncate=function(str,len,append){str=String(str);if(str.length>len){str=str.slice(0,len);if(append)str+=append}return str};exports.truncate_words=function(str,n){var str=String(str),words=str.split(/ +/);return words.slice(0,n).join(" ")};exports.replace=function(str,pattern,substitution){return String(str).replace(pattern,substitution||"")};exports.prepend=function(obj,val){return Array.isArray(obj)?[val].concat(obj):val+obj};exports.append=function(obj,val){return Array.isArray(obj)?obj.concat(val):obj+val};exports.map=function(arr,prop){return arr.map(function(obj){return obj[prop]})};exports.reverse=function(obj){return Array.isArray(obj)?obj.reverse():String(obj).split("").reverse().join("")};exports.get=function(obj,prop){return obj[prop]};exports.json=function(obj){return JSON.stringify(obj)}});require.register("utils.js",function(module,exports,require){exports.escape=function(html){return String(html).replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/'/g,"&#39;").replace(/"/g,"&quot;")}});return require("ejs")}(); \ No newline at end of file
diff --git a/node_modules/ejs/examples/client.html b/node_modules/ejs/examples/client.html
new file mode 100644
index 0000000..30dfea9
--- /dev/null
+++ b/node_modules/ejs/examples/client.html
@@ -0,0 +1,24 @@
+<html>
+ <head>
+ <script src="../ejs.js"></script>
+ <script id="users" type="text/template">
+ <% if (names.length) { %>
+ <ul>
+ <% names.forEach(function(name){ %>
+ <li><%= name %></li>
+ <% }) %>
+ </ul>
+ <% } %>
+ </script>
+ <script>
+ onload = function(){
+ var users = document.getElementById('users').innerHTML;
+ var names = ['loki', 'tobi', 'jane'];
+ var html = ejs.render(users, { names: names });
+ document.body.innerHTML = html;
+ }
+ </script>
+ </head>
+ <body>
+ </body>
+</html> \ No newline at end of file
diff --git a/node_modules/ejs/examples/functions.ejs b/node_modules/ejs/examples/functions.ejs
new file mode 100644
index 0000000..bd5610e
--- /dev/null
+++ b/node_modules/ejs/examples/functions.ejs
@@ -0,0 +1,9 @@
+<h1>Users</h1>
+
+<% function user(user) { %>
+ <li><strong><%= user.name %></strong> is a <%= user.age %> year old <%= user.species %>.</li>
+<% } %>
+
+<ul>
+ <% users.map(user) %>
+</ul> \ No newline at end of file
diff --git a/node_modules/ejs/examples/functions.js b/node_modules/ejs/examples/functions.js
new file mode 100644
index 0000000..607833f
--- /dev/null
+++ b/node_modules/ejs/examples/functions.js
@@ -0,0 +1,22 @@
+
+/**
+ * Module dependencies.
+ */
+
+var ejs = require('../')
+ , fs = require('fs')
+ , path = __dirname + '/functions.ejs'
+ , str = fs.readFileSync(path, 'utf8');
+
+var users = [];
+
+users.push({ name: 'Tobi', age: 2, species: 'ferret' })
+users.push({ name: 'Loki', age: 2, species: 'ferret' })
+users.push({ name: 'Jane', age: 6, species: 'ferret' })
+
+var ret = ejs.render(str, {
+ users: users,
+ filename: path
+});
+
+console.log(ret); \ No newline at end of file
diff --git a/node_modules/ejs/examples/list.ejs b/node_modules/ejs/examples/list.ejs
new file mode 100644
index 0000000..0b378a9
--- /dev/null
+++ b/node_modules/ejs/examples/list.ejs
@@ -0,0 +1,7 @@
+<% if (names.length) { %>
+ <ul>
+ <% names.forEach(function(name){ %>
+ <li foo='<%= name + "'" %>'><%= name %></li>
+ <% }) %>
+ </ul>
+<% } %> \ No newline at end of file
diff --git a/node_modules/ejs/examples/list.js b/node_modules/ejs/examples/list.js
new file mode 100644
index 0000000..ec614ed
--- /dev/null
+++ b/node_modules/ejs/examples/list.js
@@ -0,0 +1,14 @@
+
+/**
+ * Module dependencies.
+ */
+
+var ejs = require('../')
+ , fs = require('fs')
+ , str = fs.readFileSync(__dirname + '/list.ejs', 'utf8');
+
+var ret = ejs.render(str, {
+ names: ['foo', 'bar', 'baz']
+});
+
+console.log(ret); \ No newline at end of file
diff --git a/node_modules/ejs/index.js b/node_modules/ejs/index.js
new file mode 100644
index 0000000..20bf71a
--- /dev/null
+++ b/node_modules/ejs/index.js
@@ -0,0 +1,2 @@
+
+module.exports = require('./lib/ejs'); \ No newline at end of file
diff --git a/node_modules/ejs/lib/ejs.js b/node_modules/ejs/lib/ejs.js
new file mode 100644
index 0000000..f36944f
--- /dev/null
+++ b/node_modules/ejs/lib/ejs.js
@@ -0,0 +1,357 @@
+
+/*!
+ * EJS
+ * Copyright(c) 2012 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var utils = require('./utils')
+ , path = require('path')
+ , dirname = path.dirname
+ , extname = path.extname
+ , join = path.join
+ , fs = require('fs')
+ , read = fs.readFileSync;
+
+/**
+ * Filters.
+ *
+ * @type Object
+ */
+
+var filters = exports.filters = require('./filters');
+
+/**
+ * Intermediate js cache.
+ *
+ * @type Object
+ */
+
+var cache = {};
+
+/**
+ * Clear intermediate js cache.
+ *
+ * @api public
+ */
+
+exports.clearCache = function(){
+ cache = {};
+};
+
+/**
+ * Translate filtered code into function calls.
+ *
+ * @param {String} js
+ * @return {String}
+ * @api private
+ */
+
+function filtered(js) {
+ return js.substr(1).split('|').reduce(function(js, filter){
+ var parts = filter.split(':')
+ , name = parts.shift()
+ , args = parts.join(':') || '';
+ if (args) args = ', ' + args;
+ return 'filters.' + name + '(' + js + args + ')';
+ });
+};
+
+/**
+ * Re-throw the given `err` in context to the
+ * `str` of ejs, `filename`, and `lineno`.
+ *
+ * @param {Error} err
+ * @param {String} str
+ * @param {String} filename
+ * @param {String} lineno
+ * @api private
+ */
+
+function rethrow(err, str, filename, lineno){
+ var lines = str.split('\n')
+ , start = Math.max(lineno - 3, 0)
+ , end = Math.min(lines.length, lineno + 3);
+
+ // Error context
+ var context = lines.slice(start, end).map(function(line, i){
+ var curr = i + start + 1;
+ return (curr == lineno ? ' >> ' : ' ')
+ + curr
+ + '| '
+ + line;
+ }).join('\n');
+
+ // Alter exception message
+ err.path = filename;
+ err.message = (filename || 'ejs') + ':'
+ + lineno + '\n'
+ + context + '\n\n'
+ + err.message;
+
+ throw err;
+}
+
+/**
+ * Parse the given `str` of ejs, returning the function body.
+ *
+ * @param {String} str
+ * @return {String}
+ * @api public
+ */
+
+var parse = exports.parse = function(str, options){
+ var options = options || {}
+ , open = options.open || exports.open || '<%'
+ , close = options.close || exports.close || '%>'
+ , filename = options.filename
+ , compileDebug = options.compileDebug !== false
+ , buf = "";
+
+ buf += 'var buf = [];';
+ if (false !== options._with) buf += '\nwith (locals || {}) { (function(){ ';
+ buf += '\n buf.push(\'';
+
+ var lineno = 1;
+
+ var consumeEOL = false;
+ for (var i = 0, len = str.length; i < len; ++i) {
+ var stri = str[i];
+ if (str.slice(i, open.length + i) == open) {
+ i += open.length
+
+ var prefix, postfix, line = (compileDebug ? '__stack.lineno=' : '') + lineno;
+ switch (str[i]) {
+ case '=':
+ prefix = "', escape((" + line + ', ';
+ postfix = ")), '";
+ ++i;
+ break;
+ case '-':
+ prefix = "', (" + line + ', ';
+ postfix = "), '";
+ ++i;
+ break;
+ default:
+ prefix = "');" + line + ';';
+ postfix = "; buf.push('";
+ }
+
+ var end = str.indexOf(close, i)
+ , js = str.substring(i, end)
+ , start = i
+ , include = null
+ , n = 0;
+
+ if ('-' == js[js.length-1]){
+ js = js.substring(0, js.length - 2);
+ consumeEOL = true;
+ }
+
+ if (0 == js.trim().indexOf('include')) {
+ var name = js.trim().slice(7).trim();
+ if (!filename) throw new Error('filename option is required for includes');
+ var path = resolveInclude(name, filename);
+ include = read(path, 'utf8');
+ include = exports.parse(include, { filename: path, _with: false, open: open, close: close, compileDebug: compileDebug });
+ buf += "' + (function(){" + include + "})() + '";
+ js = '';
+ }
+
+ while (~(n = js.indexOf("\n", n))) n++, lineno++;
+ if (js.substr(0, 1) == ':') js = filtered(js);
+ if (js) {
+ if (js.lastIndexOf('//') > js.lastIndexOf('\n')) js += '\n';
+ buf += prefix;
+ buf += js;
+ buf += postfix;
+ }
+ i += end - start + close.length - 1;
+
+ } else if (stri == "\\") {
+ buf += "\\\\";
+ } else if (stri == "'") {
+ buf += "\\'";
+ } else if (stri == "\r") {
+ // ignore
+ } else if (stri == "\n") {
+ if (consumeEOL) {
+ consumeEOL = false;
+ } else {
+ buf += "\\n";
+ lineno++;
+ }
+ } else {
+ buf += stri;
+ }
+ }
+
+ if (false !== options._with) buf += "'); })();\n} \nreturn buf.join('');";
+ else buf += "');\nreturn buf.join('');";
+ return buf;
+};
+
+/**
+ * Compile the given `str` of ejs into a `Function`.
+ *
+ * @param {String} str
+ * @param {Object} options
+ * @return {Function}
+ * @api public
+ */
+
+var compile = exports.compile = function(str, options){
+ options = options || {};
+ var escape = options.escape || utils.escape;
+
+ var input = JSON.stringify(str)
+ , compileDebug = options.compileDebug !== false
+ , client = options.client
+ , filename = options.filename
+ ? JSON.stringify(options.filename)
+ : 'undefined';
+
+ if (compileDebug) {
+ // Adds the fancy stack trace meta info
+ str = [
+ 'var __stack = { lineno: 1, input: ' + input + ', filename: ' + filename + ' };',
+ rethrow.toString(),
+ 'try {',
+ exports.parse(str, options),
+ '} catch (err) {',
+ ' rethrow(err, __stack.input, __stack.filename, __stack.lineno);',
+ '}'
+ ].join("\n");
+ } else {
+ str = exports.parse(str, options);
+ }
+
+ if (options.debug) console.log(str);
+ if (client) str = 'escape = escape || ' + escape.toString() + ';\n' + str;
+
+ try {
+ var fn = new Function('locals, filters, escape, rethrow', str);
+ } catch (err) {
+ if ('SyntaxError' == err.name) {
+ err.message += options.filename
+ ? ' in ' + filename
+ : ' while compiling ejs';
+ }
+ throw err;
+ }
+
+ if (client) return fn;
+
+ return function(locals){
+ return fn.call(this, locals, filters, escape, rethrow);
+ }
+};
+
+/**
+ * Render the given `str` of ejs.
+ *
+ * Options:
+ *
+ * - `locals` Local variables object
+ * - `cache` Compiled functions are cached, requires `filename`
+ * - `filename` Used by `cache` to key caches
+ * - `scope` Function execution context
+ * - `debug` Output generated function body
+ * - `open` Open tag, defaulting to "<%"
+ * - `close` Closing tag, defaulting to "%>"
+ *
+ * @param {String} str
+ * @param {Object} options
+ * @return {String}
+ * @api public
+ */
+
+exports.render = function(str, options){
+ var fn
+ , options = options || {};
+
+ if (options.cache) {
+ if (options.filename) {
+ fn = cache[options.filename] || (cache[options.filename] = compile(str, options));
+ } else {
+ throw new Error('"cache" option requires "filename".');
+ }
+ } else {
+ fn = compile(str, options);
+ }
+
+ options.__proto__ = options.locals;
+ return fn.call(options.scope, options);
+};
+
+/**
+ * Render an EJS 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 = {};
+ }
+
+ options.filename = path;
+
+ var str;
+ try {
+ str = options.cache
+ ? cache[key] || (cache[key] = read(path, 'utf8'))
+ : read(path, 'utf8');
+ } catch (err) {
+ fn(err);
+ return;
+ }
+ fn(null, exports.render(str, options));
+};
+
+/**
+ * Resolve include `name` relative to `filename`.
+ *
+ * @param {String} name
+ * @param {String} filename
+ * @return {String}
+ * @api private
+ */
+
+function resolveInclude(name, filename) {
+ var path = join(dirname(filename), name);
+ var ext = extname(name);
+ if (!ext) path += '.ejs';
+ return path;
+}
+
+// express support
+
+exports.__express = exports.renderFile;
+
+/**
+ * Expose to require().
+ */
+
+if (require.extensions) {
+ require.extensions['.ejs'] = function (module, filename) {
+ filename = filename || module.filename;
+ var options = { filename: filename, client: true }
+ , template = fs.readFileSync(filename).toString()
+ , fn = compile(template, options);
+ module._compile('module.exports = ' + fn.toString() + ';', filename);
+ };
+} else if (require.registerExtension) {
+ require.registerExtension('.ejs', function(src) {
+ return compile(src, {});
+ });
+}
diff --git a/node_modules/ejs/lib/filters.js b/node_modules/ejs/lib/filters.js
new file mode 100644
index 0000000..45b0478
--- /dev/null
+++ b/node_modules/ejs/lib/filters.js
@@ -0,0 +1,201 @@
+/*!
+ * EJS - Filters
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * First element of the target `obj`.
+ */
+
+exports.first = function(obj) {
+ return obj[0];
+};
+
+/**
+ * Last element of the target `obj`.
+ */
+
+exports.last = function(obj) {
+ return obj[obj.length - 1];
+};
+
+/**
+ * Capitalize the first letter of the target `str`.
+ */
+
+exports.capitalize = function(str){
+ str = String(str);
+ return str[0].toUpperCase() + str.substr(1, str.length);
+};
+
+/**
+ * Downcase the target `str`.
+ */
+
+exports.downcase = function(str){
+ return String(str).toLowerCase();
+};
+
+/**
+ * Uppercase the target `str`.
+ */
+
+exports.upcase = function(str){
+ return String(str).toUpperCase();
+};
+
+/**
+ * Sort the target `obj`.
+ */
+
+exports.sort = function(obj){
+ return Object.create(obj).sort();
+};
+
+/**
+ * Sort the target `obj` by the given `prop` ascending.
+ */
+
+exports.sort_by = function(obj, prop){
+ return Object.create(obj).sort(function(a, b){
+ a = a[prop], b = b[prop];
+ if (a > b) return 1;
+ if (a < b) return -1;
+ return 0;
+ });
+};
+
+/**
+ * Size or length of the target `obj`.
+ */
+
+exports.size = exports.length = function(obj) {
+ return obj.length;
+};
+
+/**
+ * Add `a` and `b`.
+ */
+
+exports.plus = function(a, b){
+ return Number(a) + Number(b);
+};
+
+/**
+ * Subtract `b` from `a`.
+ */
+
+exports.minus = function(a, b){
+ return Number(a) - Number(b);
+};
+
+/**
+ * Multiply `a` by `b`.
+ */
+
+exports.times = function(a, b){
+ return Number(a) * Number(b);
+};
+
+/**
+ * Divide `a` by `b`.
+ */
+
+exports.divided_by = function(a, b){
+ return Number(a) / Number(b);
+};
+
+/**
+ * Join `obj` with the given `str`.
+ */
+
+exports.join = function(obj, str){
+ return obj.join(str || ', ');
+};
+
+/**
+ * Truncate `str` to `len`.
+ */
+
+exports.truncate = function(str, len, append){
+ str = String(str);
+ if (str.length > len) {
+ str = str.slice(0, len);
+ if (append) str += append;
+ }
+ return str;
+};
+
+/**
+ * Truncate `str` to `n` words.
+ */
+
+exports.truncate_words = function(str, n){
+ var str = String(str)
+ , words = str.split(/ +/);
+ return words.slice(0, n).join(' ');
+};
+
+/**
+ * Replace `pattern` with `substitution` in `str`.
+ */
+
+exports.replace = function(str, pattern, substitution){
+ return String(str).replace(pattern, substitution || '');
+};
+
+/**
+ * Prepend `val` to `obj`.
+ */
+
+exports.prepend = function(obj, val){
+ return Array.isArray(obj)
+ ? [val].concat(obj)
+ : val + obj;
+};
+
+/**
+ * Append `val` to `obj`.
+ */
+
+exports.append = function(obj, val){
+ return Array.isArray(obj)
+ ? obj.concat(val)
+ : obj + val;
+};
+
+/**
+ * Map the given `prop`.
+ */
+
+exports.map = function(arr, prop){
+ return arr.map(function(obj){
+ return obj[prop];
+ });
+};
+
+/**
+ * Reverse the given `obj`.
+ */
+
+exports.reverse = function(obj){
+ return Array.isArray(obj)
+ ? obj.reverse()
+ : String(obj).split('').reverse().join('');
+};
+
+/**
+ * Get `prop` of the given `obj`.
+ */
+
+exports.get = function(obj, prop){
+ return obj[prop];
+};
+
+/**
+ * Packs the given `obj` into json string
+ */
+exports.json = function(obj){
+ return JSON.stringify(obj);
+};
diff --git a/node_modules/ejs/lib/utils.js b/node_modules/ejs/lib/utils.js
new file mode 100644
index 0000000..8df6c6a
--- /dev/null
+++ b/node_modules/ejs/lib/utils.js
@@ -0,0 +1,24 @@
+
+/*!
+ * EJS
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Escape the given string of `html`.
+ *
+ * @param {String} html
+ * @return {String}
+ * @api private
+ */
+
+exports.escape = function(html){
+ return String(html)
+ .replace(/&(?!#?[a-zA-Z0-9]+;)/g, '&amp;')
+ .replace(/</g, '&lt;')
+ .replace(/>/g, '&gt;')
+ .replace(/'/g, '&#39;')
+ .replace(/"/g, '&quot;');
+};
+
diff --git a/node_modules/ejs/package.json b/node_modules/ejs/package.json
new file mode 100644
index 0000000..627896b
--- /dev/null
+++ b/node_modules/ejs/package.json
@@ -0,0 +1,51 @@
+{
+ "name": "ejs",
+ "description": "Embedded JavaScript templates",
+ "version": "0.8.8",
+ "author": {
+ "name": "TJ Holowaychuk",
+ "email": "tj@vision-media.ca"
+ },
+ "keywords": [
+ "template",
+ "engine",
+ "ejs"
+ ],
+ "devDependencies": {
+ "mocha": "*",
+ "should": "*"
+ },
+ "main": "./lib/ejs.js",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/visionmedia/ejs.git"
+ },
+ "scripts": {
+ "test": "mocha --require should --reporter spec"
+ },
+ "bugs": {
+ "url": "https://github.com/visionmedia/ejs/issues"
+ },
+ "homepage": "https://github.com/visionmedia/ejs",
+ "_id": "ejs@0.8.8",
+ "dist": {
+ "shasum": "ffdc56dcc35d02926dd50ad13439bbc54061d598",
+ "tarball": "http://registry.npmjs.org/ejs/-/ejs-0.8.8.tgz"
+ },
+ "_from": "ejs@>=0.8.5 <0.9.0",
+ "_npmVersion": "1.4.6",
+ "_npmUser": {
+ "name": "tjholowaychuk",
+ "email": "tj@vision-media.ca"
+ },
+ "maintainers": [
+ {
+ "name": "tjholowaychuk",
+ "email": "tj@vision-media.ca"
+ }
+ ],
+ "directories": {},
+ "_shasum": "ffdc56dcc35d02926dd50ad13439bbc54061d598",
+ "_resolved": "https://registry.npmjs.org/ejs/-/ejs-0.8.8.tgz",
+ "readme": "ERROR: No README data found!"
+}
diff --git a/node_modules/ejs/support/compile.js b/node_modules/ejs/support/compile.js
new file mode 100644
index 0000000..6d3a5eb
--- /dev/null
+++ b/node_modules/ejs/support/compile.js
@@ -0,0 +1,177 @@
+
+/**
+ * Module dependencies.
+ */
+
+var fs = require('fs');
+
+/**
+ * Arguments.
+ */
+
+var args = process.argv.slice(2)
+ , pending = args.length
+ , files = {};
+
+console.log('');
+
+// parse arguments
+
+args.forEach(function(file){
+ var mod = file.replace('lib/', '');
+ fs.readFile(file, 'utf8', function(err, js){
+ if (err) throw err;
+ console.log(' \033[90mcompile : \033[0m\033[36m%s\033[0m', file);
+ files[file] = parse(js);
+ --pending || compile();
+ });
+});
+
+/**
+ * Parse the given `js`.
+ */
+
+function parse(js) {
+ return parseInheritance(parseConditionals(js));
+}
+
+/**
+ * Parse __proto__.
+ */
+
+function parseInheritance(js) {
+ return js
+ .replace(/^ *(\w+)\.prototype\.__proto__ * = *(\w+)\.prototype *;?/gm, function(_, child, parent){
+ return child + '.prototype = new ' + parent + ';\n'
+ + child + '.prototype.constructor = '+ child + ';\n';
+ });
+}
+
+/**
+ * Parse the given `js`, currently supporting:
+ *
+ * 'if' ['node' | 'browser']
+ * 'end'
+ *
+ */
+
+function parseConditionals(js) {
+ var lines = js.split('\n')
+ , len = lines.length
+ , buffer = true
+ , browser = false
+ , buf = []
+ , line
+ , cond;
+
+ for (var i = 0; i < len; ++i) {
+ line = lines[i];
+ if (/^ *\/\/ *if *(node|browser)/gm.exec(line)) {
+ cond = RegExp.$1;
+ buffer = browser = 'browser' == cond;
+ } else if (/^ *\/\/ *end/.test(line)) {
+ buffer = true;
+ browser = false;
+ } else if (browser) {
+ buf.push(line.replace(/^( *)\/\//, '$1'));
+ } else if (buffer) {
+ buf.push(line);
+ }
+ }
+
+ return buf.join('\n');
+}
+
+/**
+ * Compile the files.
+ */
+
+function compile() {
+ var buf = '';
+ buf += 'ejs = (function(){\n';
+ buf += '\n// CommonJS require()\n\n';
+ buf += browser.require + '\n\n';
+ buf += 'require.modules = {};\n\n';
+ buf += 'require.resolve = ' + browser.resolve + ';\n\n';
+ buf += 'require.register = ' + browser.register + ';\n\n';
+ buf += 'require.relative = ' + browser.relative + ';\n\n';
+ args.forEach(function(file){
+ var js = files[file];
+ file = file.replace('lib/', '');
+ buf += '\nrequire.register("' + file + '", function(module, exports, require){\n';
+ buf += js;
+ buf += '\n}); // module: ' + file + '\n';
+ });
+ buf += '\n return require("ejs");\n})();';
+ fs.writeFile('ejs.js', buf, function(err){
+ if (err) throw err;
+ console.log(' \033[90m create : \033[0m\033[36m%s\033[0m', 'ejs.js');
+ console.log();
+ });
+}
+
+// refactored version of weepy's
+// https://github.com/weepy/brequire/blob/master/browser/brequire.js
+
+var browser = {
+
+ /**
+ * Require a module.
+ */
+
+ require: function require(p){
+ if ('fs' == p) return {};
+ if ('path' == p) return {};
+ 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;
+ },
+
+ /**
+ * Resolve module path.
+ */
+
+ resolve: function(path){
+ var orig = path
+ , reg = path + '.js'
+ , index = path + '/index.js';
+ return require.modules[reg] && reg
+ || require.modules[index] && index
+ || orig;
+ },
+
+ /**
+ * Return relative require().
+ */
+
+ relative: function(parent) {
+ return function(p){
+ if ('.' != p.substr(0, 1)) 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('/'));
+ };
+ },
+
+ /**
+ * Register a module.
+ */
+
+ register: function(path, fn){
+ require.modules[path] = fn;
+ }
+}; \ No newline at end of file
diff --git a/node_modules/ejs/test/ejs.js b/node_modules/ejs/test/ejs.js
new file mode 100644
index 0000000..7df7ace
--- /dev/null
+++ b/node_modules/ejs/test/ejs.js
@@ -0,0 +1,306 @@
+/**
+ * Module dependencies.
+ */
+
+var ejs = require('..')
+ , fs = require('fs')
+ , read = fs.readFileSync
+ , assert = require('should');
+
+/**
+ * Load fixture `name`.
+ */
+
+function fixture(name) {
+ return read('test/fixtures/' + name, 'utf8').replace(/\r/g, '');
+}
+
+/**
+ * User fixtures.
+ */
+
+var users = [];
+users.push({ name: 'tobi' });
+users.push({ name: 'loki' });
+users.push({ name: 'jane' });
+
+describe('ejs.compile(str, options)', function(){
+ it('should compile to a function', function(){
+ var fn = ejs.compile('<p>yay</p>');
+ fn().should.equal('<p>yay</p>');
+ })
+
+ it('should throw if there are syntax errors', function(){
+ try {
+ ejs.compile(fixture('fail.ejs'));
+ } catch (err) {
+ err.message.should.include('compiling ejs');
+
+ try {
+ ejs.compile(fixture('fail.ejs'), { filename: 'fail.ejs' });
+ } catch (err) {
+ err.message.should.include('fail.ejs');
+ return;
+ }
+ }
+
+ assert(false, 'compiling a file with invalid syntax should throw an exception');
+ })
+
+ it('should allow customizing delimiters', function(){
+ var fn = ejs.compile('<p>{= name }</p>', { open: '{', close: '}' });
+ fn({ name: 'tobi' }).should.equal('<p>tobi</p>');
+
+ var fn = ejs.compile('<p>::= name ::</p>', { open: '::', close: '::' });
+ fn({ name: 'tobi' }).should.equal('<p>tobi</p>');
+
+ var fn = ejs.compile('<p>(= name )</p>', { open: '(', close: ')' });
+ fn({ name: 'tobi' }).should.equal('<p>tobi</p>');
+ })
+
+ it('should default to using ejs.open and ejs.close', function(){
+ ejs.open = '{';
+ ejs.close = '}';
+ var fn = ejs.compile('<p>{= name }</p>');
+ fn({ name: 'tobi' }).should.equal('<p>tobi</p>');
+
+ var fn = ejs.compile('<p>|= name |</p>', { open: '|', close: '|' });
+ fn({ name: 'tobi' }).should.equal('<p>tobi</p>');
+ delete ejs.open;
+ delete ejs.close;
+ })
+
+ it('should have a working client option', function(){
+ var fn = ejs.compile('<p><%= foo %></p>', { client: true });
+ var str = fn.toString();
+ eval('var preFn = ' + str);
+ preFn({ foo: 'bar' }).should.equal('<p>bar</p>');
+ })
+})
+
+describe('ejs.render(str, options)', function(){
+ it('should render the template', function(){
+ ejs.render('<p>yay</p>')
+ .should.equal('<p>yay</p>');
+ })
+
+ it('should accept locals', function(){
+ ejs.render('<p><%= name %></p>', { name: 'tobi' })
+ .should.equal('<p>tobi</p>');
+ })
+})
+
+describe('ejs.renderFile(path, options, fn)', function(){
+ it('should render a file', function(done){
+ ejs.renderFile('test/fixtures/para.ejs', function(err, html){
+ if (err) return done(err);
+ html.should.equal('<p>hey</p>');
+ done();
+ });
+ })
+
+ it('should accept locals', function(done){
+ var options = { name: 'tj', open: '{', close: '}' };
+ ejs.renderFile('test/fixtures/user.ejs', options, function(err, html){
+ if (err) return done(err);
+ html.should.equal('<h1>tj</h1>');
+ done();
+ });
+ })
+
+ it('should not catch err threw by callback', function(done){
+ var options = { name: 'tj', open: '{', close: '}' };
+ var counter = 0;
+ try {
+ ejs.renderFile('test/fixtures/user.ejs', options, function(err, html){
+ counter++;
+ if (err) {
+ err.message.should.not.equal('Exception in callback');
+ return done(err);
+ }
+ throw new Error('Exception in callback');
+ });
+ } catch (err) {
+ counter.should.equal(1);
+ err.message.should.equal('Exception in callback');
+ done();
+ }
+ })
+})
+
+describe('<%=', function(){
+ it('should escape <script>', function(){
+ ejs.render('<%= name %>', { name: '<script>' })
+ .should.equal('&lt;script&gt;');
+ })
+ it("should escape '", function(){
+ ejs.render('<%= name %>', { name: "The Jones's" })
+ .should.equal('The Jones&#39;s');
+ })
+ it("shouldn't escape &amp;", function(){
+ ejs.render('<%= name %>', { name: "Us &amp; Them" })
+ .should.equal('Us &amp; Them');
+ })
+ it("shouldn't escape &#93;", function(){
+ ejs.render('<%= name %>', { name: "The Jones&#39;s" })
+ .should.equal('The Jones&#39;s');
+ })
+ it("should escape &foo_bar;", function(){
+ ejs.render('<%= name %>', { name: "&foo_bar;" })
+ .should.equal('&amp;foo_bar;');
+ })
+})
+
+describe('<%-', function(){
+ it('should not escape', function(){
+ ejs.render('<%- name %>', { name: '<script>' })
+ .should.equal('<script>');
+ })
+})
+
+describe('%>', function(){
+ it('should produce newlines', function(){
+ ejs.render(fixture('newlines.ejs'), { users: users })
+ .should.equal(fixture('newlines.html'));
+ })
+})
+
+describe('-%>', function(){
+ it('should not produce newlines', function(){
+ ejs.render(fixture('no.newlines.ejs'), { users: users })
+ .should.equal(fixture('no.newlines.html'));
+ })
+})
+
+describe('single quotes', function(){
+ it('should not mess up the constructed function', function(){
+ ejs.render(fixture('single-quote.ejs'))
+ .should.equal(fixture('single-quote.html'));
+ })
+})
+
+describe('double quotes', function(){
+ it('should not mess up the constructed function', function(){
+ ejs.render(fixture('double-quote.ejs'))
+ .should.equal(fixture('double-quote.html'));
+ })
+})
+
+describe('backslashes', function(){
+ it('should escape', function(){
+ ejs.render(fixture('backslash.ejs'))
+ .should.equal(fixture('backslash.html'));
+ })
+})
+
+describe('messed up whitespace', function(){
+ it('should work', function(){
+ ejs.render(fixture('messed.ejs'), { users: users })
+ .should.equal(fixture('messed.html'));
+ })
+})
+
+describe('filters', function(){
+ it('should work', function(){
+ var items = ['foo', 'bar', 'baz'];
+ ejs.render('<%=: items | reverse | first | reverse | capitalize %>', { items: items })
+ .should.equal('Zab');
+ })
+
+ it('should accept arguments', function(){
+ ejs.render('<%=: users | map:"name" | join:", " %>', { users: users })
+ .should.equal('tobi, loki, jane');
+ })
+
+ it('should truncate string', function(){
+ ejs.render('<%=: word | truncate: 3 %>', { word: 'World' })
+ .should.equal('Wor');
+ })
+
+ it('should append string if string is longer', function(){
+ ejs.render('<%=: word | truncate: 2,"..." %>', { word: 'Testing' })
+ .should.equal('Te...');
+ })
+
+ it('should not append string if string is shorter', function(){
+ ejs.render('<%=: word | truncate: 10,"..." %>', { word: 'Testing' })
+ .should.equal('Testing');
+ })
+
+ it('should accept arguments containing :', function(){
+ ejs.render('<%=: users | map:"name" | join:"::" %>', { users: users })
+ .should.equal('tobi::loki::jane');
+ })
+})
+
+describe('exceptions', function(){
+ it('should produce useful stack traces', function(done){
+ try {
+ ejs.render(fixture('error.ejs'), { filename: 'error.ejs' });
+ } catch (err) {
+ err.path.should.equal('error.ejs');
+ err.stack.split('\n').slice(0, 8).join('\n').should.equal(fixture('error.out'));
+ done();
+ }
+ })
+
+ it('should not include __stack if compileDebug is false', function() {
+ try {
+ ejs.render(fixture('error.ejs'), {
+ filename: 'error.ejs',
+ compileDebug: false
+ });
+ } catch (err) {
+ err.should.not.have.property('path');
+ err.stack.split('\n').slice(0, 8).join('\n').should.not.equal(fixture('error.out'));
+ }
+ });
+})
+
+describe('includes', function(){
+ it('should include ejs', function(){
+ var file = 'test/fixtures/include.ejs';
+ ejs.render(fixture('include.ejs'), { filename: file, pets: users, open: '[[', close: ']]' })
+ .should.equal(fixture('include.html'));
+ })
+
+ it('should work when nested', function(){
+ var file = 'test/fixtures/menu.ejs';
+ ejs.render(fixture('menu.ejs'), { filename: file, pets: users })
+ .should.equal(fixture('menu.html'));
+ })
+
+ it('should include arbitrary files as-is', function(){
+ var file = 'test/fixtures/include.css.ejs';
+ ejs.render(fixture('include.css.ejs'), { filename: file, pets: users })
+ .should.equal(fixture('include.css.html'));
+ })
+
+ it('should pass compileDebug to include', function(){
+ var file = 'test/fixtures/include.ejs';
+ var fn = ejs.compile(fixture('include.ejs'), { filename: file, open: '[[', close: ']]', compileDebug: false, client: true })
+ var str = fn.toString();
+ eval('var preFn = ' + str);
+ str.should.not.match(/__stack/);
+ (function() {
+ preFn({ pets: users });
+ }).should.not.throw();
+ })
+})
+
+describe('comments', function() {
+ it('should fully render with comments removed', function() {
+ ejs.render(fixture('comments.ejs'))
+ .should.equal(fixture('comments.html'));
+ })
+})
+
+
+describe('require', function() {
+ it('should allow ejs templates to be required as node modules', function() {
+ var file = 'test/fixtures/include.ejs'
+ , template = require(__dirname + '/fixtures/menu.ejs');
+ template({ filename: file, pets: users })
+ .should.equal(fixture('menu.html'));
+ })
+})
diff --git a/node_modules/ejs/test/fixtures/backslash.ejs b/node_modules/ejs/test/fixtures/backslash.ejs
new file mode 100644
index 0000000..eeb4a48
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/backslash.ejs
@@ -0,0 +1 @@
+\foo \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/backslash.html b/node_modules/ejs/test/fixtures/backslash.html
new file mode 100644
index 0000000..eeb4a48
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/backslash.html
@@ -0,0 +1 @@
+\foo \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/comments.ejs b/node_modules/ejs/test/fixtures/comments.ejs
new file mode 100644
index 0000000..ba34b0a
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/comments.ejs
@@ -0,0 +1,5 @@
+<li><a href="foo"><% // double-slash comment %>foo</li>
+<li><a href="bar"><% /* C-style comment */ %>bar</li>
+<li><a href="baz"><% // double-slash comment with newline
+ %>baz</li>
+<li><a href="qux"><% var x = 'qux'; // double-slash comment @ end of line %><%= x %></li> \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/comments.html b/node_modules/ejs/test/fixtures/comments.html
new file mode 100644
index 0000000..f728923
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/comments.html
@@ -0,0 +1,4 @@
+<li><a href="foo">foo</li>
+<li><a href="bar">bar</li>
+<li><a href="baz">baz</li>
+<li><a href="qux">qux</li> \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/double-quote.ejs b/node_modules/ejs/test/fixtures/double-quote.ejs
new file mode 100644
index 0000000..3bccdcf
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/double-quote.ejs
@@ -0,0 +1 @@
+<p><%= "lo" + 'ki' %>'s "wheelchair"</p> \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/double-quote.html b/node_modules/ejs/test/fixtures/double-quote.html
new file mode 100644
index 0000000..6473979
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/double-quote.html
@@ -0,0 +1 @@
+<p>loki's "wheelchair"</p> \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/error.ejs b/node_modules/ejs/test/fixtures/error.ejs
new file mode 100644
index 0000000..f032730
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/error.ejs
@@ -0,0 +1,5 @@
+<ul>
+ <% if (users) { %>
+ <p>Has users</p>
+ <% } %>
+</ul> \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/error.out b/node_modules/ejs/test/fixtures/error.out
new file mode 100644
index 0000000..a2c9108
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/error.out
@@ -0,0 +1,8 @@
+ReferenceError: error.ejs:2
+ 1| <ul>
+ >> 2| <% if (users) { %>
+ 3| <p>Has users</p>
+ 4| <% } %>
+ 5| </ul>
+
+users is not defined \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/fail.ejs b/node_modules/ejs/test/fixtures/fail.ejs
new file mode 100644
index 0000000..1a7a0f7
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/fail.ejs
@@ -0,0 +1 @@
+<% function foo() return 'foo'; %> \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/include.css.ejs b/node_modules/ejs/test/fixtures/include.css.ejs
new file mode 100644
index 0000000..f47358b
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/include.css.ejs
@@ -0,0 +1 @@
+<style><% var value = 'bar' %><% include style.css %></style> \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/include.css.html b/node_modules/ejs/test/fixtures/include.css.html
new file mode 100644
index 0000000..43343fe
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/include.css.html
@@ -0,0 +1,3 @@
+<style>body {
+ foo: 'bar';
+}</style> \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/include.ejs b/node_modules/ejs/test/fixtures/include.ejs
new file mode 100644
index 0000000..8017337
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/include.ejs
@@ -0,0 +1,5 @@
+<ul>
+ [[ pets.forEach(function(pet){ ]]
+ [[ include pet ]]
+ [[ }) ]]
+</ul> \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/include.html b/node_modules/ejs/test/fixtures/include.html
new file mode 100644
index 0000000..ca3e298
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/include.html
@@ -0,0 +1,9 @@
+<ul>
+
+ <li>tobi</li>
+
+ <li>loki</li>
+
+ <li>jane</li>
+
+</ul> \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/includes/menu-item.ejs b/node_modules/ejs/test/fixtures/includes/menu-item.ejs
new file mode 100644
index 0000000..37cca5f
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/includes/menu-item.ejs
@@ -0,0 +1 @@
+<li><% include menu/item %></li> \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/includes/menu/item.ejs b/node_modules/ejs/test/fixtures/includes/menu/item.ejs
new file mode 100644
index 0000000..8abc3fe
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/includes/menu/item.ejs
@@ -0,0 +1 @@
+<a href="/<%= url %>"><%= title %></a> \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/menu.ejs b/node_modules/ejs/test/fixtures/menu.ejs
new file mode 100644
index 0000000..61fad41
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/menu.ejs
@@ -0,0 +1,11 @@
+<% var url = '/foo' -%>
+<% var title = 'Foo' -%>
+<% include includes/menu-item -%>
+
+<% var url = '/bar' -%>
+<% var title = 'Bar' -%>
+<% include includes/menu-item -%>
+
+<% var url = '/baz' -%>
+<% var title = 'Baz' -%>
+<% include includes/menu-item -%> \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/menu.html b/node_modules/ejs/test/fixtures/menu.html
new file mode 100644
index 0000000..1f9e45f
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/menu.html
@@ -0,0 +1,3 @@
+<li><a href="//foo">Foo</a></li>
+<li><a href="//bar">Bar</a></li>
+<li><a href="//baz">Baz</a></li> \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/messed.ejs b/node_modules/ejs/test/fixtures/messed.ejs
new file mode 100644
index 0000000..7d69033
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/messed.ejs
@@ -0,0 +1 @@
+<ul><%users.forEach(function(user){%><li><%=user.name%></li><%})%></ul> \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/messed.html b/node_modules/ejs/test/fixtures/messed.html
new file mode 100644
index 0000000..1e49148
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/messed.html
@@ -0,0 +1 @@
+<ul><li>tobi</li><li>loki</li><li>jane</li></ul> \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/newlines.ejs b/node_modules/ejs/test/fixtures/newlines.ejs
new file mode 100644
index 0000000..47401b2
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/newlines.ejs
@@ -0,0 +1,5 @@
+<ul>
+ <% users.forEach(function(user){ %>
+ <li><%= user.name %></li>
+ <% }) %>
+</ul> \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/newlines.html b/node_modules/ejs/test/fixtures/newlines.html
new file mode 100644
index 0000000..ca3e298
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/newlines.html
@@ -0,0 +1,9 @@
+<ul>
+
+ <li>tobi</li>
+
+ <li>loki</li>
+
+ <li>jane</li>
+
+</ul> \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/no.newlines.ejs b/node_modules/ejs/test/fixtures/no.newlines.ejs
new file mode 100644
index 0000000..029b461
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/no.newlines.ejs
@@ -0,0 +1,5 @@
+<ul>
+ <% users.forEach(function(user){ -%>
+ <li><%= user.name %></li>
+ <% }) -%>
+</ul> \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/no.newlines.html b/node_modules/ejs/test/fixtures/no.newlines.html
new file mode 100644
index 0000000..6efee2c
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/no.newlines.html
@@ -0,0 +1,5 @@
+<ul>
+ <li>tobi</li>
+ <li>loki</li>
+ <li>jane</li>
+ </ul> \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/para.ejs b/node_modules/ejs/test/fixtures/para.ejs
new file mode 100644
index 0000000..89da779
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/para.ejs
@@ -0,0 +1 @@
+<p>hey</p> \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/pet.ejs b/node_modules/ejs/test/fixtures/pet.ejs
new file mode 100644
index 0000000..5788558
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/pet.ejs
@@ -0,0 +1 @@
+<li>[[= pet.name ]]</li> \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/single-quote.ejs b/node_modules/ejs/test/fixtures/single-quote.ejs
new file mode 100644
index 0000000..1e35a95
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/single-quote.ejs
@@ -0,0 +1 @@
+<p><%= 'loki' %>'s wheelchair</p> \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/single-quote.html b/node_modules/ejs/test/fixtures/single-quote.html
new file mode 100644
index 0000000..3125173
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/single-quote.html
@@ -0,0 +1 @@
+<p>loki's wheelchair</p> \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/style.css b/node_modules/ejs/test/fixtures/style.css
new file mode 100644
index 0000000..1630b8c
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/style.css
@@ -0,0 +1,3 @@
+body {
+ foo: '<%= value %>';
+} \ No newline at end of file
diff --git a/node_modules/ejs/test/fixtures/user.ejs b/node_modules/ejs/test/fixtures/user.ejs
new file mode 100644
index 0000000..b312b5d
--- /dev/null
+++ b/node_modules/ejs/test/fixtures/user.ejs
@@ -0,0 +1 @@
+<h1>{= name}</h1> \ No newline at end of file