Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Teino1978-Corp/f6250a6f2a66280ad3f2 to your computer and use it in GitHub Desktop.
Save Teino1978-Corp/f6250a6f2a66280ad3f2 to your computer and use it in GitHub Desktop.
This gist exceeds the recommended number of files (~10). To access all files, please clone this gist.
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
</project>
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" />
</project>
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/MobileMicToPC.iml" filepath="$PROJECT_DIR$/.idea/MobileMicToPC.iml" />
</modules>
</component>
</project>
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="app.js" type="NodeJSConfigurationType" factoryName="Node.js" path-to-node="/usr/local/bin/node" path-to-js-file="app.js" working-dir="$PROJECT_DIR$">
<browser start="false" url="http://localhost:3000" with-js-debugger="false" />
<RunnerSettings RunnerId="NodeJS.run" />
<ConfigurationWrapper RunnerId="NodeJS.run" />
<method />
</configuration>
</component>
<component name="DependencyValidationManager">
<state>
<option name="SKIP_IMPORT_STATEMENTS" value="false" />
</state>
</component>
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="" />
</component>
</project>
/**
* Module dependencies.
*/
var express = require('express')
, routes = require('./routes')
, user = require('./routes/user')
, http = require('http')
, path = require('path');
var app = express();
app.configure(function () {
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser('your secret here'));
app.use(express.session());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
});
app.configure('development', function () {
app.use(express.errorHandler());
});
app.get('/', routes.index);
app.get('/users', user.list);
app.post('/submitData', function (req, res) {
console.log(req.body.data);
var d = req.body.data;
var s = require('net').Socket();
s.connect(4321);
s.write(d);
s.end();
res.jsonp('success');
})
http.createServer(app).listen(app.get('port'), function () {
console.log("Express server listening on port " + app.get('port'));
});
#!/usr/bin/env node
/**
* Module dependencies.
*/
var exec = require('child_process').exec
, program = require('commander')
, mkdirp = require('mkdirp')
, pkg = require('../package.json')
, version = pkg.version
, os = require('os')
, fs = require('fs');
// CLI
program
.version(version)
.option('-s, --sessions', 'add session support')
.option('-e, --ejs', 'add ejs engine support (defaults to jade)')
.option('-J, --jshtml', 'add jshtml engine support (defaults to jade)')
.option('-H, --hogan', 'add hogan.js engine support')
.option('-c, --css <engine>', 'add stylesheet <engine> support (less|stylus) (defaults to plain css)')
.option('-f, --force', 'force on non-empty directory')
.parse(process.argv);
// Path
var path = program.args.shift() || '.';
// end-of-line code
var eol = 'win32' == os.platform() ? '\r\n' : '\n'
// Template engine
program.template = 'jade';
if (program.ejs) program.template = 'ejs';
if (program.jshtml) program.template = 'jshtml';
if (program.hogan) program.template = 'hjs';
/**
* Routes index template.
*/
var index = [
''
, '/*'
, ' * GET home page.'
, ' */'
, ''
, 'exports.index = function(req, res){'
, ' res.render(\'index\', { title: \'Express\' });'
, '};'
].join(eol);
/**
* Routes users template.
*/
var users = [
''
, '/*'
, ' * GET users listing.'
, ' */'
, ''
, 'exports.list = function(req, res){'
, ' res.send("respond with a resource");'
, '};'
].join(eol);
/**
* Jade layout template.
*/
var jadeLayout = [
'doctype 5'
, 'html'
, ' head'
, ' title= title'
, ' link(rel=\'stylesheet\', href=\'/stylesheets/style.css\')'
, ' body'
, ' block content'
].join(eol);
/**
* Jade index template.
*/
var jadeIndex = [
'extends layout'
, ''
, 'block content'
, ' h1= title'
, ' p Welcome to #{title}'
].join(eol);
/**
* EJS index template.
*/
var ejsIndex = [
'<!DOCTYPE html>'
, '<html>'
, ' <head>'
, ' <title><%= title %></title>'
, ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
, ' </head>'
, ' <body>'
, ' <h1><%= title %></h1>'
, ' <p>Welcome to <%= title %></p>'
, ' </body>'
, '</html>'
].join(eol);
/**
* JSHTML layout template.
*/
var jshtmlLayout = [
'<!DOCTYPE html>'
, '<html>'
, ' <head>'
, ' <title> @write(title) </title>'
, ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
, ' </head>'
, ' <body>'
, ' @write(body)'
, ' </body>'
, '</html>'
].join(eol);
/**
* JSHTML index template.
*/
var jshtmlIndex = [
'<h1>@write(title)</h1>'
, '<p>Welcome to @write(title)</p>'
].join(eol);
/**
* Hogan.js index template.
*/
var hoganIndex = [
'<!DOCTYPE html>'
, '<html>'
, ' <head>'
, ' <title>{{ title }}</title>'
, ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
, ' </head>'
, ' <body>'
, ' <h1>{{ title }}</h1>'
, ' <p>Welcome to {{ title }}</p>'
, ' </body>'
, '</html>'
].join(eol);
/**
* Default css template.
*/
var css = [
'body {'
, ' padding: 50px;'
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;'
, '}'
, ''
, 'a {'
, ' color: #00B7FF;'
, '}'
].join(eol);
/**
* Default less template.
*/
var less = [
'body {'
, ' padding: 50px;'
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;'
, '}'
, ''
, 'a {'
, ' color: #00B7FF;'
, '}'
].join(eol);
/**
* Default stylus template.
*/
var stylus = [
'body'
, ' padding: 50px'
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif'
, 'a'
, ' color: #00B7FF'
].join(eol);
/**
* App template.
*/
var app = [
''
, '/**'
, ' * Module dependencies.'
, ' */'
, ''
, 'var express = require(\'express\')'
, ' , routes = require(\'./routes\')'
, ' , user = require(\'./routes/user\')'
, ' , http = require(\'http\')'
, ' , path = require(\'path\');'
, ''
, 'var app = express();'
, ''
, 'app.configure(function(){'
, ' app.set(\'port\', process.env.PORT || 3000);'
, ' app.set(\'views\', __dirname + \'/views\');'
, ' app.set(\'view engine\', \':TEMPLATE\');'
, ' app.use(express.favicon());'
, ' app.use(express.logger(\'dev\'));'
, ' app.use(express.bodyParser());'
, ' app.use(express.methodOverride());{sess}'
, ' app.use(app.router);{css}'
, ' app.use(express.static(path.join(__dirname, \'public\')));'
, '});'
, ''
, 'app.configure(\'development\', function(){'
, ' app.use(express.errorHandler());'
, '});'
, ''
, 'app.get(\'/\', routes.index);'
, 'app.get(\'/users\', user.list);'
, ''
, 'http.createServer(app).listen(app.get(\'port\'), function(){'
, ' console.log("Express server listening on port " + app.get(\'port\'));'
, '});'
, ''
].join(eol);
// Generate application
(function createApplication(path) {
emptyDirectory(path, function(empty){
if (empty || program.force) {
createApplicationAt(path);
} else {
program.confirm('destination is not empty, continue? ', function(ok){
if (ok) {
process.stdin.destroy();
createApplicationAt(path);
} else {
abort('aborting');
}
});
}
});
})(path);
/**
* Create application at the given directory `path`.
*
* @param {String} path
*/
function createApplicationAt(path) {
console.log();
process.on('exit', function(){
console.log();
console.log(' install dependencies:');
console.log(' $ cd %s && npm install', path);
console.log();
console.log(' run the app:');
console.log(' $ node app');
console.log();
});
mkdir(path, function(){
mkdir(path + '/public');
mkdir(path + '/public/javascripts');
mkdir(path + '/public/images');
mkdir(path + '/public/stylesheets', function(){
switch (program.css) {
case 'less':
write(path + '/public/stylesheets/style.less', less);
break;
case 'stylus':
write(path + '/public/stylesheets/style.styl', stylus);
break;
default:
write(path + '/public/stylesheets/style.css', css);
}
});
mkdir(path + '/routes', function(){
write(path + '/routes/index.js', index);
write(path + '/routes/user.js', users);
});
mkdir(path + '/views', function(){
switch (program.template) {
case 'ejs':
write(path + '/views/index.ejs', ejsIndex);
break;
case 'jade':
write(path + '/views/layout.jade', jadeLayout);
write(path + '/views/index.jade', jadeIndex);
break;
case 'jshtml':
write(path + '/views/layout.jshtml', jshtmlLayout);
write(path + '/views/index.jshtml', jshtmlIndex);
break;
case 'hjs':
write(path + '/views/index.hjs', hoganIndex);
break;
}
});
// CSS Engine support
switch (program.css) {
case 'less':
app = app.replace('{css}', eol + ' app.use(require(\'less-middleware\')({ src: __dirname + \'/public\' }));');
break;
case 'stylus':
app = app.replace('{css}', eol + ' app.use(require(\'stylus\').middleware(__dirname + \'/public\'));');
break;
default:
app = app.replace('{css}', '');
}
// Session support
app = app.replace('{sess}', program.sessions
? eol + ' app.use(express.cookieParser(\'your secret here\'));' + eol + ' app.use(express.session());'
: '');
// Template support
app = app.replace(':TEMPLATE', program.template);
// package.json
var pkg = {
name: 'application-name'
, version: '0.0.1'
, private: true
, scripts: { start: 'node app' }
, dependencies: {
express: version
}
}
if (program.template) pkg.dependencies[program.template] = '*';
// CSS Engine support
switch (program.css) {
case 'less':
pkg.dependencies['less-middleware'] = '*';
break;
default:
if (program.css) {
pkg.dependencies[program.css] = '*';
}
}
write(path + '/package.json', JSON.stringify(pkg, null, 2));
write(path + '/app.js', app);
});
}
/**
* Check if the given directory `path` is empty.
*
* @param {String} path
* @param {Function} fn
*/
function emptyDirectory(path, fn) {
fs.readdir(path, function(err, files){
if (err && 'ENOENT' != err.code) throw err;
fn(!files || !files.length);
});
}
/**
* echo str > path.
*
* @param {String} path
* @param {String} str
*/
function write(path, str) {
fs.writeFile(path, str);
console.log(' \x1b[36mcreate\x1b[0m : ' + path);
}
/**
* Mkdir -p.
*
* @param {String} path
* @param {Function} fn
*/
function mkdir(path, fn) {
mkdirp(path, 0755, function(err){
if (err) throw err;
console.log(' \033[36mcreate\033[0m : ' + path);
fn && fn();
});
}
/**
* Exit with the given `str`.
*
* @param {String} str
*/
function abort(str) {
console.error(str);
process.exit(1);
}
# ignore any vim files:
*.sw[a-z]
vim/.netrwhist
node_modules
language: node_js
node_js:
- 0.11
- 0.10
- 0.9
- 0.6
- 0.8
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');
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 <[email protected]>
* 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);
if (end < 0){
throw new Error('Could not find matching close tag "' + close + '".');
}
var 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 <[email protected]>
* 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 <[email protected]>
* MIT Licensed
*/
/**
* Escape the given string of `html`.
*
* @param {String} html
* @return {String}
* @api private
*/
exports.escape = function(html){
return String(html)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/'/g, '&#39;')
.replace(/"/g, '&quot;');
};
}); // module: utils.js
return require("ejs");
})();
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);if(end<0){throw new Error('Could not find matching close tag "'+close+'".')}var 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(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/'/g,"&#39;").replace(/"/g,"&quot;")}});return require("ejs")}();
<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>
<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>
/**
* 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);
<% if (names.length) { %>
<ul>
<% names.forEach(function(name){ %>
<li foo='<%= name + "'" %>'><%= name %></li>
<% }) %>
</ul>
<% } %>
/**
* 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);

1.0.0 / 2014-03-24

  • change: escape & even if it looks like an HTML entity. Don't try to prevent double-escaping.

0.8.6 / 2014-03-21

  • fix: Escape & even if it looks like an HTML entity. Don't try to prevent double-escaping.

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
module.exports = require('./lib/ejs');
/*!
* EJS
* Copyright(c) 2012 TJ Holowaychuk <[email protected]>
* 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);
if (end < 0){
throw new Error('Could not find matching close tag "' + close + '".');
}
var 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, {});
});
}
/*!
* EJS - Filters
* Copyright(c) 2010 TJ Holowaychuk <[email protected]>
* 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);
};
/*!
* EJS
* Copyright(c) 2010 TJ Holowaychuk <[email protected]>
* MIT Licensed
*/
/**
* Escape the given string of `html`.
*
* @param {String} html
* @return {String}
* @api private
*/
exports.escape = function(html){
return String(html)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/'/g, '&#39;')
.replace(/"/g, '&quot;');
};
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
{
"name": "ejs",
"description": "Embedded JavaScript templates",
"version": "1.0.0",
"author": {
"name": "TJ Holowaychuk",
"email": "[email protected]"
},
"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"
},
"readme": "# EJS\n\nEmbedded JavaScript templates.\n\n[![Build Status](https://travis-ci.org/visionmedia/ejs.png)](https://travis-ci.org/visionmedia/ejs)\n\n## Installation\n\n $ npm install ejs\n\n## Features\n\n * Complies with the [Express](http://expressjs.com) view system\n * Static caching of intermediate JavaScript\n * Unbuffered code for conditionals etc `<% code %>`\n * Escapes html by default with `<%= code %>`\n * Unescaped buffering with `<%- code %>`\n * Supports tag customization\n * Filter support for designer-friendly templates\n * Includes\n * Client-side support\n * Newline slurping with `<% code -%>` or `<% -%>` or `<%= code -%>` or `<%- code -%>`\n\n## Example\n\n <% if (user) { %>\n\t <h2><%= user.name %></h2>\n <% } %>\n \n## Try out a live example now\n\n<a href=\"https://runnable.com/ejs\" target=\"_blank\"><img src=\"https://runnable.com/external/styles/assets/runnablebtn.png\" style=\"width:67px;height:25px;\"></a>\n\n## Usage\n\n ejs.compile(str, options);\n // => Function\n\n ejs.render(str, options);\n // => str\n\n## Options\n\n - `cache` Compiled functions are cached, requires `filename`\n - `filename` Used by `cache` to key caches\n - `scope` Function execution context\n - `debug` Output generated function body\n - `compileDebug` When `false` no debug instrumentation is compiled\n - `client` Returns standalone compiled function\n - `open` Open tag, defaulting to \"<%\"\n - `close` Closing tag, defaulting to \"%>\"\n - * All others are template-local variables\n\n## Includes\n\n Includes are relative to the template with the `include` statement,\n for example if you have \"./views/users.ejs\" and \"./views/user/show.ejs\"\n you would use `<% include user/show %>`. The included file(s) are literally\n included into the template, _no_ IO is performed after compilation, thus\n local variables are available to these included templates.\n\n```\n<ul>\n <% users.forEach(function(user){ %>\n <% include user/show %>\n <% }) %>\n</ul>\n```\n\n## Custom delimiters\n\nCustom delimiters can also be applied globally:\n\n var ejs = require('ejs');\n ejs.open = '{{';\n ejs.close = '}}';\n\nWhich would make the following a valid template:\n\n <h1>{{= title }}</h1>\n\n## Filters\n\nEJS conditionally supports the concept of \"filters\". A \"filter chain\"\nis a designer friendly api for manipulating data, without writing JavaScript.\n\nFilters 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:\n\nTemplate:\n\n <p><%=: users | map:'name' | join %></p>\n\nOutput:\n\n <p>Tj, Mape, Guillermo</p>\n\nRender call:\n\n ejs.render(str, {\n users: [\n { name: 'tj' },\n { name: 'mape' },\n { name: 'guillermo' }\n ]\n });\n\nOr perhaps capitalize the first user's name for display:\n\n <p><%=: users | first | capitalize %></p>\n\n## Filter list\n\nCurrently these filters are available:\n\n - first\n - last\n - capitalize\n - downcase\n - upcase\n - sort\n - sort_by:'prop'\n - size\n - length\n - plus:n\n - minus:n\n - times:n\n - divided_by:n\n - join:'val'\n - truncate:n\n - truncate_words:n\n - replace:pattern,substitution\n - prepend:val\n - append:val\n - map:'prop'\n - reverse\n - get:'prop'\n\n## Adding filters\n\n To add a filter simply add a method to the `.filters` object:\n \n```js\nejs.filters.last = function(obj) {\n return obj[obj.length - 1];\n};\n```\n\n## Layouts\n\n Currently EJS has no notion of blocks, only compile-time `include`s,\n however you may still utilize this feature to implement \"layouts\" by\n simply including a header and footer like so:\n\n```html\n<% include head %>\n<h1>Title</h1>\n<p>My page</p>\n<% include foot %>\n```\n\n## client-side support\n\n include `./ejs.js` or `./ejs.min.js` and `require(\"ejs\").compile(str)`.\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2009-2010 TJ Holowaychuk &lt;[email protected]&gt;\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n",
"readmeFilename": "Readme.md",
"_id": "[email protected]",
"_from": "ejs@*"
}

EJS

Embedded JavaScript templates.

Build Status

Installation

$ npm install ejs

Features

  • Complies with the Express 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

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:

ejs.filters.last = function(obj) {
  return obj[obj.length - 1];
};

Layouts

Currently EJS has no notion of blocks, only compile-time includes, however you may still utilize this feature to implement "layouts" by simply including a header and footer like so:

<% 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 <[email protected]>

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.

/**
* 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;
}
};
/**
* 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 &amp;<script>', function(){
ejs.render('<%= name %>', { name: '&nbsp;<script>' })
.should.equal('&amp;nbsp;&lt;script&gt;');
})
it("should escape '", function(){
ejs.render('<%= name %>', { name: "The Jones'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>');
})
it('should terminate gracefully if no close tag is found', function(){
try {
ejs.compile('<h1>oops</h1><%- name ->')
throw new Error('Expected parse failure');
} catch (err) {
err.message.should.equal('Could not find matching close tag "%>".');
}
})
})
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'));
})
})
<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>
<li><a href="foo">foo</li>
<li><a href="bar">bar</li>
<li><a href="baz">baz</li>
<li><a href="qux">qux</li>
<ul>
<% if (users) { %>
<p>Has users</p>
<% } %>
</ul>
ReferenceError: error.ejs:2
1| <ul>
>> 2| <% if (users) { %>
3| <p>Has users</p>
4| <% } %>
5| </ul>
users is not defined
<style><% var value = 'bar' %><% include style.css %></style>
<ul>
[[ pets.forEach(function(pet){ ]]
[[ include pet ]]
[[ }) ]]
</ul>
<ul>
<li>tobi</li>
<li>loki</li>
<li>jane</li>
</ul>
<% 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 -%>
<li><a href="//foo">Foo</a></li>
<li><a href="//bar">Bar</a></li>
<li><a href="//baz">Baz</a></li>
<ul><%users.forEach(function(user){%><li><%=user.name%></li><%})%></ul>
<ul><li>tobi</li><li>loki</li><li>jane</li></ul>
<ul>
<% users.forEach(function(user){ %>
<li><%= user.name %></li>
<% }) %>
</ul>
<ul>
<li>tobi</li>
<li>loki</li>
<li>jane</li>
</ul>
<ul>
<% users.forEach(function(user){ -%>
<li><%= user.name %></li>
<% }) -%>
</ul>
<ul>
<li>tobi</li>
<li>loki</li>
<li>jane</li>
</ul>
.git*
docs/
examples/
support/
test/
testing.js
.DS_Store
coverage.html
lib-cov
language: node_js
node_js:
- 0.6
- 0.8
#!/usr/bin/env node
/**
* Module dependencies.
*/
var exec = require('child_process').exec
, program = require('commander')
, mkdirp = require('mkdirp')
, pkg = require('../package.json')
, version = pkg.version
, os = require('os')
, fs = require('fs');
// CLI
program
.version(version)
.option('-s, --sessions', 'add session support')
.option('-e, --ejs', 'add ejs engine support (defaults to jade)')
.option('-J, --jshtml', 'add jshtml engine support (defaults to jade)')
.option('-H, --hogan', 'add hogan.js engine support')
.option('-c, --css <engine>', 'add stylesheet <engine> support (less|stylus) (defaults to plain css)')
.option('-f, --force', 'force on non-empty directory')
.parse(process.argv);
// Path
var path = program.args.shift() || '.';
// end-of-line code
var eol = 'win32' == os.platform() ? '\r\n' : '\n'
// Template engine
program.template = 'jade';
if (program.ejs) program.template = 'ejs';
if (program.jshtml) program.template = 'jshtml';
if (program.hogan) program.template = 'hjs';
/**
* Routes index template.
*/
var index = [
''
, '/*'
, ' * GET home page.'
, ' */'
, ''
, 'exports.index = function(req, res){'
, ' res.render(\'index\', { title: \'Express\' });'
, '};'
].join(eol);
/**
* Routes users template.
*/
var users = [
''
, '/*'
, ' * GET users listing.'
, ' */'
, ''
, 'exports.list = function(req, res){'
, ' res.send("respond with a resource");'
, '};'
].join(eol);
/**
* Jade layout template.
*/
var jadeLayout = [
'doctype 5'
, 'html'
, ' head'
, ' title= title'
, ' link(rel=\'stylesheet\', href=\'/stylesheets/style.css\')'
, ' body'
, ' block content'
].join(eol);
/**
* Jade index template.
*/
var jadeIndex = [
'extends layout'
, ''
, 'block content'
, ' h1= title'
, ' p Welcome to #{title}'
].join(eol);
/**
* EJS index template.
*/
var ejsIndex = [
'<!DOCTYPE html>'
, '<html>'
, ' <head>'
, ' <title><%= title %></title>'
, ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
, ' </head>'
, ' <body>'
, ' <h1><%= title %></h1>'
, ' <p>Welcome to <%= title %></p>'
, ' </body>'
, '</html>'
].join(eol);
/**
* JSHTML layout template.
*/
var jshtmlLayout = [
'<!DOCTYPE html>'
, '<html>'
, ' <head>'
, ' <title> @write(title) </title>'
, ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
, ' </head>'
, ' <body>'
, ' @write(body)'
, ' </body>'
, '</html>'
].join(eol);
/**
* JSHTML index template.
*/
var jshtmlIndex = [
'<h1>@write(title)</h1>'
, '<p>Welcome to @write(title)</p>'
].join(eol);
/**
* Hogan.js index template.
*/
var hoganIndex = [
'<!DOCTYPE html>'
, '<html>'
, ' <head>'
, ' <title>{{ title }}</title>'
, ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
, ' </head>'
, ' <body>'
, ' <h1>{{ title }}</h1>'
, ' <p>Welcome to {{ title }}</p>'
, ' </body>'
, '</html>'
].join(eol);
/**
* Default css template.
*/
var css = [
'body {'
, ' padding: 50px;'
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;'
, '}'
, ''
, 'a {'
, ' color: #00B7FF;'
, '}'
].join(eol);
/**
* Default less template.
*/
var less = [
'body {'
, ' padding: 50px;'
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;'
, '}'
, ''
, 'a {'
, ' color: #00B7FF;'
, '}'
].join(eol);
/**
* Default stylus template.
*/
var stylus = [
'body'
, ' padding: 50px'
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif'
, 'a'
, ' color: #00B7FF'
].join(eol);
/**
* App template.
*/
var app = [
''
, '/**'
, ' * Module dependencies.'
, ' */'
, ''
, 'var express = require(\'express\')'
, ' , routes = require(\'./routes\')'
, ' , user = require(\'./routes/user\')'
, ' , http = require(\'http\')'
, ' , path = require(\'path\');'
, ''
, 'var app = express();'
, ''
, 'app.configure(function(){'
, ' app.set(\'port\', process.env.PORT || 3000);'
, ' app.set(\'views\', __dirname + \'/views\');'
, ' app.set(\'view engine\', \':TEMPLATE\');'
, ' app.use(express.favicon());'
, ' app.use(express.logger(\'dev\'));'
, ' app.use(express.bodyParser());'
, ' app.use(express.methodOverride());{sess}'
, ' app.use(app.router);{css}'
, ' app.use(express.static(path.join(__dirname, \'public\')));'
, '});'
, ''
, 'app.configure(\'development\', function(){'
, ' app.use(express.errorHandler());'
, '});'
, ''
, 'app.get(\'/\', routes.index);'
, 'app.get(\'/users\', user.list);'
, ''
, 'http.createServer(app).listen(app.get(\'port\'), function(){'
, ' console.log("Express server listening on port " + app.get(\'port\'));'
, '});'
, ''
].join(eol);
// Generate application
(function createApplication(path) {
emptyDirectory(path, function(empty){
if (empty || program.force) {
createApplicationAt(path);
} else {
program.confirm('destination is not empty, continue? ', function(ok){
if (ok) {
process.stdin.destroy();
createApplicationAt(path);
} else {
abort('aborting');
}
});
}
});
})(path);
/**
* Create application at the given directory `path`.
*
* @param {String} path
*/
function createApplicationAt(path) {
console.log();
process.on('exit', function(){
console.log();
console.log(' install dependencies:');
console.log(' $ cd %s && npm install', path);
console.log();
console.log(' run the app:');
console.log(' $ node app');
console.log();
});
mkdir(path, function(){
mkdir(path + '/public');
mkdir(path + '/public/javascripts');
mkdir(path + '/public/images');
mkdir(path + '/public/stylesheets', function(){
switch (program.css) {
case 'less':
write(path + '/public/stylesheets/style.less', less);
break;
case 'stylus':
write(path + '/public/stylesheets/style.styl', stylus);
break;
default:
write(path + '/public/stylesheets/style.css', css);
}
});
mkdir(path + '/routes', function(){
write(path + '/routes/index.js', index);
write(path + '/routes/user.js', users);
});
mkdir(path + '/views', function(){
switch (program.template) {
case 'ejs':
write(path + '/views/index.ejs', ejsIndex);
break;
case 'jade':
write(path + '/views/layout.jade', jadeLayout);
write(path + '/views/index.jade', jadeIndex);
break;
case 'jshtml':
write(path + '/views/layout.jshtml', jshtmlLayout);
write(path + '/views/index.jshtml', jshtmlIndex);
break;
case 'hjs':
write(path + '/views/index.hjs', hoganIndex);
break;
}
});
// CSS Engine support
switch (program.css) {
case 'less':
app = app.replace('{css}', eol + ' app.use(require(\'less-middleware\')({ src: __dirname + \'/public\' }));');
break;
case 'stylus':
app = app.replace('{css}', eol + ' app.use(require(\'stylus\').middleware(__dirname + \'/public\'));');
break;
default:
app = app.replace('{css}', '');
}
// Session support
app = app.replace('{sess}', program.sessions
? eol + ' app.use(express.cookieParser(\'your secret here\'));' + eol + ' app.use(express.session());'
: '');
// Template support
app = app.replace(':TEMPLATE', program.template);
// package.json
var pkg = {
name: 'application-name'
, version: '0.0.1'
, private: true
, scripts: { start: 'node app' }
, dependencies: {
express: version
}
}
if (program.template) pkg.dependencies[program.template] = '*';
// CSS Engine support
switch (program.css) {
case 'less':
pkg.dependencies['less-middleware'] = '*';
break;
default:
if (program.css) {
pkg.dependencies[program.css] = '*';
}
}
write(path + '/package.json', JSON.stringify(pkg, null, 2));
write(path + '/app.js', app);
});
}
/**
* Check if the given directory `path` is empty.
*
* @param {String} path
* @param {Function} fn
*/
function emptyDirectory(path, fn) {
fs.readdir(path, function(err, files){
if (err && 'ENOENT' != err.code) throw err;
fn(!files || !files.length);
});
}
/**
* echo str > path.
*
* @param {String} path
* @param {String} str
*/
function write(path, str) {
fs.writeFile(path, str);
console.log(' \x1b[36mcreate\x1b[0m : ' + path);
}
/**
* Mkdir -p.
*
* @param {String} path
* @param {Function} fn
*/
function mkdir(path, fn) {
mkdirp(path, 0755, function(err){
if (err) throw err;
console.log(' \033[36mcreate\033[0m : ' + path);
fn && fn();
});
}
/**
* Exit with the given `str`.
*
* @param {String} str
*/
function abort(str) {
console.error(str);
process.exit(1);
}
var http = require('http');
var times = 50;
while (times--) {
var req = http.request({
port: 3000
, method: 'POST'
, headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
});
req.on('response', function(res){
console.log(res.statusCode);
});
var n = 500000;
while (n--) {
req.write('foo=bar&bar=baz&');
}
req.write('foo=bar&bar=baz');
req.end();
}

3.1.0 / 2013-01-25

  • add support for leading "." in "view engine" setting
  • add array support to res.set()
  • add node 0.8.x to travis.yml
  • add "subdomain offset" setting for tweaking req.subdomains
  • add res.location(url) implementing res.redirect()-like setting of Location
  • use app.get() for x-powered-by setting for inheritance
  • fix colons in passwords for req.auth

3.0.6 / 2013-01-04

  • add http verb methods to Router
  • update connect
  • fix mangling of the res.cookie() options object
  • fix jsonp whitespace escape. Closes #1132

3.0.5 / 2012-12-19

  • add throwing when a non-function is passed to a route
  • fix: explicitly remove Transfer-Encoding header from 204 and 304 responses
  • revert "add 'etag' option"

3.0.4 / 2012-12-05

  • add 'etag' option to disable res.send() Etags
  • add escaping of urls in text/plain in res.redirect() for old browsers interpreting as html
  • change crc32 module for a more liberal license
  • update connect

3.0.3 / 2012-11-13

  • update connect
  • update cookie module
  • fix cookie max-age

3.0.2 / 2012-11-08

  • add OPTIONS to cors example. Closes #1398
  • fix route chaining regression. Closes #1397

3.0.1 / 2012-11-01

  • update connect

3.0.0 / 2012-10-23

  • add make clean
  • add "Basic" check to req.auth
  • add req.auth test coverage
  • add cb && cb(payload) to res.jsonp(). Closes #1374
  • add backwards compat for res.redirect() status. Closes #1336
  • add support for res.json() to retain previously defined Content-Types. Closes #1349
  • update connect
  • change res.redirect() to utilize a pathname-relative Location again. Closes #1382
  • remove non-primitive string support for res.send()
  • fix view-locals example. Closes #1370
  • fix route-separation example

3.0.0rc5 / 2012-09-18

  • update connect
  • add redis search example
  • add static-files example
  • add "x-powered-by" setting (app.disable('x-powered-by'))
  • add "application/octet-stream" redirect Accept test case. Closes #1317

3.0.0rc4 / 2012-08-30

  • add res.jsonp(). Closes #1307
  • add "verbose errors" option to error-pages example
  • add another route example to express(1) so people are not so confused
  • add redis online user activity tracking example
  • update connect dep
  • fix etag quoting. Closes #1310
  • fix error-pages 404 status
  • fix jsonp callback char restrictions
  • remove old OPTIONS default response

3.0.0rc3 / 2012-08-13

  • update connect dep
  • fix signed cookies to work with connect.cookieParser() ("s:" prefix was missing) [tnydwrds]
  • fix res.render() clobbering of "locals"

3.0.0rc2 / 2012-08-03

  • add CORS example
  • update connect dep
  • deprecate .createServer() & remove old stale examples
  • fix: escape res.redirect() link
  • fix vhost example

3.0.0rc1 / 2012-07-24

  • add more examples to view-locals
  • add scheme-relative redirects (res.redirect("//foo.com")) support
  • update cookie dep
  • update connect dep
  • update send dep
  • fix express(1) -h flag, use -H for hogan. Closes #1245
  • fix res.sendfile() socket error handling regression

3.0.0beta7 / 2012-07-16

  • update connect dep for send() root normalization regression

3.0.0beta6 / 2012-07-13

  • add err.view property for view errors. Closes #1226
  • add "jsonp callback name" setting
  • add support for "/foo/:bar*" non-greedy matches
  • change res.sendfile() to use send() module
  • change res.send to use "response-send" module
  • remove app.locals.use and res.locals.use, use regular middleware

3.0.0beta5 / 2012-07-03

  • add "make check" support
  • add route-map example
  • add res.json(obj, status) support back for BC
  • add "methods" dep, remove internal methods module
  • update connect dep
  • update auth example to utilize cores pbkdf2
  • updated tests to use "supertest"

3.0.0beta4 / 2012-06-25

  • Added req.auth
  • Added req.range(size)
  • Added res.links(obj)
  • Added res.send(body, status) support back for backwards compat
  • Added .default() support to res.format()
  • Added 2xx / 304 check to req.fresh
  • Revert "Added + support to the router"
  • Fixed res.send() freshness check, respect res.statusCode

3.0.0beta3 / 2012-06-15

  • Added hogan --hjs to express(1) [nullfirm]
  • Added another example to content-negotiation
  • Added fresh dep
  • Changed: res.send() always checks freshness
  • Fixed: expose connects mime module. Cloases #1165

3.0.0beta2 / 2012-06-06

  • Added + support to the router
  • Added req.host
  • Changed req.param() to check route first
  • Update connect dep

3.0.0beta1 / 2012-06-01

  • Added res.format() callback to override default 406 behaviour
  • Fixed res.redirect() 406. Closes #1154

3.0.0alpha5 / 2012-05-30

  • Added req.ip
  • Added { signed: true } option to res.cookie()
  • Removed res.signedCookie()
  • Changed: dont reverse req.ips
  • Fixed "trust proxy" setting check for req.ips

3.0.0alpha4 / 2012-05-09

  • Added: allow [] in jsonp callback. Closes #1128
  • Added PORT env var support in generated template. Closes #1118 [benatkin]
  • Updated: connect 2.2.2

3.0.0alpha3 / 2012-05-04

  • Added public app.routes. Closes #887
  • Added view-locals example
  • Added mvc example
  • Added res.locals.use(). Closes #1120
  • Added conditional-GET support to res.send()
  • Added: coerce res.set() values to strings
  • Changed: moved static() in generated apps below router
  • Changed: res.send() only set ETag when not previously set
  • Changed connect 2.2.1 dep
  • Changed: make test now runs unit / acceptance tests
  • Fixed req/res proto inheritance

3.0.0alpha2 / 2012-04-26

  • Added make benchmark back
  • Added res.send() support for String objects
  • Added client-side data exposing example
  • Added res.header() and req.header() aliases for BC
  • Added express.createServer() for BC
  • Perf: memoize parsed urls
  • Perf: connect 2.2.0 dep
  • Changed: make expressInit() middleware self-aware
  • Fixed: use app.get() for all core settings
  • Fixed redis session example
  • Fixed session example. Closes #1105
  • Fixed generated express dep. Closes #1078

3.0.0alpha1 / 2012-04-15

  • Added app.locals.use(callback)
  • Added app.locals object
  • Added app.locals(obj)
  • Added res.locals object
  • Added res.locals(obj)
  • Added res.format() for content-negotiation
  • Added app.engine()
  • Added res.cookie() JSON cookie support
  • Added "trust proxy" setting
  • Added req.subdomains
  • Added req.protocol
  • Added req.secure
  • Added req.path
  • Added req.ips
  • Added req.fresh
  • Added req.stale
  • Added comma-delmited / array support for req.accepts()
  • Added debug instrumentation
  • Added res.set(obj)
  • Added res.set(field, value)
  • Added res.get(field)
  • Added app.get(setting). Closes #842
  • Added req.acceptsLanguage()
  • Added req.acceptsCharset()
  • Added req.accepted
  • Added req.acceptedLanguages
  • Added req.acceptedCharsets
  • Added "json replacer" setting
  • Added "json spaces" setting
  • Added X-Forwarded-Proto support to res.redirect(). Closes #92
  • Added --less support to express(1)
  • Added express.response prototype
  • Added express.request prototype
  • Added express.application prototype
  • Added app.path()
  • Added app.render()
  • Added res.type() to replace res.contentType()
  • Changed: res.redirect() to add relative support
  • Changed: enable "jsonp callback" by default
  • Changed: renamed "case sensitive routes" to "case sensitive routing"
  • Rewrite of all tests with mocha
  • Removed "root" setting
  • Removed res.redirect('home') support
  • Removed req.notify()
  • Removed app.register()
  • Removed app.redirect()
  • Removed app.is()
  • Removed app.helpers()
  • Removed app.dynamicHelpers()
  • Fixed res.sendfile() with non-GET. Closes #723
  • Fixed express(1) public dir for windows. Closes #866

2.5.9/ 2012-04-02

  • Added support for PURGE request method [pbuyle]
  • Fixed express(1) generated app app.address() before listening [mmalecki]

2.5.8 / 2012-02-08

  • Update mkdirp dep. Closes #991

2.5.7 / 2012-02-06

  • Fixed app.all duplicate DELETE requests [mscdex]

2.5.6 / 2012-01-13

  • Updated hamljs dev dep. Closes #953

2.5.5 / 2012-01-08

  • Fixed: set filename on cached templates [matthewleon]

2.5.4 / 2012-01-02

  • Fixed express(1) eol on 0.4.x. Closes #947

2.5.3 / 2011-12-30

  • Fixed req.is() when a charset is present

2.5.2 / 2011-12-10

  • Fixed: express(1) LF -> CRLF for windows

2.5.1 / 2011-11-17

  • Changed: updated connect to 1.8.x
  • Removed sass.js support from express(1)

2.5.0 / 2011-10-24

  • Added ./routes dir for generated app by default
  • Added npm install reminder to express(1) app gen
  • Added 0.5.x support
  • Removed make test-cov since it wont work with node 0.5.x
  • Fixed express(1) public dir for windows. Closes #866

2.4.7 / 2011-10-05

  • Added mkdirp to express(1). Closes #795
  • Added simple json-config example
  • Added shorthand for the parsed request's pathname via req.path
  • Changed connect dep to 1.7.x to fix npm issue...
  • Fixed res.redirect() HEAD support. [reported by xerox]
  • Fixed req.flash(), only escape args
  • Fixed absolute path checking on windows. Closes #829 [reported by andrewpmckenzie]

2.4.6 / 2011-08-22

  • Fixed multiple param callback regression. Closes #824 [reported by TroyGoode]

2.4.5 / 2011-08-19

  • Added support for routes to handle errors. Closes #809
  • Added app.routes.all(). Closes #803
  • Added "basepath" setting to work in conjunction with reverse proxies etc.
  • Refactored Route to use a single array of callbacks
  • Added support for multiple callbacks for app.param(). Closes #801 Closes #805
  • Changed: removed .call(self) for route callbacks
  • Dependency: qs >= 0.3.1
  • Fixed res.redirect() on windows due to join() usage. Closes #808

2.4.4 / 2011-08-05

  • Fixed res.header() intention of a set, even when undefined
  • Fixed *, value no longer required
  • Fixed res.send(204) support. Closes #771

2.4.3 / 2011-07-14

  • Added docs for status option special-case. Closes #739
  • Fixed options.filename, exposing the view path to template engines

2.4.2. / 2011-07-06

  • Revert "removed jsonp stripping" for XSS

2.4.1 / 2011-07-06

  • Added res.json() JSONP support. Closes #737
  • Added extending-templates example. Closes #730
  • Added "strict routing" setting for trailing slashes
  • Added support for multiple envs in app.configure() calls. Closes #735
  • Changed: res.send() using res.json()
  • Changed: when cookie path === null don't default it
  • Changed; default cookie path to "home" setting. Closes #731
  • Removed pids/logs creation from express(1)

2.4.0 / 2011-06-28

  • Added chainable res.status(code)
  • Added res.json(), an explicit version of res.send(obj)
  • Added simple web-service example

2.3.12 / 2011-06-22

  • #express is now on freenode! come join!
  • Added req.get(field, param)
  • Added links to Japanese documentation, thanks @hideyukisaito!
  • Added; the express(1) generated app outputs the env
  • Added content-negotiation example
  • Dependency: connect >= 1.5.1 < 2.0.0
  • Fixed view layout bug. Closes #720
  • Fixed; ignore body on 304. Closes #701

2.3.11 / 2011-06-04

  • Added npm test
  • Removed generation of dummy test file from express(1)
  • Fixed; express(1) adds express as a dep
  • Fixed; prune on prepublish

2.3.10 / 2011-05-27

  • Added req.route, exposing the current route
  • Added package.json generation support to express(1)
  • Fixed call to app.param() function for optional params. Closes #682

2.3.9 / 2011-05-25

  • Fixed bug-ish with ../' in res.partial()` calls

2.3.8 / 2011-05-24

  • Fixed app.options()

2.3.7 / 2011-05-23

  • Added route Collection, ex: app.get('/user/:id').remove();
  • Added support for app.param(fn) to define param logic
  • Removed app.param() support for callback with return value
  • Removed module.parent check from express(1) generated app. Closes #670
  • Refactored router. Closes #639

2.3.6 / 2011-05-20

  • Changed; using devDependencies instead of git submodules
  • Fixed redis session example
  • Fixed markdown example
  • Fixed view caching, should not be enabled in development

2.3.5 / 2011-05-20

  • Added export .view as alias for .View

2.3.4 / 2011-05-08

  • Added ./examples/say
  • Fixed res.sendfile() bug preventing the transfer of files with spaces

2.3.3 / 2011-05-03

  • Added "case sensitive routes" option.
  • Changed; split methods supported per rfc [slaskis]
  • Fixed route-specific middleware when using the same callback function several times

2.3.2 / 2011-04-27

  • Fixed view hints

2.3.1 / 2011-04-26

  • Added app.match() as app.match.all()
  • Added app.lookup() as app.lookup.all()
  • Added app.remove() for app.remove.all()
  • Added app.remove.VERB()
  • Fixed template caching collision issue. Closes #644
  • Moved router over from connect and started refactor

2.3.0 / 2011-04-25

  • Added options support to res.clearCookie()
  • Added res.helpers() as alias of res.locals()
  • Added; json defaults to UTF-8 with res.send(). Closes #632. [Daniel * Dependency connect >= 1.4.0
  • Changed; auto set Content-Type in res.attachement [Aaron Heckmann]
  • Renamed "cache views" to "view cache". Closes #628
  • Fixed caching of views when using several apps. Closes #637
  • Fixed gotcha invoking app.param() callbacks once per route middleware. Closes #638
  • Fixed partial lookup precedence. Closes #631 Shaw]

2.2.2 / 2011-04-12

  • Added second callback support for res.download() connection errors
  • Fixed filename option passing to template engine

2.2.1 / 2011-04-04

  • Added layout(path) helper to change the layout within a view. Closes #610

  • Fixed partial() collection object support. Previously only anything with .length would work. When .length is present one must still be aware of holes, however now { collection: {foo: 'bar'}} is valid, exposes keyInCollection and keysInCollection.

  • Performance improved with better view caching

  • Removed request and response locals

  • Changed; errorHandler page title is now Express instead of Connect

2.2.0 / 2011-03-30

  • Added app.lookup.VERB(), ex app.lookup.put('/user/:id'). Closes #606
  • Added app.match.VERB(), ex app.match.put('/user/12'). Closes #606
  • Added app.VERB(path) as alias of app.lookup.VERB().
  • Dependency connect >= 1.2.0

2.1.1 / 2011-03-29

  • Added; expose err.view object when failing to locate a view
  • Fixed res.partial() call next(err) when no callback is given [reported by aheckmann]
  • Fixed; res.send(undefined) responds with 204 [aheckmann]

2.1.0 / 2011-03-24

  • Added <root>/_?<name> partial lookup support. Closes #447
  • Added request, response, and app local variables
  • Added settings local variable, containing the app's settings
  • Added req.flash() exception if req.session is not available
  • Added res.send(bool) support (json response)
  • Fixed stylus example for latest version
  • Fixed; wrap try/catch around res.render()

2.0.0 / 2011-03-17

  • Fixed up index view path alternative.
  • Changed; res.locals() without object returns the locals

2.0.0rc3 / 2011-03-17

  • Added res.locals(obj) to compliment res.local(key, val)
  • Added res.partial() callback support
  • Fixed recursive error reporting issue in res.render()

2.0.0rc2 / 2011-03-17

  • Changed; partial() "locals" are now optional
  • Fixed SlowBuffer support. Closes #584 [reported by tyrda01]
  • Fixed .filename view engine option [reported by drudge]
  • Fixed blog example
  • Fixed {req,res}.app reference when mounting [Ben Weaver]

2.0.0rc / 2011-03-14

  • Fixed; expose HTTPSServer constructor
  • Fixed express(1) default test charset. Closes #579 [reported by secoif]
  • Fixed; default charset to utf-8 instead of utf8 for lame IE [reported by NickP]

2.0.0beta3 / 2011-03-09

  • Added support for res.contentType() literal The original res.contentType('.json'), res.contentType('application/json'), and res.contentType('json') will work now.
  • Added res.render() status option support back
  • Added charset option for res.render()
  • Added .charset support (via connect 1.0.4)
  • Added view resolution hints when in development and a lookup fails
  • Added layout lookup support relative to the page view. For example while rendering ./views/user/index.jade if you create ./views/user/layout.jade it will be used in favour of the root layout.
  • Fixed res.redirect(). RFC states absolute url [reported by unlink]
  • Fixed; default res.send() string charset to utf8
  • Removed Partial constructor (not currently used)

2.0.0beta2 / 2011-03-07

  • Added res.render() .locals support back to aid in migration process
  • Fixed flash example

2.0.0beta / 2011-03-03

  • Added HTTPS support
  • Added res.cookie() maxAge support
  • Added req.header() Referrer / Referer special-case, either works
  • Added mount support for res.redirect(), now respects the mount-point
  • Added union() util, taking place of merge(clone()) combo
  • Added stylus support to express(1) generated app
  • Added secret to session middleware used in examples and generated app
  • Added res.local(name, val) for progressive view locals
  • Added default param support to req.param(name, default)
  • Added app.disabled() and app.enabled()
  • Added app.register() support for omitting leading ".", either works
  • Added res.partial(), using the same interface as partial() within a view. Closes #539
  • Added app.param() to map route params to async/sync logic
  • Added; aliased app.helpers() as app.locals(). Closes #481
  • Added extname with no leading "." support to res.contentType()
  • Added cache views setting, defaulting to enabled in "production" env
  • Added index file partial resolution, eg: partial('user') may try views/user/index.jade.
  • Added req.accepts() support for extensions
  • Changed; res.download() and res.sendfile() now utilize Connect's static file server connect.static.send().
  • Changed; replaced connect.utils.mime() with npm mime module
  • Changed; allow req.query to be pre-defined (via middleware or other parent
  • Changed view partial resolution, now relative to parent view
  • Changed view engine signature. no longer engine.render(str, options, callback), now engine.compile(str, options) -> Function, the returned function accepts fn(locals).
  • Fixed req.param() bug returning Array.prototype methods. Closes #552
  • Fixed; using Stream#pipe() instead of sys.pump() in res.sendfile()
  • Fixed; using qs module instead of querystring
  • Fixed; strip unsafe chars from jsonp callbacks
  • Removed "stream threshold" setting

1.0.8 / 2011-03-01

  • Allow req.query to be pre-defined (via middleware or other parent app)
  • "connect": ">= 0.5.0 < 1.0.0". Closes #547
  • Removed the long deprecated EXPRESS_ENV support

1.0.7 / 2011-02-07

  • Fixed render() setting inheritance. Mounted apps would not inherit "view engine"

1.0.6 / 2011-02-07

  • Fixed view engine setting bug when period is in dirname

1.0.5 / 2011-02-05

  • Added secret to generated app session() call

1.0.4 / 2011-02-05

  • Added qs dependency to package.json
  • Fixed namespaced require()s for latest connect support

1.0.3 / 2011-01-13

  • Remove unsafe characters from JSONP callback names [Ryan Grove]

1.0.2 / 2011-01-10

  • Removed nested require, using connect.router

1.0.1 / 2010-12-29

  • Fixed for middleware stacked via createServer() previously the foo middleware passed to createServer(foo) would not have access to Express methods such as res.send() or props like req.query etc.

1.0.0 / 2010-11-16

  • Added; deduce partial object names from the last segment. For example by default partial('forum/post', postObject) will give you the post object, providing a meaningful default.
  • Added http status code string representation to res.redirect() body
  • Added; res.redirect() supporting text/plain and text/html via Accept.
  • Added req.is() to aid in content negotiation
  • Added partial local inheritance [suggested by masylum]. Closes #102 providing access to parent template locals.
  • Added -s, --session[s] flag to express(1) to add session related middleware
  • Added --template flag to express(1) to specify the template engine to use.
  • Added --css flag to express(1) to specify the stylesheet engine to use (or just plain css by default).
  • Added app.all() support [thanks aheckmann]
  • Added partial direct object support. You may now partial('user', user) providing the "user" local, vs previously partial('user', { object: user }).
  • Added route-separation example since many people question ways to do this with CommonJS modules. Also view the blog example for an alternative.
  • Performance; caching view path derived partial object names
  • Fixed partial local inheritance precedence. [reported by Nick Poulden] Closes #454
  • Fixed jsonp support; text/javascript as per mailinglist discussion

1.0.0rc4 / 2010-10-14

  • Added NODE_ENV support, EXPRESS_ENV is deprecated and will be removed in 1.0.0
  • Added route-middleware support (very helpful, see the docs)
  • Added jsonp callback setting to enable/disable jsonp autowrapping [Dav Glass]
  • Added callback query check on response.send to autowrap JSON objects for simple webservice implementations [Dav Glass]
  • Added partial() support for array-like collections. Closes #434
  • Added support for swappable querystring parsers
  • Added session usage docs. Closes #443
  • Added dynamic helper caching. Closes #439 [suggested by maritz]
  • Added authentication example
  • Added basic Range support to res.sendfile() (and res.download() etc)
  • Changed; express(1) generated app using 2 spaces instead of 4
  • Default env to "development" again [aheckmann]
  • Removed context option is no more, use "scope"
  • Fixed; exposing ./support libs to examples so they can run without installs
  • Fixed mvc example

1.0.0rc3 / 2010-09-20

  • Added confirmation for express(1) app generation. Closes #391
  • Added extending of flash formatters via app.flashFormatters
  • Added flash formatter support. Closes #411
  • Added streaming support to res.sendfile() using sys.pump() when >= "stream threshold"
  • Added stream threshold setting for res.sendfile()
  • Added res.send() HEAD support
  • Added res.clearCookie()
  • Added res.cookie()
  • Added res.render() headers option
  • Added res.redirect() response bodies
  • Added res.render() status option support. Closes #425 [thanks aheckmann]
  • Fixed res.sendfile() responding with 403 on malicious path
  • Fixed res.download() bug; when an error occurs remove Content-Disposition
  • Fixed; mounted apps settings now inherit from parent app [aheckmann]
  • Fixed; stripping Content-Length / Content-Type when 204
  • Fixed res.send() 204. Closes #419
  • Fixed multiple Set-Cookie headers via res.header(). Closes #402
  • Fixed bug messing with error handlers when listenFD() is called instead of listen(). [thanks guillermo]

1.0.0rc2 / 2010-08-17

  • Added app.register() for template engine mapping. Closes #390
  • Added res.render() callback support as second argument (no options)
  • Added callback support to res.download()
  • Added callback support for res.sendfile()
  • Added support for middleware access via express.middlewareName() vs connect.middlewareName()
  • Added "partials" setting to docs
  • Added default expresso tests to express(1) generated app. Closes #384
  • Fixed res.sendfile() error handling, defer via next()
  • Fixed res.render() callback when a layout is used [thanks guillermo]
  • Fixed; make install creating ~/.node_libraries when not present
  • Fixed issue preventing error handlers from being defined anywhere. Closes #387

1.0.0rc / 2010-07-28

  • Added mounted hook. Closes #369

  • Added connect dependency to package.json

  • Removed "reload views" setting and support code development env never caches, production always caches.

  • Removed param in route callbacks, signature is now simply (req, res, next), previously (req, res, params, next). Use req.params for path captures, req.query for GET params.

  • Fixed "home" setting

  • Fixed middleware/router precedence issue. Closes #366

  • Fixed; configure() callbacks called immediately. Closes #368

1.0.0beta2 / 2010-07-23

  • Added more examples
  • Added; exporting Server constructor
  • Added Server#helpers() for view locals
  • Added Server#dynamicHelpers() for dynamic view locals. Closes #349
  • Added support for absolute view paths
  • Added; home setting defaults to Server#route for mounted apps. Closes #363
  • Added Guillermo Rauch to the contributor list
  • Added support for "as" for non-collection partials. Closes #341
  • Fixed install.sh, ensuring ~/.node_libraries exists. Closes #362 [thanks jf]
  • Fixed res.render() exceptions, now passed to next() when no callback is given [thanks guillermo]
  • Fixed instanceof Array checks, now Array.isArray()
  • Fixed express(1) expansion of public dirs. Closes #348
  • Fixed middleware precedence. Closes #345
  • Fixed view watcher, now async [thanks aheckmann]

1.0.0beta / 2010-07-15

  • Re-write
    • much faster
    • much lighter
    • Check ExpressJS.com for migration guide and updated docs

0.14.0 / 2010-06-15

  • Utilize relative requires
  • Added Static bufferSize option [aheckmann]
  • Fixed caching of view and partial subdirectories [aheckmann]
  • Fixed mime.type() comments now that ".ext" is not supported
  • Updated haml submodule
  • Updated class submodule
  • Removed bin/express

0.13.0 / 2010-06-01

  • Added node v0.1.97 compatibility
  • Added support for deleting cookies via Request#cookie('key', null)
  • Updated haml submodule
  • Fixed not-found page, now using using charset utf-8
  • Fixed show-exceptions page, now using using charset utf-8
  • Fixed view support due to fs.readFile Buffers
  • Changed; mime.type() no longer accepts ".type" due to node extname() changes

0.12.0 / 2010-05-22

  • Added node v0.1.96 compatibility
  • Added view helpers export which act as additional local variables
  • Updated haml submodule
  • Changed ETag; removed inode, modified time only
  • Fixed LF to CRLF for setting multiple cookies
  • Fixed cookie complation; values are now urlencoded
  • Fixed cookies parsing; accepts quoted values and url escaped cookies

0.11.0 / 2010-05-06

  • Added support for layouts using different engines
    • this.render('page.html.haml', { layout: 'super-cool-layout.html.ejs' })
    • this.render('page.html.haml', { layout: 'foo' }) // assumes 'foo.html.haml'
    • this.render('page.html.haml', { layout: false }) // no layout
  • Updated ext submodule
  • Updated haml submodule
  • Fixed EJS partial support by passing along the context. Issue #307

0.10.1 / 2010-05-03

  • Fixed binary uploads.

0.10.0 / 2010-04-30

  • Added charset support via Request#charset (automatically assigned to 'UTF-8' when respond()'s encoding is set to 'utf8' or 'utf-8'.
  • Added "encoding" option to Request#render(). Closes #299
  • Added "dump exceptions" setting, which is enabled by default.
  • Added simple ejs template engine support
  • Added error reponse support for text/plain, application/json. Closes #297
  • Added callback function param to Request#error()
  • Added Request#sendHead()
  • Added Request#stream()
  • Added support for Request#respond(304, null) for empty response bodies
  • Added ETag support to Request#sendfile()
  • Added options to Request#sendfile(), passed to fs.createReadStream()
  • Added filename arg to Request#download()
  • Performance enhanced due to pre-reversing plugins so that plugins.reverse() is not called on each request
  • Performance enhanced by preventing several calls to toLowerCase() in Router#match()
  • Changed; Request#sendfile() now streams
  • Changed; Renamed Request#halt() to Request#respond(). Closes #289
  • Changed; Using sys.inspect() instead of JSON.encode() for error output
  • Changed; run() returns the http.Server instance. Closes #298
  • Changed; Defaulting Server#host to null (INADDR_ANY)
  • Changed; Logger "common" format scale of 0.4f
  • Removed Logger "request" format
  • Fixed; Catching ENOENT in view caching, preventing error when "views/partials" is not found
  • Fixed several issues with http client
  • Fixed Logger Content-Length output
  • Fixed bug preventing Opera from retaining the generated session id. Closes #292

0.9.0 / 2010-04-14

  • Added DSL level error() route support
  • Added DSL level notFound() route support
  • Added Request#error()
  • Added Request#notFound()
  • Added Request#render() callback function. Closes #258
  • Added "max upload size" setting
  • Added "magic" variables to collection partials (__index__, __length__, __isFirst__, __isLast__). Closes #254
  • Added haml.js submodule; removed haml-js
  • Added callback function support to Request#halt() as 3rd/4th arg
  • Added preprocessing of route param wildcards using param(). Closes #251
  • Added view partial support (with collections etc)
  • Fixed bug preventing falsey params (such as ?page=0). Closes #286
  • Fixed setting of multiple cookies. Closes #199
  • Changed; view naming convention is now NAME.TYPE.ENGINE (for example page.html.haml)
  • Changed; session cookie is now httpOnly
  • Changed; Request is no longer global
  • Changed; Event is no longer global
  • Changed; "sys" module is no longer global
  • Changed; moved Request#download to Static plugin where it belongs
  • Changed; Request instance created before body parsing. Closes #262
  • Changed; Pre-caching views in memory when "cache view contents" is enabled. Closes #253
  • Changed; Pre-caching view partials in memory when "cache view partials" is enabled
  • Updated support to node --version 0.1.90
  • Updated dependencies
  • Removed set("session cookie") in favour of use(Session, { cookie: { ... }})
  • Removed utils.mixin(); use Object#mergeDeep()

0.8.0 / 2010-03-19

  • Added coffeescript example app. Closes #242
  • Changed; cache api now async friendly. Closes #240
  • Removed deprecated 'express/static' support. Use 'express/plugins/static'

0.7.6 / 2010-03-19

  • Added Request#isXHR. Closes #229
  • Added make install (for the executable)
  • Added express executable for setting up simple app templates
  • Added "GET /public/*" to Static plugin, defaulting to /public
  • Added Static plugin
  • Fixed; Request#render() only calls cache.get() once
  • Fixed; Namespacing View caches with "view:"
  • Fixed; Namespacing Static caches with "static:"
  • Fixed; Both example apps now use the Static plugin
  • Fixed set("views"). Closes #239
  • Fixed missing space for combined log format
  • Deprecated Request#sendfile() and 'express/static'
  • Removed Server#running

0.7.5 / 2010-03-16

  • Added Request#flash() support without args, now returns all flashes
  • Updated ext submodule

0.7.4 / 2010-03-16

  • Fixed session reaper
  • Changed; class.js replacing js-oo Class implementation (quite a bit faster, no browser cruft)

0.7.3 / 2010-03-16

  • Added package.json
  • Fixed requiring of haml / sass due to kiwi removal

0.7.2 / 2010-03-16

  • Fixed GIT submodules (HAH!)

0.7.1 / 2010-03-16

  • Changed; Express now using submodules again until a PM is adopted
  • Changed; chat example using millisecond conversions from ext

0.7.0 / 2010-03-15

  • Added Request#pass() support (finds the next matching route, or the given path)
  • Added Logger plugin (default "common" format replaces CommonLogger)
  • Removed Profiler plugin
  • Removed CommonLogger plugin

0.6.0 / 2010-03-11

  • Added seed.yml for kiwi package management support

  • Added HTTP client query string support when method is GET. Closes #205

  • Added support for arbitrary view engines. For example "foo.engine.html" will now require('engine'), the exports from this module are cached after the first require().

  • Added async plugin support

  • Removed usage of RESTful route funcs as http client get() etc, use http.get() and friends

  • Removed custom exceptions

0.5.0 / 2010-03-10

  • Added ext dependency (library of js extensions)
  • Removed extname() / basename() utils. Use path module
  • Removed toArray() util. Use arguments.values
  • Removed escapeRegexp() util. Use RegExp.escape()
  • Removed process.mixin() dependency. Use utils.mixin()
  • Removed Collection
  • Removed ElementCollection
  • Shameless self promotion of ebook "Advanced JavaScript" (http://dev-mag.com) ;)

0.4.0 / 2010-02-11

  • Added flash() example to sample upload app
  • Added high level restful http client module (express/http)
  • Changed; RESTful route functions double as HTTP clients. Closes #69
  • Changed; throwing error when routes are added at runtime
  • Changed; defaulting render() context to the current Request. Closes #197
  • Updated haml submodule

0.3.0 / 2010-02-11

  • Updated haml / sass submodules. Closes #200
  • Added flash message support. Closes #64
  • Added accepts() now allows multiple args. fixes #117
  • Added support for plugins to halt. Closes #189
  • Added alternate layout support. Closes #119
  • Removed Route#run(). Closes #188
  • Fixed broken specs due to use(Cookie) missing

0.2.1 / 2010-02-05

  • Added "plot" format option for Profiler (for gnuplot processing)
  • Added request number to Profiler plugin
  • Fixed binary encoding for multi-part file uploads, was previously defaulting to UTF8
  • Fixed issue with routes not firing when not files are present. Closes #184
  • Fixed process.Promise -> events.Promise

0.2.0 / 2010-02-03

  • Added parseParam() support for name[] etc. (allows for file inputs with "multiple" attr) Closes #180
  • Added Both Cache and Session option "reapInterval" may be "reapEvery". Closes #174
  • Added expiration support to cache api with reaper. Closes #133
  • Added cache Store.Memory#reap()
  • Added Cache; cache api now uses first class Cache instances
  • Added abstract session Store. Closes #172
  • Changed; cache Memory.Store#get() utilizing Collection
  • Renamed MemoryStore -> Store.Memory
  • Fixed use() of the same plugin several time will always use latest options. Closes #176

0.1.0 / 2010-02-03

  • Changed; Hooks (before / after) pass request as arg as well as evaluated in their context
  • Updated node support to 0.1.27 Closes #169
  • Updated dirname(__filename) -> __dirname
  • Updated libxmljs support to v0.2.0
  • Added session support with memory store / reaping
  • Added quick uid() helper
  • Added multi-part upload support
  • Added Sass.js support / submodule
  • Added production env caching view contents and static files
  • Added static file caching. Closes #136
  • Added cache plugin with memory stores
  • Added support to StaticFile so that it works with non-textual files.
  • Removed dirname() helper
  • Removed several globals (now their modules must be required)

0.0.2 / 2010-01-10

  • Added view benchmarks; currently haml vs ejs
  • Added Request#attachment() specs. Closes #116
  • Added use of node's parseQuery() util. Closes #123
  • Added make init for submodules
  • Updated Haml
  • Updated sample chat app to show messages on load
  • Updated libxmljs parseString -> parseHtmlString
  • Fixed make init to work with older versions of git
  • Fixed specs can now run independant specs for those who cant build deps. Closes #127
  • Fixed issues introduced by the node url module changes. Closes 126.
  • Fixed two assertions failing due to Collection#keys() returning strings
  • Fixed faulty Collection#toArray() spec due to keys() returning strings
  • Fixed make test now builds libxmljs.node before testing

0.0.1 / 2010-01-03

  • Initial release
module.exports = process.env.EXPRESS_COV
? require('./lib-cov/express')
: require('./lib/express');
/**
* Module dependencies.
*/
var connect = require('connect')
, Router = require('./router')
, methods = require('methods')
, middleware = require('./middleware')
, debug = require('debug')('express:application')
, locals = require('./utils').locals
, View = require('./view')
, utils = connect.utils
, path = require('path')
, http = require('http')
, join = path.join;
/**
* Application prototype.
*/
var app = exports = module.exports = {};
/**
* Initialize the server.
*
* - setup default configuration
* - setup default middleware
* - setup route reflection methods
*
* @api private
*/
app.init = function(){
this.cache = {};
this.settings = {};
this.engines = {};
this.viewCallbacks = [];
this.defaultConfiguration();
};
/**
* Initialize application configuration.
*
* @api private
*/
app.defaultConfiguration = function(){
// default settings
this.enable('x-powered-by');
this.set('env', process.env.NODE_ENV || 'development');
this.set('subdomain offset', 2);
debug('booting in %s mode', this.get('env'));
// implicit middleware
this.use(connect.query());
this.use(middleware.init(this));
// inherit protos
this.on('mount', function(parent){
this.request.__proto__ = parent.request;
this.response.__proto__ = parent.response;
this.engines.__proto__ = parent.engines;
});
// router
this._router = new Router(this);
this.routes = this._router.map;
this.__defineGetter__('router', function(){
this._usedRouter = true;
this._router.caseSensitive = this.enabled('case sensitive routing');
this._router.strict = this.enabled('strict routing');
return this._router.middleware;
});
// setup locals
this.locals = locals(this);
// default locals
this.locals.settings = this.settings;
// default configuration
this.set('views', process.cwd() + '/views');
this.set('jsonp callback name', 'callback');
this.configure('development', function(){
this.set('json spaces', 2);
});
this.configure('production', function(){
this.enable('view cache');
});
};
/**
* Proxy `connect#use()` to apply settings to
* mounted applications.
*
* @param {String|Function|Server} route
* @param {Function|Server} fn
* @return {app} for chaining
* @api public
*/
app.use = function(route, fn){
var app;
// default route to '/'
if ('string' != typeof route) fn = route, route = '/';
// express app
if (fn.handle && fn.set) app = fn;
// restore .app property on req and res
if (app) {
app.route = route;
fn = function(req, res, next) {
var orig = req.app;
app.handle(req, res, function(err){
req.app = res.app = orig;
req.__proto__ = orig.request;
res.__proto__ = orig.response;
next(err);
});
};
}
connect.proto.use.call(this, route, fn);
// mounted an app
if (app) {
app.parent = this;
app.emit('mount', this);
}
return this;
};
/**
* Register the given template engine callback `fn`
* as `ext`.
*
* By default will `require()` the engine based on the
* file extension. For example if you try to render
* a "foo.jade" file Express will invoke the following internally:
*
* app.engine('jade', require('jade').__express);
*
* For engines that do not provide `.__express` out of the box,
* or if you wish to "map" a different extension to the template engine
* you may use this method. For example mapping the EJS template engine to
* ".html" files:
*
* app.engine('html', require('ejs').renderFile);
*
* In this case EJS provides a `.renderFile()` method with
* the same signature that Express expects: `(path, options, callback)`,
* though note that it aliases this method as `ejs.__express` internally
* so if you're using ".ejs" extensions you dont need to do anything.
*
* Some template engines do not follow this convention, the
* [Consolidate.js](https://github.com/visionmedia/consolidate.js)
* library was created to map all of node's popular template
* engines to follow this convention, thus allowing them to
* work seeessly within Express.
*
* @param {String} ext
* @param {Function} fn
* @return {app} for chaining
* @api public
*/
app.engine = function(ext, fn){
if ('function' != typeof fn) throw new Error('callback function required');
if ('.' != ext[0]) ext = '.' + ext;
this.engines[ext] = fn;
return this;
};
/**
* Map the given param placeholder `name`(s) to the given callback(s).
*
* Parameter mapping is used to provide pre-conditions to routes
* which use normalized placeholders. For example a _:user_id_ parameter
* could automatically load a user's information from the database without
* any additional code,
*
* The callback uses the samesignature as middleware, the only differencing
* being that the value of the placeholder is passed, in this case the _id_
* of the user. Once the `next()` function is invoked, just like middleware
* it will continue on to execute the route, or subsequent parameter functions.
*
* app.param('user_id', function(req, res, next, id){
* User.find(id, function(err, user){
* if (err) {
* next(err);
* } else if (user) {
* req.user = user;
* next();
* } else {
* next(new Error('failed to load user'));
* }
* });
* });
*
* @param {String|Array} name
* @param {Function} fn
* @return {app} for chaining
* @api public
*/
app.param = function(name, fn){
var self = this
, fns = [].slice.call(arguments, 1);
// array
if (Array.isArray(name)) {
name.forEach(function(name){
fns.forEach(function(fn){
self.param(name, fn);
});
});
// param logic
} else if ('function' == typeof name) {
this._router.param(name);
// single
} else {
if (':' == name[0]) name = name.substr(1);
fns.forEach(function(fn){
self._router.param(name, fn);
});
}
return this;
};
/**
* Assign `setting` to `val`, or return `setting`'s value.
*
* app.set('foo', 'bar');
* app.get('foo');
* // => "bar"
*
* Mounted servers inherit their parent server's settings.
*
* @param {String} setting
* @param {String} val
* @return {Server} for chaining
* @api public
*/
app.set = function(setting, val){
if (1 == arguments.length) {
if (this.settings.hasOwnProperty(setting)) {
return this.settings[setting];
} else if (this.parent) {
return this.parent.set(setting);
}
} else {
this.settings[setting] = val;
return this;
}
};
/**
* Return the app's absolute pathname
* based on the parent(s) that have
* mounted it.
*
* For example if the application was
* mounted as "/admin", which itself
* was mounted as "/blog" then the
* return value would be "/blog/admin".
*
* @return {String}
* @api private
*/
app.path = function(){
return this.parent
? this.parent.path() + this.route
: '';
};
/**
* Check if `setting` is enabled (truthy).
*
* app.enabled('foo')
* // => false
*
* app.enable('foo')
* app.enabled('foo')
* // => true
*
* @param {String} setting
* @return {Boolean}
* @api public
*/
app.enabled = function(setting){
return !!this.set(setting);
};
/**
* Check if `setting` is disabled.
*
* app.disabled('foo')
* // => true
*
* app.enable('foo')
* app.disabled('foo')
* // => false
*
* @param {String} setting
* @return {Boolean}
* @api public
*/
app.disabled = function(setting){
return !this.set(setting);
};
/**
* Enable `setting`.
*
* @param {String} setting
* @return {app} for chaining
* @api public
*/
app.enable = function(setting){
return this.set(setting, true);
};
/**
* Disable `setting`.
*
* @param {String} setting
* @return {app} for chaining
* @api public
*/
app.disable = function(setting){
return this.set(setting, false);
};
/**
* Configure callback for zero or more envs,
* when no `env` is specified that callback will
* be invoked for all environments. Any combination
* can be used multiple times, in any order desired.
*
* Examples:
*
* app.configure(function(){
* // executed for all envs
* });
*
* app.configure('stage', function(){
* // executed staging env
* });
*
* app.configure('stage', 'production', function(){
* // executed for stage and production
* });
*
* Note:
*
* These callbacks are invoked immediately, and
* are effectively sugar for the following:
*
* var env = process.env.NODE_ENV || 'development';
*
* switch (env) {
* case 'development':
* ...
* break;
* case 'stage':
* ...
* break;
* case 'production':
* ...
* break;
* }
*
* @param {String} env...
* @param {Function} fn
* @return {app} for chaining
* @api public
*/
app.configure = function(env, fn){
var envs = 'all'
, args = [].slice.call(arguments);
fn = args.pop();
if (args.length) envs = args;
if ('all' == envs || ~envs.indexOf(this.settings.env)) fn.call(this);
return this;
};
/**
* Delegate `.VERB(...)` calls to `router.VERB(...)`.
*/
methods.forEach(function(method){
app[method] = function(path){
if ('get' == method && 1 == arguments.length) return this.set(path);
// if no router attacked yet, attach the router
if (!this._usedRouter) this.use(this.router);
// setup route
this._router[method].apply(this._router, arguments);
return this;
};
});
/**
* Special-cased "all" method, applying the given route `path`,
* middleware, and callback to _every_ HTTP method.
*
* @param {String} path
* @param {Function} ...
* @return {app} for chaining
* @api public
*/
app.all = function(path){
var args = arguments;
methods.forEach(function(method){
app[method].apply(this, args);
}, this);
return this;
};
// del -> delete alias
app.del = app.delete;
/**
* Render the given view `name` name with `options`
* and a callback accepting an error and the
* rendered template string.
*
* Example:
*
* app.render('email', { name: 'Tobi' }, function(err, html){
* // ...
* })
*
* @param {String} name
* @param {String|Function} options or fn
* @param {Function} fn
* @api public
*/
app.render = function(name, options, fn){
var opts = {}
, cache = this.cache
, engines = this.engines
, view;
// support callback function as second arg
if ('function' == typeof options) {
fn = options, options = {};
}
// merge app.locals
utils.merge(opts, this.locals);
// merge options._locals
if (options._locals) utils.merge(opts, options._locals);
// merge options
utils.merge(opts, options);
// set .cache unless explicitly provided
opts.cache = null == opts.cache
? this.enabled('view cache')
: opts.cache;
// primed cache
if (opts.cache) view = cache[name];
// view
if (!view) {
view = new View(name, {
defaultEngine: this.get('view engine'),
root: this.get('views'),
engines: engines
});
if (!view.path) {
var err = new Error('Failed to lookup view "' + name + '"');
err.view = view;
return fn(err);
}
// prime the cache
if (opts.cache) cache[name] = view;
}
// render
try {
view.render(opts, fn);
} catch (err) {
fn(err);
}
};
/**
* Listen for connections.
*
* A node `http.Server` is returned, with this
* application (which is a `Function`) as its
* callback. If you wish to create both an HTTP
* and HTTPS server you may do so with the "http"
* and "https" modules as shown here:
*
* var http = require('http')
* , https = require('https')
* , express = require('express')
* , app = express();
*
* http.createServer(app).listen(80);
* https.createServer({ ... }, app).listen(443);
*
* @return {http.Server}
* @api public
*/
app.listen = function(){
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};
/**
* Module dependencies.
*/
var connect = require('connect')
, proto = require('./application')
, Route = require('./router/route')
, Router = require('./router')
, req = require('./request')
, res = require('./response')
, utils = connect.utils;
/**
* Expose `createApplication()`.
*/
exports = module.exports = createApplication;
/**
* Framework version.
*/
exports.version = '3.1.0';
/**
* Expose mime.
*/
exports.mime = connect.mime;
/**
* Create an express application.
*
* @return {Function}
* @api public
*/
function createApplication() {
var app = connect();
utils.merge(app, proto);
app.request = { __proto__: req };
app.response = { __proto__: res };
app.init();
return app;
}
/**
* Expose connect.middleware as express.*
* for example `express.logger` etc.
*/
for (var key in connect.middleware) {
Object.defineProperty(
exports
, key
, Object.getOwnPropertyDescriptor(connect.middleware, key));
}
/**
* Error on createServer().
*/
exports.createServer = function(){
console.warn('Warning: express.createServer() is deprecated, express');
console.warn('applications no longer inherit from http.Server,');
console.warn('please use:');
console.warn('');
console.warn(' var express = require("express");');
console.warn(' var app = express();');
console.warn('');
return createApplication();
};
/**
* Expose the prototypes.
*/
exports.application = proto;
exports.request = req;
exports.response = res;
/**
* Expose constructors.
*/
exports.Route = Route;
exports.Router = Router;
// Error handler title
exports.errorHandler.title = 'Express';
/**
* Module dependencies.
*/
var utils = require('./utils');
/**
* Initialization middleware, exposing the
* request and response to eachother, as well
* as defaulting the X-Powered-By header field.
*
* @param {Function} app
* @return {Function}
* @api private
*/
exports.init = function(app){
return function expressInit(req, res, next){
req.app = res.app = app;
if (app.enabled('x-powered-by')) res.setHeader('X-Powered-By', 'Express');
req.res = res;
res.req = req;
req.next = next;
req.__proto__ = app.request;
res.__proto__ = app.response;
res.locals = res.locals || utils.locals(res);
next();
}
};
/**
* Module dependencies.
*/
var http = require('http')
, utils = require('./utils')
, connect = require('connect')
, fresh = require('fresh')
, parseRange = require('range-parser')
, parse = connect.utils.parseUrl
, mime = connect.mime;
/**
* Request prototype.
*/
var req = exports = module.exports = {
__proto__: http.IncomingMessage.prototype
};
/**
* Return request header.
*
* The `Referrer` header field is special-cased,
* both `Referrer` and `Referer` are interchangeable.
*
* Examples:
*
* req.get('Content-Type');
* // => "text/plain"
*
* req.get('content-type');
* // => "text/plain"
*
* req.get('Something');
* // => undefined
*
* Aliased as `req.header()`.
*
* @param {String} name
* @return {String}
* @api public
*/
req.get =
req.header = function(name){
switch (name = name.toLowerCase()) {
case 'referer':
case 'referrer':
return this.headers.referrer
|| this.headers.referer;
default:
return this.headers[name];
}
};
/**
* Check if the given `type(s)` is acceptable, returning
* the best match when true, otherwise `undefined`, in which
* case you should respond with 406 "Not Acceptable".
*
* The `type` value may be a single mime type string
* such as "application/json", the extension name
* such as "json", a comma-delimted list such as "json, html, text/plain",
* or an array `["json", "html", "text/plain"]`. When a list
* or array is given the _best_ match, if any is returned.
*
* Examples:
*
* // Accept: text/html
* req.accepts('html');
* // => "html"
*
* // Accept: text/*, application/json
* req.accepts('html');
* // => "html"
* req.accepts('text/html');
* // => "text/html"
* req.accepts('json, text');
* // => "json"
* req.accepts('application/json');
* // => "application/json"
*
* // Accept: text/*, application/json
* req.accepts('image/png');
* req.accepts('png');
* // => undefined
*
* // Accept: text/*;q=.5, application/json
* req.accepts(['html', 'json']);
* req.accepts('html, json');
* // => "json"
*
* @param {String|Array} type(s)
* @return {String}
* @api public
*/
req.accepts = function(type){
return utils.accepts(type, this.get('Accept'));
};
/**
* Check if the given `charset` is acceptable,
* otherwise you should respond with 406 "Not Acceptable".
*
* @param {String} charset
* @return {Boolean}
* @api public
*/
req.acceptsCharset = function(charset){
var accepted = this.acceptedCharsets;
return accepted.length
? ~accepted.indexOf(charset)
: true;
};
/**
* Check if the given `lang` is acceptable,
* otherwise you should respond with 406 "Not Acceptable".
*
* @param {String} lang
* @return {Boolean}
* @api public
*/
req.acceptsLanguage = function(lang){
var accepted = this.acceptedLanguages;
return accepted.length
? ~accepted.indexOf(lang)
: true;
};
/**
* Parse Range header field,
* capping to the given `size`.
*
* Unspecified ranges such as "0-" require
* knowledge of your resource length. In
* the case of a byte range this is of course
* the total number of bytes. If the Range
* header field is not given `null` is returned,
* `-1` when unsatisfiable, `-2` when syntactically invalid.
*
* NOTE: remember that ranges are inclusive, so
* for example "Range: users=0-3" should respond
* with 4 users when available, not 3.
*
* @param {Number} size
* @return {Array}
* @api public
*/
req.range = function(size){
var range = this.get('Range');
if (!range) return;
return parseRange(size, range);
};
/**
* Return an array of Accepted media types
* ordered from highest quality to lowest.
*
* Examples:
*
* [ { value: 'application/json',
* quality: 1,
* type: 'application',
* subtype: 'json' },
* { value: 'text/html',
* quality: 0.5,
* type: 'text',
* subtype: 'html' } ]
*
* @return {Array}
* @api public
*/
req.__defineGetter__('accepted', function(){
var accept = this.get('Accept');
return accept
? utils.parseAccept(accept)
: [];
});
/**
* Return an array of Accepted languages
* ordered from highest quality to lowest.
*
* Examples:
*
* Accept-Language: en;q=.5, en-us
* ['en-us', 'en']
*
* @return {Array}
* @api public
*/
req.__defineGetter__('acceptedLanguages', function(){
var accept = this.get('Accept-Language');
return accept
? utils
.parseQuality(accept)
.map(function(obj){
return obj.value;
})
: [];
});
/**
* Return an array of Accepted charsets
* ordered from highest quality to lowest.
*
* Examples:
*
* Accept-Charset: iso-8859-5;q=.2, unicode-1-1;q=0.8
* ['unicode-1-1', 'iso-8859-5']
*
* @return {Array}
* @api public
*/
req.__defineGetter__('acceptedCharsets', function(){
var accept = this.get('Accept-Charset');
return accept
? utils
.parseQuality(accept)
.map(function(obj){
return obj.value;
})
: [];
});
/**
* Return the value of param `name` when present or `defaultValue`.
*
* - Checks route placeholders, ex: _/user/:id_
* - Checks body params, ex: id=12, {"id":12}
* - Checks query string params, ex: ?id=12
*
* To utilize request bodies, `req.body`
* should be an object. This can be done by using
* the `connect.bodyParser()` middleware.
*
* @param {String} name
* @param {Mixed} defaultValue
* @return {String}
* @api public
*/
req.param = function(name, defaultValue){
var params = this.params || {};
var body = this.body || {};
var query = this.query || {};
if (null != params[name] && params.hasOwnProperty(name)) return params[name];
if (null != body[name]) return body[name];
if (null != query[name]) return query[name];
return defaultValue;
};
/**
* Check if the incoming request contains the "Content-Type"
* header field, and it contains the give mime `type`.
*
* Examples:
*
* // With Content-Type: text/html; charset=utf-8
* req.is('html');
* req.is('text/html');
* req.is('text/*');
* // => true
*
* // When Content-Type is application/json
* req.is('json');
* req.is('application/json');
* req.is('application/*');
* // => true
*
* req.is('html');
* // => false
*
* @param {String} type
* @return {Boolean}
* @api public
*/
req.is = function(type){
var ct = this.get('Content-Type');
if (!ct) return false;
ct = ct.split(';')[0];
if (!~type.indexOf('/')) type = mime.lookup(type);
if (~type.indexOf('*')) {
type = type.split('/');
ct = ct.split('/');
if ('*' == type[0] && type[1] == ct[1]) return true;
if ('*' == type[1] && type[0] == ct[0]) return true;
return false;
}
return !! ~ct.indexOf(type);
};
/**
* Return the protocol string "http" or "https"
* when requested with TLS. When the "trust proxy"
* setting is enabled the "X-Forwarded-Proto" header
* field will be trusted. If you're running behind
* a reverse proxy that supplies https for you this
* may be enabled.
*
* @return {String}
* @api public
*/
req.__defineGetter__('protocol', function(){
var trustProxy = this.app.get('trust proxy');
return this.connection.encrypted
? 'https'
: trustProxy
? (this.get('X-Forwarded-Proto') || 'http')
: 'http';
});
/**
* Short-hand for:
*
* req.protocol == 'https'
*
* @return {Boolean}
* @api public
*/
req.__defineGetter__('secure', function(){
return 'https' == this.protocol;
});
/**
* Return the remote address, or when
* "trust proxy" is `true` return
* the upstream addr.
*
* @return {String}
* @api public
*/
req.__defineGetter__('ip', function(){
return this.ips[0] || this.connection.remoteAddress;
});
/**
* When "trust proxy" is `true`, parse
* the "X-Forwarded-For" ip address list.
*
* For example if the value were "client, proxy1, proxy2"
* you would receive the array `["client", "proxy1", "proxy2"]`
* where "proxy2" is the furthest down-stream.
*
* @return {Array}
* @api public
*/
req.__defineGetter__('ips', function(){
var trustProxy = this.app.get('trust proxy');
var val = this.get('X-Forwarded-For');
return trustProxy && val
? val.split(/ *, */)
: [];
});
/**
* Return basic auth credentials.
*
* Examples:
*
* // http://tobi:[email protected]
* req.auth
* // => { username: 'tobi', password: 'hello' }
*
* @return {Object} or undefined
* @api public
*/
req.__defineGetter__('auth', function(){
// missing
var auth = this.get('Authorization');
if (!auth) return;
// malformed
var parts = auth.split(' ');
if ('basic' != parts[0].toLowerCase()) return;
if (!parts[1]) return;
auth = parts[1];
// credentials
auth = new Buffer(auth, 'base64').toString().match(/^([^:]*):(.*)$/);
if (!auth) return;
return { username: auth[1], password: auth[2] };
});
/**
* Return subdomains as an array.
*
* Subdomains are the dot-separated parts of the host before the main domain of
* the app. By default, the domain of the app is assumed to be the last two
* parts of the host. This can be changed by setting "subdomain offset".
*
* For example, if the domain is "tobi.ferrets.example.com":
* If "subdomain offset" is not set, req.subdomains is `["ferrets", "tobi"]`.
* If "subdomain offset" is 3, req.subdomains is `["tobi"]`.
*
* @return {Array}
* @api public
*/
req.__defineGetter__('subdomains', function(){
var offset = this.app.get('subdomain offset');
return this.get('Host')
.split('.')
.reverse()
.slice(offset);
});
/**
* Short-hand for `url.parse(req.url).pathname`.
*
* @return {String}
* @api public
*/
req.__defineGetter__('path', function(){
return parse(this).pathname;
});
/**
* Parse the "Host" header field hostname.
*
* @return {String}
* @api public
*/
req.__defineGetter__('host', function(){
return this.get('Host').split(':')[0];
});
/**
* Check if the request is fresh, aka
* Last-Modified and/or the ETag
* still match.
*
* @return {Boolean}
* @api public
*/
req.__defineGetter__('fresh', function(){
var method = this.method;
var s = this.res.statusCode;
// GET or HEAD for weak freshness validation only
if ('GET' != method && 'HEAD' != method) return false;
// 2xx or 304 as per rfc2616 14.26
if ((s >= 200 && s < 300) || 304 == s) {
return fresh(this.headers, this.res._headers);
}
return false;
});
/**
* Check if the request is stale, aka
* "Last-Modified" and / or the "ETag" for the
* resource has changed.
*
* @return {Boolean}
* @api public
*/
req.__defineGetter__('stale', function(){
return !this.fresh;
});
/**
* Check if the request was an _XMLHttpRequest_.
*
* @return {Boolean}
* @api public
*/
req.__defineGetter__('xhr', function(){
var val = this.get('X-Requested-With') || '';
return 'xmlhttprequest' == val.toLowerCase();
});
/**
* Module dependencies.
*/
var http = require('http')
, path = require('path')
, connect = require('connect')
, utils = connect.utils
, sign = require('cookie-signature').sign
, normalizeType = require('./utils').normalizeType
, normalizeTypes = require('./utils').normalizeTypes
, etag = require('./utils').etag
, statusCodes = http.STATUS_CODES
, cookie = require('cookie')
, send = require('send')
, mime = connect.mime
, basename = path.basename
, extname = path.extname
, join = path.join;
/**
* Response prototype.
*/
var res = module.exports = {
__proto__: http.ServerResponse.prototype
};
/**
* Set status `code`.
*
* @param {Number} code
* @return {ServerResponse}
* @api public
*/
res.status = function(code){
this.statusCode = code;
return this;
};
/**
* Set Link header field with the given `links`.
*
* Examples:
*
* res.links({
* next: 'http://api.example.com/users?page=2',
* last: 'http://api.example.com/users?page=5'
* });
*
* @param {Object} links
* @return {ServerResponse}
* @api public
*/
res.links = function(links){
return this.set('Link', Object.keys(links).map(function(rel){
return '<' + links[rel] + '>; rel="' + rel + '"';
}).join(', '));
};
/**
* Send a response.
*
* Examples:
*
* res.send(new Buffer('wahoo'));
* res.send({ some: 'json' });
* res.send('<p>some html</p>');
* res.send(404, 'Sorry, cant find that');
* res.send(404);
*
* @param {Mixed} body or status
* @param {Mixed} body
* @return {ServerResponse}
* @api public
*/
res.send = function(body){
var req = this.req
, head = 'HEAD' == req.method
, len;
// allow status / body
if (2 == arguments.length) {
// res.send(body, status) backwards compat
if ('number' != typeof body && 'number' == typeof arguments[1]) {
this.statusCode = arguments[1];
} else {
this.statusCode = body;
body = arguments[1];
}
}
switch (typeof body) {
// response status
case 'number':
this.get('Content-Type') || this.type('txt');
this.statusCode = body;
body = http.STATUS_CODES[body];
break;
// string defaulting to html
case 'string':
if (!this.get('Content-Type')) {
this.charset = this.charset || 'utf-8';
this.type('html');
}
break;
case 'boolean':
case 'object':
if (null == body) {
body = '';
} else if (Buffer.isBuffer(body)) {
this.get('Content-Type') || this.type('bin');
} else {
return this.json(body);
}
break;
}
// populate Content-Length
if (undefined !== body && !this.get('Content-Length')) {
this.set('Content-Length', len = Buffer.isBuffer(body)
? body.length
: Buffer.byteLength(body));
}
// ETag support
// TODO: W/ support
if (len > 1024) {
if (!this.get('ETag')) {
this.set('ETag', etag(body));
}
}
// freshness
if (req.fresh) this.statusCode = 304;
// strip irrelevant headers
if (204 == this.statusCode || 304 == this.statusCode) {
this.removeHeader('Content-Type');
this.removeHeader('Content-Length');
this.removeHeader('Transfer-Encoding');
body = '';
}
// respond
this.end(head ? null : body);
return this;
};
/**
* Send JSON response.
*
* Examples:
*
* res.json(null);
* res.json({ user: 'tj' });
* res.json(500, 'oh noes!');
* res.json(404, 'I dont have that');
*
* @param {Mixed} obj or status
* @param {Mixed} obj
* @return {ServerResponse}
* @api public
*/
res.json = function(obj){
// allow status / body
if (2 == arguments.length) {
// res.json(body, status) backwards compat
if ('number' == typeof arguments[1]) {
this.statusCode = arguments[1];
} else {
this.statusCode = obj;
obj = arguments[1];
}
}
// settings
var app = this.app;
var replacer = app.get('json replacer');
var spaces = app.get('json spaces');
var body = JSON.stringify(obj, replacer, spaces);
// content-type
this.charset = this.charset || 'utf-8';
this.get('Content-Type') || this.set('Content-Type', 'application/json');
return this.send(body);
};
/**
* Send JSON response with JSONP callback support.
*
* Examples:
*
* res.jsonp(null);
* res.jsonp({ user: 'tj' });
* res.jsonp(500, 'oh noes!');
* res.jsonp(404, 'I dont have that');
*
* @param {Mixed} obj or status
* @param {Mixed} obj
* @return {ServerResponse}
* @api public
*/
res.jsonp = function(obj){
// allow status / body
if (2 == arguments.length) {
// res.json(body, status) backwards compat
if ('number' == typeof arguments[1]) {
this.statusCode = arguments[1];
} else {
this.statusCode = obj;
obj = arguments[1];
}
}
// settings
var app = this.app;
var replacer = app.get('json replacer');
var spaces = app.get('json spaces');
var body = JSON.stringify(obj, replacer, spaces)
.replace(/\u2028/g, '\\u2028')
.replace(/\u2029/g, '\\u2029');
var callback = this.req.query[app.get('jsonp callback name')];
// content-type
this.charset = this.charset || 'utf-8';
this.set('Content-Type', 'application/json');
// jsonp
if (callback) {
this.set('Content-Type', 'text/javascript');
var cb = callback.replace(/[^\[\]\w$.]/g, '');
body = cb + ' && ' + cb + '(' + body + ');';
}
return this.send(body);
};
/**
* Transfer the file at the given `path`.
*
* Automatically sets the _Content-Type_ response header field.
* The callback `fn(err)` is invoked when the transfer is complete
* or when an error occurs. Be sure to check `res.sentHeader`
* if you wish to attempt responding, as the header and some data
* may have already been transferred.
*
* Options:
*
* - `maxAge` defaulting to 0
* - `root` root directory for relative filenames
*
* Examples:
*
* The following example illustrates how `res.sendfile()` may
* be used as an alternative for the `static()` middleware for
* dynamic situations. The code backing `res.sendfile()` is actually
* the same code, so HTTP cache support etc is identical.
*
* app.get('/user/:uid/photos/:file', function(req, res){
* var uid = req.params.uid
* , file = req.params.file;
*
* req.user.mayViewFilesFrom(uid, function(yes){
* if (yes) {
* res.sendfile('/uploads/' + uid + '/' + file);
* } else {
* res.send(403, 'Sorry! you cant see that.');
* }
* });
* });
*
* @param {String} path
* @param {Object|Function} options or fn
* @param {Function} fn
* @api public
*/
res.sendfile = function(path, options, fn){
var self = this
, req = self.req
, next = this.req.next
, options = options || {}
, done;
// support function as second arg
if ('function' == typeof options) {
fn = options;
options = {};
}
// socket errors
req.socket.on('error', error);
// errors
function error(err) {
if (done) return;
done = true;
// clean up
cleanup();
if (!self.headerSent) self.removeHeader('Content-Disposition');
// callback available
if (fn) return fn(err);
// list in limbo if there's no callback
if (self.headerSent) return;
// delegate
next(err);
}
// streaming
function stream() {
if (done) return;
cleanup();
if (fn) self.on('finish', fn);
}
// cleanup
function cleanup() {
req.socket.removeListener('error', error);
}
// transfer
var file = send(req, path);
if (options.root) file.root(options.root);
file.maxage(options.maxAge || 0);
file.on('error', error);
file.on('directory', next);
file.on('stream', stream);
file.pipe(this);
this.on('finish', cleanup);
};
/**
* Transfer the file at the given `path` as an attachment.
*
* Optionally providing an alternate attachment `filename`,
* and optional callback `fn(err)`. The callback is invoked
* when the data transfer is complete, or when an error has
* ocurred. Be sure to check `res.headerSent` if you plan to respond.
*
* This method uses `res.sendfile()`.
*
* @param {String} path
* @param {String|Function} filename or fn
* @param {Function} fn
* @api public
*/
res.download = function(path, filename, fn){
// support function as second arg
if ('function' == typeof filename) {
fn = filename;
filename = null;
}
filename = filename || path;
this.set('Content-Disposition', 'attachment; filename="' + basename(filename) + '"');
return this.sendfile(path, fn);
};
/**
* Set _Content-Type_ response header with `type` through `mime.lookup()`
* when it does not contain "/", or set the Content-Type to `type` otherwise.
*
* Examples:
*
* res.type('.html');
* res.type('html');
* res.type('json');
* res.type('application/json');
* res.type('png');
*
* @param {String} type
* @return {ServerResponse} for chaining
* @api public
*/
res.contentType =
res.type = function(type){
return this.set('Content-Type', ~type.indexOf('/')
? type
: mime.lookup(type));
};
/**
* Respond to the Acceptable formats using an `obj`
* of mime-type callbacks.
*
* This method uses `req.accepted`, an array of
* acceptable types ordered by their quality values.
* When "Accept" is not present the _first_ callback
* is invoked, otherwise the first match is used. When
* no match is performed the server responds with
* 406 "Not Acceptable".
*
* Content-Type is set for you, however if you choose
* you may alter this within the callback using `res.type()`
* or `res.set('Content-Type', ...)`.
*
* res.format({
* 'text/plain': function(){
* res.send('hey');
* },
*
* 'text/html': function(){
* res.send('<p>hey</p>');
* },
*
* 'appliation/json': function(){
* res.send({ message: 'hey' });
* }
* });
*
* In addition to canonicalized MIME types you may
* also use extnames mapped to these types:
*
* res.format({
* text: function(){
* res.send('hey');
* },
*
* html: function(){
* res.send('<p>hey</p>');
* },
*
* json: function(){
* res.send({ message: 'hey' });
* }
* });
*
* By default Express passes an `Error`
* with a `.status` of 406 to `next(err)`
* if a match is not made. If you provide
* a `.default` callback it will be invoked
* instead.
*
* @param {Object} obj
* @return {ServerResponse} for chaining
* @api public
*/
res.format = function(obj){
var req = this.req
, next = req.next;
var fn = obj.default;
if (fn) delete obj.default;
var keys = Object.keys(obj);
var key = req.accepts(keys);
this.set('Vary', 'Accept');
if (key) {
this.set('Content-Type', normalizeType(key));
obj[key](req, this, next);
} else if (fn) {
fn();
} else {
var err = new Error('Not Acceptable');
err.status = 406;
err.types = normalizeTypes(keys);
next(err);
}
return this;
};
/**
* Set _Content-Disposition_ header to _attachment_ with optional `filename`.
*
* @param {String} filename
* @return {ServerResponse}
* @api public
*/
res.attachment = function(filename){
if (filename) this.type(extname(filename));
this.set('Content-Disposition', filename
? 'attachment; filename="' + basename(filename) + '"'
: 'attachment');
return this;
};
/**
* Set header `field` to `val`, or pass
* an object of header fields.
*
* Examples:
*
* res.set('Foo', ['bar', 'baz']);
* res.set('Accept', 'application/json');
* res.set({ Accept: 'text/plain', 'X-API-Key': 'tobi' });
*
* Aliased as `res.header()`.
*
* @param {String|Object|Array} field
* @param {String} val
* @return {ServerResponse} for chaining
* @api public
*/
res.set =
res.header = function(field, val){
if (2 == arguments.length) {
if (Array.isArray(val)) val = val.map(String);
else val = String(val);
this.setHeader(field, val);
} else {
for (var key in field) {
this.set(key, field[key]);
}
}
return this;
};
/**
* Get value for header `field`.
*
* @param {String} field
* @return {String}
* @api public
*/
res.get = function(field){
return this.getHeader(field);
};
/**
* Clear cookie `name`.
*
* @param {String} name
* @param {Object} options
* @param {ServerResponse} for chaining
* @api public
*/
res.clearCookie = function(name, options){
var opts = { expires: new Date(1), path: '/' };
return this.cookie(name, '', options
? utils.merge(opts, options)
: opts);
};
/**
* Set cookie `name` to `val`, with the given `options`.
*
* Options:
*
* - `maxAge` max-age in milliseconds, converted to `expires`
* - `signed` sign the cookie
* - `path` defaults to "/"
*
* Examples:
*
* // "Remember Me" for 15 minutes
* res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true });
*
* // save as above
* res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true })
*
* @param {String} name
* @param {String|Object} val
* @param {Options} options
* @api public
*/
res.cookie = function(name, val, options){
options = utils.merge({}, options);
var secret = this.req.secret;
var signed = options.signed;
if (signed && !secret) throw new Error('connect.cookieParser("secret") required for signed cookies');
if ('object' == typeof val) val = 'j:' + JSON.stringify(val);
if (signed) val = 's:' + sign(val, secret);
if ('maxAge' in options) {
options.expires = new Date(Date.now() + options.maxAge);
options.maxAge /= 1000;
}
if (null == options.path) options.path = '/';
this.set('Set-Cookie', cookie.serialize(name, String(val), options));
return this;
};
/**
* Set the location header to `url`.
*
* The given `url` can also be the name of a mapped url, for
* example by default express supports "back" which redirects
* to the _Referrer_ or _Referer_ headers or "/".
*
* Examples:
*
* res.location('/foo/bar').;
* res.location('http://example.com');
* res.location('../login'); // /blog/post/1 -> /blog/login
*
* Mounting:
*
* When an application is mounted and `res.location()`
* is given a path that does _not_ lead with "/" it becomes
* relative to the mount-point. For example if the application
* is mounted at "/blog", the following would become "/blog/login".
*
* res.location('login');
*
* While the leading slash would result in a location of "/login":
*
* res.location('/login');
*
* @param {String} url
* @api public
*/
res.location = function(url){
var app = this.app
, req = this.req;
// setup redirect map
var map = { back: req.get('Referrer') || '/' };
// perform redirect
url = map[url] || url;
// relative
if (!~url.indexOf('://') && 0 != url.indexOf('//')) {
var path = app.path();
// relative to path
if ('.' == url[0]) {
url = req.path + '/' + url;
// relative to mount-point
} else if ('/' != url[0]) {
url = path + '/' + url;
}
}
// Respond
this.set('Location', url);
return this;
};
/**
* Redirect to the given `url` with optional response `status`
* defaulting to 302.
*
* The resulting `url` is determined by `res.location()`, so
* it will play nicely with mounted apps, relative paths,
* `"back"` etc.
*
* Examples:
*
* res.redirect('/foo/bar');
* res.redirect('http://example.com');
* res.redirect(301, 'http://example.com');
* res.redirect('http://example.com', 301);
* res.redirect('../login'); // /blog/post/1 -> /blog/login
*
* @param {String} url
* @param {Number} code
* @api public
*/
res.redirect = function(url){
var app = this.app
, head = 'HEAD' == this.req.method
, status = 302
, body;
// allow status / url
if (2 == arguments.length) {
if ('number' == typeof url) {
status = url;
url = arguments[1];
} else {
status = arguments[1];
}
}
// Set location header
this.location(url);
url = this.get('Location');
// Support text/{plain,html} by default
this.format({
text: function(){
body = statusCodes[status] + '. Redirecting to ' + encodeURI(url);
},
html: function(){
var u = utils.escape(url);
body = '<p>' + statusCodes[status] + '. Redirecting to <a href="' + u + '">' + u + '</a></p>';
},
default: function(){
body = '';
}
});
// Respond
this.statusCode = status;
this.set('Content-Length', Buffer.byteLength(body));
this.end(head ? null : body);
};
/**
* Render `view` with the given `options` and optional callback `fn`.
* When a callback function is given a response will _not_ be made
* automatically, otherwise a response of _200_ and _text/html_ is given.
*
* Options:
*
* - `cache` boolean hinting to the engine it should cache
* - `filename` filename of the view being rendered
*
* @param {String} view
* @param {Object|Function} options or callback function
* @param {Function} fn
* @api public
*/
res.render = function(view, options, fn){
var self = this
, options = options || {}
, req = this.req
, app = req.app;
// support callback function as second arg
if ('function' == typeof options) {
fn = options, options = {};
}
// merge res.locals
options._locals = self.locals;
// default callback to respond
fn = fn || function(err, str){
if (err) return req.next(err);
self.send(str);
};
// render
app.render(view, options, fn);
};
/**
* Module dependencies.
*/
var Route = require('./route')
, utils = require('../utils')
, methods = require('methods')
, debug = require('debug')('express:router')
, parse = require('connect').utils.parseUrl;
/**
* Expose `Router` constructor.
*/
exports = module.exports = Router;
/**
* Initialize a new `Router` with the given `options`.
*
* @param {Object} options
* @api private
*/
function Router(options) {
options = options || {};
var self = this;
this.map = {};
this.params = {};
this._params = [];
this.caseSensitive = options.caseSensitive;
this.strict = options.strict;
this.middleware = function router(req, res, next){
self._dispatch(req, res, next);
};
}
/**
* Register a param callback `fn` for the given `name`.
*
* @param {String|Function} name
* @param {Function} fn
* @return {Router} for chaining
* @api public
*/
Router.prototype.param = function(name, fn){
// param logic
if ('function' == typeof name) {
this._params.push(name);
return;
}
// apply param functions
var params = this._params
, len = params.length
, ret;
for (var i = 0; i < len; ++i) {
if (ret = params[i](name, fn)) {
fn = ret;
}
}
// ensure we end up with a
// middleware function
if ('function' != typeof fn) {
throw new Error('invalid param() call for ' + name + ', got ' + fn);
}
(this.params[name] = this.params[name] || []).push(fn);
return this;
};
/**
* Route dispatcher aka the route "middleware".
*
* @param {IncomingMessage} req
* @param {ServerResponse} res
* @param {Function} next
* @api private
*/
Router.prototype._dispatch = function(req, res, next){
var params = this.params
, self = this;
debug('dispatching %s %s (%s)', req.method, req.url, req.originalUrl);
// route dispatch
(function pass(i, err){
var paramCallbacks
, paramIndex = 0
, paramVal
, route
, keys
, key;
// match next route
function nextRoute(err) {
pass(req._route_index + 1, err);
}
// match route
req.route = route = self.matchRequest(req, i);
// no route
if (!route) return next(err);
debug('matched %s %s', route.method, route.path);
// we have a route
// start at param 0
req.params = route.params;
keys = route.keys;
i = 0;
// param callbacks
function param(err) {
paramIndex = 0;
key = keys[i++];
paramVal = key && req.params[key.name];
paramCallbacks = key && params[key.name];
try {
if ('route' == err) {
nextRoute();
} else if (err) {
i = 0;
callbacks(err);
} else if (paramCallbacks && undefined !== paramVal) {
paramCallback();
} else if (key) {
param();
} else {
i = 0;
callbacks();
}
} catch (err) {
param(err);
}
};
param(err);
// single param callbacks
function paramCallback(err) {
var fn = paramCallbacks[paramIndex++];
if (err || !fn) return param(err);
fn(req, res, paramCallback, paramVal, key.name);
}
// invoke route callbacks
function callbacks(err) {
var fn = route.callbacks[i++];
try {
if ('route' == err) {
nextRoute();
} else if (err && fn) {
if (fn.length < 4) return callbacks(err);
fn(err, req, res, callbacks);
} else if (fn) {
if (fn.length < 4) return fn(req, res, callbacks);
callbacks();
} else {
nextRoute(err);
}
} catch (err) {
callbacks(err);
}
}
})(0);
};
/**
* Attempt to match a route for `req`
* with optional starting index of `i`
* defaulting to 0.
*
* @param {IncomingMessage} req
* @param {Number} i
* @return {Route}
* @api private
*/
Router.prototype.matchRequest = function(req, i, head){
var method = req.method.toLowerCase()
, url = parse(req)
, path = url.pathname
, routes = this.map
, i = i || 0
, route;
// HEAD support
if (!head && 'head' == method) {
route = this.matchRequest(req, i, true);
if (route) return route;
method = 'get';
}
// routes for this method
if (routes = routes[method]) {
// matching routes
for (var len = routes.length; i < len; ++i) {
route = routes[i];
if (route.match(path)) {
req._route_index = i;
return route;
}
}
}
};
/**
* Attempt to match a route for `method`
* and `url` with optional starting
* index of `i` defaulting to 0.
*
* @param {String} method
* @param {String} url
* @param {Number} i
* @return {Route}
* @api private
*/
Router.prototype.match = function(method, url, i, head){
var req = { method: method, url: url };
return this.matchRequest(req, i, head);
};
/**
* Route `method`, `path`, and one or more callbacks.
*
* @param {String} method
* @param {String} path
* @param {Function} callback...
* @return {Router} for chaining
* @api private
*/
Router.prototype.route = function(method, path, callbacks){
var method = method.toLowerCase()
, callbacks = utils.flatten([].slice.call(arguments, 2));
// ensure path was given
if (!path) throw new Error('Router#' + method + '() requires a path');
// ensure all callbacks are functions
callbacks.forEach(function(fn, i){
if ('function' == typeof fn) return;
var type = {}.toString.call(fn);
var msg = '.' + method + '() requires callback functions but got a ' + type;
throw new Error(msg);
});
// create the route
debug('defined %s %s', method, path);
var route = new Route(method, path, callbacks, {
sensitive: this.caseSensitive,
strict: this.strict
});
// add it
(this.map[method] = this.map[method] || []).push(route);
return this;
};
methods.forEach(function(method){
Router.prototype[method] = function(path){
var args = [method].concat([].slice.call(arguments));
this.route.apply(this, args);
return this;
};
});
/**
* Module dependencies.
*/
var utils = require('../utils');
/**
* Expose `Route`.
*/
module.exports = Route;
/**
* Initialize `Route` with the given HTTP `method`, `path`,
* and an array of `callbacks` and `options`.
*
* Options:
*
* - `sensitive` enable case-sensitive routes
* - `strict` enable strict matching for trailing slashes
*
* @param {String} method
* @param {String} path
* @param {Array} callbacks
* @param {Object} options.
* @api private
*/
function Route(method, path, callbacks, options) {
options = options || {};
this.path = path;
this.method = method;
this.callbacks = callbacks;
this.regexp = utils.pathRegexp(path
, this.keys = []
, options.sensitive
, options.strict);
}
/**
* Check if this route matches `path`, if so
* populate `.params`.
*
* @param {String} path
* @return {Boolean}
* @api private
*/
Route.prototype.match = function(path){
var keys = this.keys
, params = this.params = []
, m = this.regexp.exec(path);
if (!m) return false;
for (var i = 1, len = m.length; i < len; ++i) {
var key = keys[i - 1];
var val = 'string' == typeof m[i]
? decodeURIComponent(m[i])
: m[i];
if (key) {
params[key.name] = val;
} else {
params.push(val);
}
}
return true;
};
/**
* Module dependencies.
*/
var mime = require('connect').mime
, crc32 = require('buffer-crc32');
/**
* Return ETag for `body`.
*
* @param {String|Buffer} body
* @return {String}
* @api private
*/
exports.etag = function(body){
return '"' + crc32.signed(body) + '"';
};
/**
* Make `locals()` bound to the given `obj`.
*
* This is used for `app.locals` and `res.locals`.
*
* @param {Object} obj
* @return {Function}
* @api private
*/
exports.locals = function(obj){
obj.viewCallbacks = obj.viewCallbacks || [];
function locals(obj){
for (var key in obj) locals[key] = obj[key];
return obj;
};
return locals;
};
/**
* Check if `path` looks absolute.
*
* @param {String} path
* @return {Boolean}
* @api private
*/
exports.isAbsolute = function(path){
if ('/' == path[0]) return true;
if (':' == path[1] && '\\' == path[2]) return true;
};
/**
* Flatten the given `arr`.
*
* @param {Array} arr
* @return {Array}
* @api private
*/
exports.flatten = function(arr, ret){
var ret = ret || []
, len = arr.length;
for (var i = 0; i < len; ++i) {
if (Array.isArray(arr[i])) {
exports.flatten(arr[i], ret);
} else {
ret.push(arr[i]);
}
}
return ret;
};
/**
* Normalize the given `type`, for example "html" becomes "text/html".
*
* @param {String} type
* @return {String}
* @api private
*/
exports.normalizeType = function(type){
return ~type.indexOf('/') ? type : mime.lookup(type);
};
/**
* Normalize `types`, for example "html" becomes "text/html".
*
* @param {Array} types
* @return {Array}
* @api private
*/
exports.normalizeTypes = function(types){
var ret = [];
for (var i = 0; i < types.length; ++i) {
ret.push(~types[i].indexOf('/')
? types[i]
: mime.lookup(types[i]));
}
return ret;
};
/**
* Return the acceptable type in `types`, if any.
*
* @param {Array} types
* @param {String} str
* @return {String}
* @api private
*/
exports.acceptsArray = function(types, str){
// accept anything when Accept is not present
if (!str) return types[0];
// parse
var accepted = exports.parseAccept(str)
, normalized = exports.normalizeTypes(types)
, len = accepted.length;
for (var i = 0; i < len; ++i) {
for (var j = 0, jlen = types.length; j < jlen; ++j) {
if (exports.accept(normalized[j].split('/'), accepted[i])) {
return types[j];
}
}
}
};
/**
* Check if `type(s)` are acceptable based on
* the given `str`.
*
* @param {String|Array} type(s)
* @param {String} str
* @return {Boolean|String}
* @api private
*/
exports.accepts = function(type, str){
if ('string' == typeof type) type = type.split(/ *, */);
return exports.acceptsArray(type, str);
};
/**
* Check if `type` array is acceptable for `other`.
*
* @param {Array} type
* @param {Object} other
* @return {Boolean}
* @api private
*/
exports.accept = function(type, other){
return (type[0] == other.type || '*' == other.type)
&& (type[1] == other.subtype || '*' == other.subtype);
};
/**
* Parse accept `str`, returning
* an array objects containing
* `.type` and `.subtype` along
* with the values provided by
* `parseQuality()`.
*
* @param {Type} name
* @return {Type}
* @api private
*/
exports.parseAccept = function(str){
return exports
.parseQuality(str)
.map(function(obj){
var parts = obj.value.split('/');
obj.type = parts[0];
obj.subtype = parts[1];
return obj;
});
};
/**
* Parse quality `str`, returning an
* array of objects with `.value` and
* `.quality`.
*
* @param {Type} name
* @return {Type}
* @api private
*/
exports.parseQuality = function(str){
return str
.split(/ *, */)
.map(quality)
.filter(function(obj){
return obj.quality;
})
.sort(function(a, b){
return b.quality - a.quality;
});
};
/**
* Parse quality `str` returning an
* object with `.value` and `.quality`.
*
* @param {String} str
* @return {Object}
* @api private
*/
function quality(str) {
var parts = str.split(/ *; */)
, val = parts[0];
var q = parts[1]
? parseFloat(parts[1].split(/ *= */)[1])
: 1;
return { value: val, quality: q };
}
/**
* Escape special characters in the given string of html.
*
* @param {String} html
* @return {String}
* @api private
*/
exports.escape = function(html) {
return String(html)
.replace(/&/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
};
/**
* Normalize the given path string,
* returning a regular expression.
*
* An empty array should be passed,
* which will contain the placeholder
* key names. For example "/user/:id" will
* then contain ["id"].
*
* @param {String|RegExp|Array} path
* @param {Array} keys
* @param {Boolean} sensitive
* @param {Boolean} strict
* @return {RegExp}
* @api private
*/
exports.pathRegexp = function(path, keys, sensitive, strict) {
if (path instanceof RegExp) return path;
if (Array.isArray(path)) path = '(' + path.join('|') + ')';
path = path
.concat(strict ? '' : '/?')
.replace(/\/\(/g, '(?:/')
.replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?(\*)?/g, function(_, slash, format, key, capture, optional, star){
keys.push({ name: key, optional: !! optional });
slash = slash || '';
return ''
+ (optional ? '' : slash)
+ '(?:'
+ (optional ? slash : '')
+ (format || '') + (capture || (format && '([^/.]+?)' || '([^/]+?)')) + ')'
+ (optional || '')
+ (star ? '(/*)?' : '');
})
.replace(/([\/.])/g, '\\$1')
.replace(/\*/g, '(.*)');
return new RegExp('^' + path + '$', sensitive ? '' : 'i');
}
/**
* Module dependencies.
*/
var path = require('path')
, fs = require('fs')
, utils = require('./utils')
, dirname = path.dirname
, basename = path.basename
, extname = path.extname
, exists = fs.existsSync || path.existsSync
, join = path.join;
/**
* Expose `View`.
*/
module.exports = View;
/**
* Initialize a new `View` with the given `name`.
*
* Options:
*
* - `defaultEngine` the default template engine name
* - `engines` template engine require() cache
* - `root` root path for view lookup
*
* @param {String} name
* @param {Object} options
* @api private
*/
function View(name, options) {
options = options || {};
this.name = name;
this.root = options.root;
var engines = options.engines;
this.defaultEngine = options.defaultEngine;
var ext = this.ext = extname(name);
if (!ext) name += (ext = this.ext = ('.' != this.defaultEngine[0] ? '.' : '') + this.defaultEngine);
this.engine = engines[ext] || (engines[ext] = require(ext.slice(1)).__express);
this.path = this.lookup(name);
}
/**
* Lookup view by the given `path`
*
* @param {String} path
* @return {String}
* @api private
*/
View.prototype.lookup = function(path){
var ext = this.ext;
// <path>.<engine>
if (!utils.isAbsolute(path)) path = join(this.root, path);
if (exists(path)) return path;
// <path>/index.<engine>
path = join(dirname(path), basename(path, ext), 'index' + ext);
if (exists(path)) return path;
};
/**
* Render with the given `options` and callback `fn(err, str)`.
*
* @param {Object} options
* @param {Function} fn
* @api private
*/
View.prototype.render = function(options, fn){
this.engine(this.path, options, fn);
};
(The MIT License)
Copyright (c) 2009-2011 TJ Holowaychuk <[email protected]>
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.
MOCHA_OPTS=
REPORTER = dot
check: test
test: test-unit test-acceptance
test-unit:
@NODE_ENV=test ./node_modules/.bin/mocha \
--reporter $(REPORTER) \
$(MOCHA_OPTS)
test-acceptance:
@NODE_ENV=test ./node_modules/.bin/mocha \
--reporter $(REPORTER) \
--bail \
test/acceptance/*.js
test-cov: lib-cov
@EXPRESS_COV=1 $(MAKE) test REPORTER=html-cov > coverage.html
lib-cov:
@jscoverage lib lib-cov
benchmark:
@./support/bench
clean:
rm -f coverage.html
rm -fr lib-cov
.PHONY: test test-unit test-acceptance benchmark clean
language: node_js
node_js:
- 0.6
- 0.8
notifications:
email:
recipients:
- [email protected]
var Buffer = require('buffer').Buffer;
var CRC_TABLE = [
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
0x2d02ef8d
];
function bufferizeInt(num) {
var tmp = Buffer(4);
tmp.writeInt32BE(num, 0);
return tmp;
}
function _crc32(buf) {
if (!Buffer.isBuffer(buf))
buf = Buffer(buf);
var crc = 0xffffffff;
for (var n = 0; n < buf.length; n++) {
crc = CRC_TABLE[(crc ^ buf[n]) & 0xff] ^ (crc >>> 8);
}
return (crc ^ 0xffffffff);
}
function crc32() {
return bufferizeInt(_crc32.apply(null, arguments));
}
crc32.signed = function () {
return _crc32.apply(null, arguments);
};
crc32.unsigned = function () {
return crc32.apply(null, arguments).readUInt32BE(0);
};
module.exports = crc32;
{
"author": {
"name": "Brian J. Brennan",
"email": "[email protected]",
"url": "http://bjb.io"
},
"name": "buffer-crc32",
"description": "A pure javascript CRC32 algorithm that plays nice with binary data",
"version": "0.1.1",
"homepage": "https://github.com/brianloveswords/buffer-crc32",
"repository": {
"type": "git",
"url": "git://github.com/brianloveswords/buffer-crc32.git"
},
"main": "index.js",
"scripts": {
"test": "./node_modules/.bin/tap tests/*.test.js"
},
"dependencies": {},
"devDependencies": {
"tap": "~0.2.5"
},
"optionalDependencies": {},
"engines": {
"node": "*"
},
"readme": "# buffer-crc32\n\n[![Build Status](https://secure.travis-ci.org/brianloveswords/buffer-crc32.png?branch=master)](http://travis-ci.org/brianloveswords/buffer-crc32)\n\ncrc32 that works with binary data and fancy character sets, outputs\nbuffer, signed or unsigned data and has tests.\n\nDerived from the sample CRC implementation in the PNG specification: http://www.w3.org/TR/PNG/#D-CRCAppendix\n\n# install\n```\nnpm install buffer-crc32\n```\n\n# example\n```js\nvar crc32 = require('buffer-crc32');\n// works with buffers\nvar buf = Buffer([[0x00, 0x73, 0x75, 0x70, 0x20, 0x62, 0x72, 0x6f, 0x00])\ncrc32(buf) // -> <Buffer 94 5a ab 4a>\n\n// has convenience methods for getting signed or unsigned ints\ncrc32.signed(buf) // -> -1805997238\ncrc32.unsigned(buf) // -> 2488970058\n\n// will cast to buffer if given a string, so you can\n// directly use foreign characters safely\ncrc32('自動販売機') // -> <Buffer cb 03 1a c5>\n```\n\n# tests\nThis was tested against the output of zlib's crc32 method. You can run\nthe tests with`npm test` (requires tap)\n",
"readmeFilename": "README.md",
"_id": "[email protected]",
"_from": "[email protected]"
}

buffer-crc32

Build Status

crc32 that works with binary data and fancy character sets, outputs buffer, signed or unsigned data and has tests.

Derived from the sample CRC implementation in the PNG specification: http://www.w3.org/TR/PNG/#D-CRCAppendix

install

npm install buffer-crc32

example

var crc32 = require('buffer-crc32');
// works with buffers
var buf = Buffer([[0x00, 0x73, 0x75, 0x70, 0x20, 0x62, 0x72, 0x6f, 0x00])
crc32(buf) // -> <Buffer 94 5a ab 4a>

// has convenience methods for getting signed or unsigned ints
crc32.signed(buf) // -> -1805997238
crc32.unsigned(buf) // -> 2488970058

// will cast to buffer if given a string, so you can
// directly use foreign characters safely
crc32('自動販売機') // -> <Buffer cb 03 1a c5>

tests

This was tested against the output of zlib's crc32 method. You can run the tests withnpm test (requires tap)

var crc32 = require('..');
var test = require('tap').test;
test('simple crc32 is no problem', function (t) {
var input = Buffer('hey sup bros');
var expected = Buffer([0x47, 0xfa, 0x55, 0x70]);
t.same(crc32(input), expected);
t.end();
});
test('another simple one', function (t) {
var input = Buffer('IEND');
var expected = Buffer([0xae, 0x42, 0x60, 0x82]);
t.same(crc32(input), expected);
t.end();
});
test('slightly more complex', function (t) {
var input = Buffer([0x00, 0x00, 0x00]);
var expected = Buffer([0xff, 0x41, 0xd9, 0x12]);
t.same(crc32(input), expected);
t.end();
});
test('complex crc32 gets calculated like a champ', function (t) {
var input = Buffer('शीर्षक');
var expected = Buffer([0x17, 0xb8, 0xaf, 0xf1]);
t.same(crc32(input), expected);
t.end();
});
test('casts to buffer if necessary', function (t) {
var input = 'शीर्षक';
var expected = Buffer([0x17, 0xb8, 0xaf, 0xf1]);
t.same(crc32(input), expected);
t.end();
});
test('can do unsigned', function (t) {
var input = 'ham sandwich';
var expected = -1891873021;
t.same(crc32.signed(input), expected);
t.end();
});
test('can do signed', function (t) {
var input = 'bear sandwich';
var expected = 3711466352;
t.same(crc32.unsigned(input), expected);
t.end();
});

0.6.1 / 2012-06-01

  • Added: append (yes or no) on confirmation
  • Added: allow node.js v0.7.x

0.6.0 / 2012-04-10

  • Added .prompt(obj, callback) support. Closes #49
  • Added default support to .choose(). Closes #41
  • Fixed the choice example

0.5.1 / 2011-12-20

  • Fixed password() for recent nodes. Closes #36

0.5.0 / 2011-12-04

  • Added sub-command option support [itay]

0.4.3 / 2011-12-04

  • Fixed custom help ordering. Closes #32

0.4.2 / 2011-11-24

  • Added travis support
  • Fixed: line-buffered input automatically trimmed. Closes #31

0.4.1 / 2011-11-18

  • Removed listening for "close" on --help

0.4.0 / 2011-11-15

  • Added support for --. Closes #24

0.3.3 / 2011-11-14

  • Fixed: wait for close event when writing help info [Jerry Hamlet]

0.3.2 / 2011-11-01

  • Fixed long flag definitions with values [felixge]

0.3.1 / 2011-10-31

  • Changed --version short flag to -V from -v
  • Changed .version() so it's configurable [felixge]

0.3.0 / 2011-10-31

  • Added support for long flags only. Closes #18

0.2.1 / 2011-10-24

  • "node": ">= 0.4.x < 0.7.0". Closes #20

0.2.0 / 2011-09-26

  • Allow for defaults that are not just boolean. Default peassignment only occurs for --no-*, optional, and required arguments. [Jim Isaacs]

0.1.0 / 2011-08-24

  • Added support for custom --help output

0.0.5 / 2011-08-18

  • Changed: when the user enters nothing prompt for password again
  • Fixed issue with passwords beginning with numbers [NuckChorris]

0.0.4 / 2011-08-15

  • Fixed Commander#args

0.0.3 / 2011-08-15

  • Added default option value support

0.0.2 / 2011-08-15

  • Added mask support to Command#password(str[, mask], fn)
  • Added Command#password(str, fn)

0.0.1 / 2010-01-03

  • Initial release
/*!
* commander
* Copyright(c) 2011 TJ Holowaychuk <[email protected]>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var EventEmitter = require('events').EventEmitter
, path = require('path')
, tty = require('tty')
, basename = path.basename;
/**
* Expose the root command.
*/
exports = module.exports = new Command;
/**
* Expose `Command`.
*/
exports.Command = Command;
/**
* Expose `Option`.
*/
exports.Option = Option;
/**
* Initialize a new `Option` with the given `flags` and `description`.
*
* @param {String} flags
* @param {String} description
* @api public
*/
function Option(flags, description) {
this.flags = flags;
this.required = ~flags.indexOf('<');
this.optional = ~flags.indexOf('[');
this.bool = !~flags.indexOf('-no-');
flags = flags.split(/[ ,|]+/);
if (flags.length > 1 && !/^[[<]/.test(flags[1])) this.short = flags.shift();
this.long = flags.shift();
this.description = description;
}
/**
* Return option name.
*
* @return {String}
* @api private
*/
Option.prototype.name = function(){
return this.long
.replace('--', '')
.replace('no-', '');
};
/**
* Check if `arg` matches the short or long flag.
*
* @param {String} arg
* @return {Boolean}
* @api private
*/
Option.prototype.is = function(arg){
return arg == this.short
|| arg == this.long;
};
/**
* Initialize a new `Command`.
*
* @param {String} name
* @api public
*/
function Command(name) {
this.commands = [];
this.options = [];
this.args = [];
this.name = name;
}
/**
* Inherit from `EventEmitter.prototype`.
*/
Command.prototype.__proto__ = EventEmitter.prototype;
/**
* Add command `name`.
*
* The `.action()` callback is invoked when the
* command `name` is specified via __ARGV__,
* and the remaining arguments are applied to the
* function for access.
*
* When the `name` is "*" an un-matched command
* will be passed as the first arg, followed by
* the rest of __ARGV__ remaining.
*
* Examples:
*
* program
* .version('0.0.1')
* .option('-C, --chdir <path>', 'change the working directory')
* .option('-c, --config <path>', 'set config path. defaults to ./deploy.conf')
* .option('-T, --no-tests', 'ignore test hook')
*
* program
* .command('setup')
* .description('run remote setup commands')
* .action(function(){
* console.log('setup');
* });
*
* program
* .command('exec <cmd>')
* .description('run the given remote command')
* .action(function(cmd){
* console.log('exec "%s"', cmd);
* });
*
* program
* .command('*')
* .description('deploy the given env')
* .action(function(env){
* console.log('deploying "%s"', env);
* });
*
* program.parse(process.argv);
*
* @param {String} name
* @return {Command} the new command
* @api public
*/
Command.prototype.command = function(name){
var args = name.split(/ +/);
var cmd = new Command(args.shift());
this.commands.push(cmd);
cmd.parseExpectedArgs(args);
cmd.parent = this;
return cmd;
};
/**
* Parse expected `args`.
*
* For example `["[type]"]` becomes `[{ required: false, name: 'type' }]`.
*
* @param {Array} args
* @return {Command} for chaining
* @api public
*/
Command.prototype.parseExpectedArgs = function(args){
if (!args.length) return;
var self = this;
args.forEach(function(arg){
switch (arg[0]) {
case '<':
self.args.push({ required: true, name: arg.slice(1, -1) });
break;
case '[':
self.args.push({ required: false, name: arg.slice(1, -1) });
break;
}
});
return this;
};
/**
* Register callback `fn` for the command.
*
* Examples:
*
* program
* .command('help')
* .description('display verbose help')
* .action(function(){
* // output help here
* });
*
* @param {Function} fn
* @return {Command} for chaining
* @api public
*/
Command.prototype.action = function(fn){
var self = this;
this.parent.on(this.name, function(args, unknown){
// Parse any so-far unknown options
unknown = unknown || [];
var parsed = self.parseOptions(unknown);
// Output help if necessary
outputHelpIfNecessary(self, parsed.unknown);
// If there are still any unknown options, then we simply
// die, unless someone asked for help, in which case we give it
// to them, and then we die.
if (parsed.unknown.length > 0) {
self.unknownOption(parsed.unknown[0]);
}
self.args.forEach(function(arg, i){
if (arg.required && null == args[i]) {
self.missingArgument(arg.name);
}
});
// Always append ourselves to the end of the arguments,
// to make sure we match the number of arguments the user
// expects
if (self.args.length) {
args[self.args.length] = self;
} else {
args.push(self);
}
fn.apply(this, args);
});
return this;
};
/**
* Define option with `flags`, `description` and optional
* coercion `fn`.
*
* The `flags` string should contain both the short and long flags,
* separated by comma, a pipe or space. The following are all valid
* all will output this way when `--help` is used.
*
* "-p, --pepper"
* "-p|--pepper"
* "-p --pepper"
*
* Examples:
*
* // simple boolean defaulting to false
* program.option('-p, --pepper', 'add pepper');
*
* --pepper
* program.pepper
* // => Boolean
*
* // simple boolean defaulting to false
* program.option('-C, --no-cheese', 'remove cheese');
*
* program.cheese
* // => true
*
* --no-cheese
* program.cheese
* // => true
*
* // required argument
* program.option('-C, --chdir <path>', 'change the working directory');
*
* --chdir /tmp
* program.chdir
* // => "/tmp"
*
* // optional argument
* program.option('-c, --cheese [type]', 'add cheese [marble]');
*
* @param {String} flags
* @param {String} description
* @param {Function|Mixed} fn or default
* @param {Mixed} defaultValue
* @return {Command} for chaining
* @api public
*/
Command.prototype.option = function(flags, description, fn, defaultValue){
var self = this
, option = new Option(flags, description)
, oname = option.name()
, name = camelcase(oname);
// default as 3rd arg
if ('function' != typeof fn) defaultValue = fn, fn = null;
// preassign default value only for --no-*, [optional], or <required>
if (false == option.bool || option.optional || option.required) {
// when --no-* we make sure default is true
if (false == option.bool) defaultValue = true;
// preassign only if we have a default
if (undefined !== defaultValue) self[name] = defaultValue;
}
// register the option
this.options.push(option);
// when it's passed assign the value
// and conditionally invoke the callback
this.on(oname, function(val){
// coercion
if (null != val && fn) val = fn(val);
// unassigned or bool
if ('boolean' == typeof self[name] || 'undefined' == typeof self[name]) {
// if no value, bool true, and we have a default, then use it!
if (null == val) {
self[name] = option.bool
? defaultValue || true
: false;
} else {
self[name] = val;
}
} else if (null !== val) {
// reassign
self[name] = val;
}
});
return this;
};
/**
* Parse `argv`, settings options and invoking commands when defined.
*
* @param {Array} argv
* @return {Command} for chaining
* @api public
*/
Command.prototype.parse = function(argv){
// store raw args
this.rawArgs = argv;
// guess name
if (!this.name) this.name = basename(argv[1]);
// process argv
var parsed = this.parseOptions(this.normalize(argv.slice(2)));
this.args = parsed.args;
return this.parseArgs(this.args, parsed.unknown);
};
/**
* Normalize `args`, splitting joined short flags. For example
* the arg "-abc" is equivalent to "-a -b -c".
*
* @param {Array} args
* @return {Array}
* @api private
*/
Command.prototype.normalize = function(args){
var ret = []
, arg;
for (var i = 0, len = args.length; i < len; ++i) {
arg = args[i];
if (arg.length > 1 && '-' == arg[0] && '-' != arg[1]) {
arg.slice(1).split('').forEach(function(c){
ret.push('-' + c);
});
} else {
ret.push(arg);
}
}
return ret;
};
/**
* Parse command `args`.
*
* When listener(s) are available those
* callbacks are invoked, otherwise the "*"
* event is emitted and those actions are invoked.
*
* @param {Array} args
* @return {Command} for chaining
* @api private
*/
Command.prototype.parseArgs = function(args, unknown){
var cmds = this.commands
, len = cmds.length
, name;
if (args.length) {
name = args[0];
if (this.listeners(name).length) {
this.emit(args.shift(), args, unknown);
} else {
this.emit('*', args);
}
} else {
outputHelpIfNecessary(this, unknown);
// If there were no args and we have unknown options,
// then they are extraneous and we need to error.
if (unknown.length > 0) {
this.unknownOption(unknown[0]);
}
}
return this;
};
/**
* Return an option matching `arg` if any.
*
* @param {String} arg
* @return {Option}
* @api private
*/
Command.prototype.optionFor = function(arg){
for (var i = 0, len = this.options.length; i < len; ++i) {
if (this.options[i].is(arg)) {
return this.options[i];
}
}
};
/**
* Parse options from `argv` returning `argv`
* void of these options.
*
* @param {Array} argv
* @return {Array}
* @api public
*/
Command.prototype.parseOptions = function(argv){
var args = []
, len = argv.length
, literal
, option
, arg;
var unknownOptions = [];
// parse options
for (var i = 0; i < len; ++i) {
arg = argv[i];
// literal args after --
if ('--' == arg) {
literal = true;
continue;
}
if (literal) {
args.push(arg);
continue;
}
// find matching Option
option = this.optionFor(arg);
// option is defined
if (option) {
// requires arg
if (option.required) {
arg = argv[++i];
if (null == arg) return this.optionMissingArgument(option);
if ('-' == arg[0]) return this.optionMissingArgument(option, arg);
this.emit(option.name(), arg);
// optional arg
} else if (option.optional) {
arg = argv[i+1];
if (null == arg || '-' == arg[0]) {
arg = null;
} else {
++i;
}
this.emit(option.name(), arg);
// bool
} else {
this.emit(option.name());
}
continue;
}
// looks like an option
if (arg.length > 1 && '-' == arg[0]) {
unknownOptions.push(arg);
// If the next argument looks like it might be
// an argument for this option, we pass it on.
// If it isn't, then it'll simply be ignored
if (argv[i+1] && '-' != argv[i+1][0]) {
unknownOptions.push(argv[++i]);
}
continue;
}
// arg
args.push(arg);
}
return { args: args, unknown: unknownOptions };
};
/**
* Argument `name` is missing.
*
* @param {String} name
* @api private
*/
Command.prototype.missingArgument = function(name){
console.error();
console.error(" error: missing required argument `%s'", name);
console.error();
process.exit(1);
};
/**
* `Option` is missing an argument, but received `flag` or nothing.
*
* @param {String} option
* @param {String} flag
* @api private
*/
Command.prototype.optionMissingArgument = function(option, flag){
console.error();
if (flag) {
console.error(" error: option `%s' argument missing, got `%s'", option.flags, flag);
} else {
console.error(" error: option `%s' argument missing", option.flags);
}
console.error();
process.exit(1);
};
/**
* Unknown option `flag`.
*
* @param {String} flag
* @api private
*/
Command.prototype.unknownOption = function(flag){
console.error();
console.error(" error: unknown option `%s'", flag);
console.error();
process.exit(1);
};
/**
* Set the program version to `str`.
*
* This method auto-registers the "-V, --version" flag
* which will print the version number when passed.
*
* @param {String} str
* @param {String} flags
* @return {Command} for chaining
* @api public
*/
Command.prototype.version = function(str, flags){
if (0 == arguments.length) return this._version;
this._version = str;
flags = flags || '-V, --version';
this.option(flags, 'output the version number');
this.on('version', function(){
console.log(str);
process.exit(0);
});
return this;
};
/**
* Set the description `str`.
*
* @param {String} str
* @return {String|Command}
* @api public
*/
Command.prototype.description = function(str){
if (0 == arguments.length) return this._description;
this._description = str;
return this;
};
/**
* Set / get the command usage `str`.
*
* @param {String} str
* @return {String|Command}
* @api public
*/
Command.prototype.usage = function(str){
var args = this.args.map(function(arg){
return arg.required
? '<' + arg.name + '>'
: '[' + arg.name + ']';
});
var usage = '[options'
+ (this.commands.length ? '] [command' : '')
+ ']'
+ (this.args.length ? ' ' + args : '');
if (0 == arguments.length) return this._usage || usage;
this._usage = str;
return this;
};
/**
* Return the largest option length.
*
* @return {Number}
* @api private
*/
Command.prototype.largestOptionLength = function(){
return this.options.reduce(function(max, option){
return Math.max(max, option.flags.length);
}, 0);
};
/**
* Return help for options.
*
* @return {String}
* @api private
*/
Command.prototype.optionHelp = function(){
var width = this.largestOptionLength();
// Prepend the help information
return [pad('-h, --help', width) + ' ' + 'output usage information']
.concat(this.options.map(function(option){
return pad(option.flags, width)
+ ' ' + option.description;
}))
.join('\n');
};
/**
* Return command help documentation.
*
* @return {String}
* @api private
*/
Command.prototype.commandHelp = function(){
if (!this.commands.length) return '';
return [
''
, ' Commands:'
, ''
, this.commands.map(function(cmd){
var args = cmd.args.map(function(arg){
return arg.required
? '<' + arg.name + '>'
: '[' + arg.name + ']';
}).join(' ');
return cmd.name
+ (cmd.options.length
? ' [options]'
: '') + ' ' + args
+ (cmd.description()
? '\n' + cmd.description()
: '');
}).join('\n\n').replace(/^/gm, ' ')
, ''
].join('\n');
};
/**
* Return program help documentation.
*
* @return {String}
* @api private
*/
Command.prototype.helpInformation = function(){
return [
''
, ' Usage: ' + this.name + ' ' + this.usage()
, '' + this.commandHelp()
, ' Options:'
, ''
, '' + this.optionHelp().replace(/^/gm, ' ')
, ''
, ''
].join('\n');
};
/**
* Prompt for a `Number`.
*
* @param {String} str
* @param {Function} fn
* @api private
*/
Command.prototype.promptForNumber = function(str, fn){
var self = this;
this.promptSingleLine(str, function parseNumber(val){
val = Number(val);
if (isNaN(val)) return self.promptSingleLine(str + '(must be a number) ', parseNumber);
fn(val);
});
};
/**
* Prompt for a `Date`.
*
* @param {String} str
* @param {Function} fn
* @api private
*/
Command.prototype.promptForDate = function(str, fn){
var self = this;
this.promptSingleLine(str, function parseDate(val){
val = new Date(val);
if (isNaN(val.getTime())) return self.promptSingleLine(str + '(must be a date) ', parseDate);
fn(val);
});
};
/**
* Single-line prompt.
*
* @param {String} str
* @param {Function} fn
* @api private
*/
Command.prototype.promptSingleLine = function(str, fn){
if ('function' == typeof arguments[2]) {
return this['promptFor' + (fn.name || fn)](str, arguments[2]);
}
process.stdout.write(str);
process.stdin.setEncoding('utf8');
process.stdin.once('data', function(val){
fn(val.trim());
}).resume();
};
/**
* Multi-line prompt.
*
* @param {String} str
* @param {Function} fn
* @api private
*/
Command.prototype.promptMultiLine = function(str, fn){
var buf = [];
console.log(str);
process.stdin.setEncoding('utf8');
process.stdin.on('data', function(val){
if ('\n' == val || '\r\n' == val) {
process.stdin.removeAllListeners('data');
fn(buf.join('\n'));
} else {
buf.push(val.trimRight());
}
}).resume();
};
/**
* Prompt `str` and callback `fn(val)`
*
* Commander supports single-line and multi-line prompts.
* To issue a single-line prompt simply add white-space
* to the end of `str`, something like "name: ", whereas
* for a multi-line prompt omit this "description:".
*
*
* Examples:
*
* program.prompt('Username: ', function(name){
* console.log('hi %s', name);
* });
*
* program.prompt('Description:', function(desc){
* console.log('description was "%s"', desc.trim());
* });
*
* @param {String|Object} str
* @param {Function} fn
* @api public
*/
Command.prototype.prompt = function(str, fn){
var self = this;
if ('string' == typeof str) {
if (/ $/.test(str)) return this.promptSingleLine.apply(this, arguments);
this.promptMultiLine(str, fn);
} else {
var keys = Object.keys(str)
, obj = {};
function next() {
var key = keys.shift()
, label = str[key];
if (!key) return fn(obj);
self.prompt(label, function(val){
obj[key] = val;
next();
});
}
next();
}
};
/**
* Prompt for password with `str`, `mask` char and callback `fn(val)`.
*
* The mask string defaults to '', aka no output is
* written while typing, you may want to use "*" etc.
*
* Examples:
*
* program.password('Password: ', function(pass){
* console.log('got "%s"', pass);
* process.stdin.destroy();
* });
*
* program.password('Password: ', '*', function(pass){
* console.log('got "%s"', pass);
* process.stdin.destroy();
* });
*
* @param {String} str
* @param {String} mask
* @param {Function} fn
* @api public
*/
Command.prototype.password = function(str, mask, fn){
var self = this
, buf = '';
// default mask
if ('function' == typeof mask) {
fn = mask;
mask = '';
}
process.stdin.resume();
tty.setRawMode(true);
process.stdout.write(str);
// keypress
process.stdin.on('keypress', function(c, key){
if (key && 'enter' == key.name) {
console.log();
process.stdin.removeAllListeners('keypress');
tty.setRawMode(false);
if (!buf.trim().length) return self.password(str, mask, fn);
fn(buf);
return;
}
if (key && key.ctrl && 'c' == key.name) {
console.log('%s', buf);
process.exit();
}
process.stdout.write(mask);
buf += c;
}).resume();
};
/**
* Confirmation prompt with `str` and callback `fn(bool)`
*
* Examples:
*
* program.confirm('continue? ', function(ok){
* console.log(' got %j', ok);
* process.stdin.destroy();
* });
*
* @param {String} str
* @param {Function} fn
* @api public
*/
Command.prototype.confirm = function(str, fn, verbose){
var self = this;
this.prompt(str, function(ok){
if (!ok.trim()) {
if (!verbose) str += '(yes or no) ';
return self.confirm(str, fn, true);
}
fn(parseBool(ok));
});
};
/**
* Choice prompt with `list` of items and callback `fn(index, item)`
*
* Examples:
*
* var list = ['tobi', 'loki', 'jane', 'manny', 'luna'];
*
* console.log('Choose the coolest pet:');
* program.choose(list, function(i){
* console.log('you chose %d "%s"', i, list[i]);
* process.stdin.destroy();
* });
*
* @param {Array} list
* @param {Number|Function} index or fn
* @param {Function} fn
* @api public
*/
Command.prototype.choose = function(list, index, fn){
var self = this
, hasDefault = 'number' == typeof index;
if (!hasDefault) {
fn = index;
index = null;
}
list.forEach(function(item, i){
if (hasDefault && i == index) {
console.log('* %d) %s', i + 1, item);
} else {
console.log(' %d) %s', i + 1, item);
}
});
function again() {
self.prompt(' : ', function(val){
val = parseInt(val, 10) - 1;
if (hasDefault && isNaN(val)) val = index;
if (null == list[val]) {
again();
} else {
fn(val, list[val]);
}
});
}
again();
};
/**
* Camel-case the given `flag`
*
* @param {String} flag
* @return {String}
* @api private
*/
function camelcase(flag) {
return flag.split('-').reduce(function(str, word){
return str + word[0].toUpperCase() + word.slice(1);
});
}
/**
* Parse a boolean `str`.
*
* @param {String} str
* @return {Boolean}
* @api private
*/
function parseBool(str) {
return /^y|yes|ok|true$/i.test(str);
}
/**
* Pad `str` to `width`.
*
* @param {String} str
* @param {Number} width
* @return {String}
* @api private
*/
function pad(str, width) {
var len = Math.max(0, width - str.length);
return str + Array(len + 1).join(' ');
}
/**
* Output help information if necessary
*
* @param {Command} command to output help for
* @param {Array} array of options to search for -h or --help
* @api private
*/
function outputHelpIfNecessary(cmd, options) {
options = options || [];
for (var i = 0; i < options.length; i++) {
if (options[i] == '--help' || options[i] == '-h') {
process.stdout.write(cmd.helpInformation());
cmd.emit('--help');
process.exit(0);
}
}
}
TESTS = $(shell find test/test.*.js)
test:
@./test/run $(TESTS)
.PHONY: test
{
"name": "commander",
"version": "0.6.1",
"description": "the complete solution for node.js command-line programs",
"keywords": [
"command",
"option",
"parser",
"prompt",
"stdin"
],
"author": {
"name": "TJ Holowaychuk",
"email": "[email protected]"
},
"repository": {
"type": "git",
"url": "https://github.com/visionmedia/commander.js.git"
},
"dependencies": {},
"devDependencies": {
"should": ">= 0.0.1"
},
"scripts": {
"test": "make test"
},
"main": "index",
"engines": {
"node": ">= 0.4.x"
},
"readme": "# Commander.js\n\n The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/visionmedia/commander).\n\n [![Build Status](https://secure.travis-ci.org/visionmedia/commander.js.png)](http://travis-ci.org/visionmedia/commander.js)\n\n## Installation\n\n $ npm install commander\n\n## Option parsing\n\n Options with commander are defined with the `.option()` method, also serving as documentation for the options. The example below parses args and options from `process.argv`, leaving remaining args as the `program.args` array which were not consumed by options.\n\n```js\n#!/usr/bin/env node\n\n/**\n * Module dependencies.\n */\n\nvar program = require('commander');\n\nprogram\n .version('0.0.1')\n .option('-p, --peppers', 'Add peppers')\n .option('-P, --pineapple', 'Add pineapple')\n .option('-b, --bbq', 'Add bbq sauce')\n .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')\n .parse(process.argv);\n\nconsole.log('you ordered a pizza with:');\nif (program.peppers) console.log(' - peppers');\nif (program.pineapple) console.log(' - pineappe');\nif (program.bbq) console.log(' - bbq');\nconsole.log(' - %s cheese', program.cheese);\n```\n\n Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as \"--template-engine\" are camel-cased, becoming `program.templateEngine` etc.\n\n## Automated --help\n\n The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free:\n\n``` \n $ ./examples/pizza --help\n\n Usage: pizza [options]\n\n Options:\n\n -V, --version output the version number\n -p, --peppers Add peppers\n -P, --pineapple Add pineappe\n -b, --bbq Add bbq sauce\n -c, --cheese <type> Add the specified type of cheese [marble]\n -h, --help output usage information\n\n```\n\n## Coercion\n\n```js\nfunction range(val) {\n return val.split('..').map(Number);\n}\n\nfunction list(val) {\n return val.split(',');\n}\n\nprogram\n .version('0.0.1')\n .usage('[options] <file ...>')\n .option('-i, --integer <n>', 'An integer argument', parseInt)\n .option('-f, --float <n>', 'A float argument', parseFloat)\n .option('-r, --range <a>..<b>', 'A range', range)\n .option('-l, --list <items>', 'A list', list)\n .option('-o, --optional [value]', 'An optional value')\n .parse(process.argv);\n\nconsole.log(' int: %j', program.integer);\nconsole.log(' float: %j', program.float);\nconsole.log(' optional: %j', program.optional);\nprogram.range = program.range || [];\nconsole.log(' range: %j..%j', program.range[0], program.range[1]);\nconsole.log(' list: %j', program.list);\nconsole.log(' args: %j', program.args);\n```\n\n## Custom help\n\n You can display arbitrary `-h, --help` information\n by listening for \"--help\". Commander will automatically\n exit once you are done so that the remainder of your program\n does not execute causing undesired behaviours, for example\n in the following executable \"stuff\" will not output when\n `--help` is used.\n\n```js\n#!/usr/bin/env node\n\n/**\n * Module dependencies.\n */\n\nvar program = require('../');\n\nfunction list(val) {\n return val.split(',').map(Number);\n}\n\nprogram\n .version('0.0.1')\n .option('-f, --foo', 'enable some foo')\n .option('-b, --bar', 'enable some bar')\n .option('-B, --baz', 'enable some baz');\n\n// must be before .parse() since\n// node's emit() is immediate\n\nprogram.on('--help', function(){\n console.log(' Examples:');\n console.log('');\n console.log(' $ custom-help --help');\n console.log(' $ custom-help -h');\n console.log('');\n});\n\nprogram.parse(process.argv);\n\nconsole.log('stuff');\n```\n\nyielding the following help output:\n\n```\n\nUsage: custom-help [options]\n\nOptions:\n\n -h, --help output usage information\n -V, --version output the version number\n -f, --foo enable some foo\n -b, --bar enable some bar\n -B, --baz enable some baz\n\nExamples:\n\n $ custom-help --help\n $ custom-help -h\n\n```\n\n## .prompt(msg, fn)\n\n Single-line prompt:\n\n```js\nprogram.prompt('name: ', function(name){\n console.log('hi %s', name);\n});\n```\n\n Multi-line prompt:\n\n```js\nprogram.prompt('description:', function(name){\n console.log('hi %s', name);\n});\n```\n\n Coercion:\n\n```js\nprogram.prompt('Age: ', Number, function(age){\n console.log('age: %j', age);\n});\n```\n\n```js\nprogram.prompt('Birthdate: ', Date, function(date){\n console.log('date: %s', date);\n});\n```\n\n## .password(msg[, mask], fn)\n\nPrompt for password without echoing:\n\n```js\nprogram.password('Password: ', function(pass){\n console.log('got \"%s\"', pass);\n process.stdin.destroy();\n});\n```\n\nPrompt for password with mask char \"*\":\n\n```js\nprogram.password('Password: ', '*', function(pass){\n console.log('got \"%s\"', pass);\n process.stdin.destroy();\n});\n```\n\n## .confirm(msg, fn)\n\n Confirm with the given `msg`:\n\n```js\nprogram.confirm('continue? ', function(ok){\n console.log(' got %j', ok);\n});\n```\n\n## .choose(list, fn)\n\n Let the user choose from a `list`:\n\n```js\nvar list = ['tobi', 'loki', 'jane', 'manny', 'luna'];\n\nconsole.log('Choose the coolest pet:');\nprogram.choose(list, function(i){\n console.log('you chose %d \"%s\"', i, list[i]);\n});\n```\n\n## Links\n\n - [API documentation](http://visionmedia.github.com/commander.js/)\n - [ascii tables](https://github.com/LearnBoost/cli-table)\n - [progress bars](https://github.com/visionmedia/node-progress)\n - [more progress bars](https://github.com/substack/node-multimeter)\n - [examples](https://github.com/visionmedia/commander.js/tree/master/examples)\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2011 TJ Holowaychuk &lt;[email protected]&gt;\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.",
"readmeFilename": "Readme.md",
"_id": "[email protected]",
"_from": "[email protected]"
}

Commander.js

The complete solution for node.js command-line interfaces, inspired by Ruby's commander.

Build Status

Installation

$ npm install commander

Option parsing

Options with commander are defined with the .option() method, also serving as documentation for the options. The example below parses args and options from process.argv, leaving remaining args as the program.args array which were not consumed by options.

#!/usr/bin/env node

/**
 * Module dependencies.
 */

var program = require('commander');

program
  .version('0.0.1')
  .option('-p, --peppers', 'Add peppers')
  .option('-P, --pineapple', 'Add pineapple')
  .option('-b, --bbq', 'Add bbq sauce')
  .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')
  .parse(process.argv);

console.log('you ordered a pizza with:');
if (program.peppers) console.log('  - peppers');
if (program.pineapple) console.log('  - pineappe');
if (program.bbq) console.log('  - bbq');
console.log('  - %s cheese', program.cheese);

Short flags may be passed as a single arg, for example -abc is equivalent to -a -b -c. Multi-word options such as "--template-engine" are camel-cased, becoming program.templateEngine etc.

Automated --help

The help information is auto-generated based on the information commander already knows about your program, so the following --help info is for free:

 $ ./examples/pizza --help

   Usage: pizza [options]

   Options:

     -V, --version        output the version number
     -p, --peppers        Add peppers
     -P, --pineapple      Add pineappe
     -b, --bbq            Add bbq sauce
     -c, --cheese <type>  Add the specified type of cheese [marble]
     -h, --help           output usage information

Coercion

function range(val) {
  return val.split('..').map(Number);
}

function list(val) {
  return val.split(',');
}

program
  .version('0.0.1')
  .usage('[options] <file ...>')
  .option('-i, --integer <n>', 'An integer argument', parseInt)
  .option('-f, --float <n>', 'A float argument', parseFloat)
  .option('-r, --range <a>..<b>', 'A range', range)
  .option('-l, --list <items>', 'A list', list)
  .option('-o, --optional [value]', 'An optional value')
  .parse(process.argv);

console.log(' int: %j', program.integer);
console.log(' float: %j', program.float);
console.log(' optional: %j', program.optional);
program.range = program.range || [];
console.log(' range: %j..%j', program.range[0], program.range[1]);
console.log(' list: %j', program.list);
console.log(' args: %j', program.args);

Custom help

You can display arbitrary -h, --help information by listening for "--help". Commander will automatically exit once you are done so that the remainder of your program does not execute causing undesired behaviours, for example in the following executable "stuff" will not output when --help is used.

#!/usr/bin/env node

/**
 * Module dependencies.
 */

var program = require('../');

function list(val) {
  return val.split(',').map(Number);
}

program
  .version('0.0.1')
  .option('-f, --foo', 'enable some foo')
  .option('-b, --bar', 'enable some bar')
  .option('-B, --baz', 'enable some baz');

// must be before .parse() since
// node's emit() is immediate

program.on('--help', function(){
  console.log('  Examples:');
  console.log('');
  console.log('    $ custom-help --help');
  console.log('    $ custom-help -h');
  console.log('');
});

program.parse(process.argv);

console.log('stuff');

yielding the following help output:


Usage: custom-help [options]

Options:

  -h, --help     output usage information
  -V, --version  output the version number
  -f, --foo      enable some foo
  -b, --bar      enable some bar
  -B, --baz      enable some baz

Examples:

  $ custom-help --help
  $ custom-help -h

.prompt(msg, fn)

Single-line prompt:

program.prompt('name: ', function(name){
  console.log('hi %s', name);
});

Multi-line prompt:

program.prompt('description:', function(name){
  console.log('hi %s', name);
});

Coercion:

program.prompt('Age: ', Number, function(age){
  console.log('age: %j', age);
});
program.prompt('Birthdate: ', Date, function(date){
  console.log('date: %s', date);
});

.password(msg[, mask], fn)

Prompt for password without echoing:

program.password('Password: ', function(pass){
  console.log('got "%s"', pass);
  process.stdin.destroy();
});

Prompt for password with mask char "*":

program.password('Password: ', '*', function(pass){
  console.log('got "%s"', pass);
  process.stdin.destroy();
});

.confirm(msg, fn)

Confirm with the given msg:

program.confirm('continue? ', function(ok){
  console.log(' got %j', ok);
});

.choose(list, fn)

Let the user choose from a list:

var list = ['tobi', 'loki', 'jane', 'manny', 'luna'];

console.log('Choose the coolest pet:');
program.choose(list, function(i){
  console.log('you chose %d "%s"', i, list[i]);
});

Links

License

(The MIT License)

Copyright (c) 2011 TJ Holowaychuk <[email protected]>

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.

*.markdown
*.md
.git*
Makefile
benchmarks/
docs/
examples/
install.sh
support/
test/
.DS_Store
coverage.html
module.exports = process.env.CONNECT_COV
? require('./lib-cov/connect')
: require('./lib/connect');
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['cache.js']) {
_$jscoverage['cache.js'] = [];
_$jscoverage['cache.js'][12] = 0;
_$jscoverage['cache.js'][21] = 0;
_$jscoverage['cache.js'][22] = 0;
_$jscoverage['cache.js'][23] = 0;
_$jscoverage['cache.js'][24] = 0;
_$jscoverage['cache.js'][35] = 0;
_$jscoverage['cache.js'][36] = 0;
_$jscoverage['cache.js'][37] = 0;
_$jscoverage['cache.js'][47] = 0;
_$jscoverage['cache.js'][48] = 0;
_$jscoverage['cache.js'][59] = 0;
_$jscoverage['cache.js'][60] = 0;
_$jscoverage['cache.js'][71] = 0;
_$jscoverage['cache.js'][73] = 0;
_$jscoverage['cache.js'][76] = 0;
_$jscoverage['cache.js'][78] = 0;
_$jscoverage['cache.js'][79] = 0;
_$jscoverage['cache.js'][80] = 0;
}
_$jscoverage['cache.js'][12]++;
module.exports = Cache;
_$jscoverage['cache.js'][21]++;
function Cache(limit) {
_$jscoverage['cache.js'][22]++;
this.store = {};
_$jscoverage['cache.js'][23]++;
this.keys = [];
_$jscoverage['cache.js'][24]++;
this.limit = limit;
}
_$jscoverage['cache.js'][35]++;
Cache.prototype.touch = (function (key, i) {
_$jscoverage['cache.js'][36]++;
this.keys.splice(i, 1);
_$jscoverage['cache.js'][37]++;
this.keys.push(key);
});
_$jscoverage['cache.js'][47]++;
Cache.prototype.remove = (function (key) {
_$jscoverage['cache.js'][48]++;
delete this.store[key];
});
_$jscoverage['cache.js'][59]++;
Cache.prototype.get = (function (key) {
_$jscoverage['cache.js'][60]++;
return this.store[key];
});
_$jscoverage['cache.js'][71]++;
Cache.prototype.add = (function (key) {
_$jscoverage['cache.js'][73]++;
var len = this.keys.push(key);
_$jscoverage['cache.js'][76]++;
if (len > this.limit) {
_$jscoverage['cache.js'][76]++;
this.remove(this.keys.shift());
}
_$jscoverage['cache.js'][78]++;
var arr = this.store[key] = [];
_$jscoverage['cache.js'][79]++;
arr.createdAt = new Date();
_$jscoverage['cache.js'][80]++;
return arr;
});
_$jscoverage['cache.js'].source = ["","/*!"," * Connect - Cache"," * Copyright(c) 2011 Sencha Inc."," * MIT Licensed"," */","","/**"," * Expose `Cache`."," */","","module.exports = Cache;","","/**"," * LRU cache store."," *"," * @param {Number} limit"," * @api private"," */","","function Cache(limit) {"," this.store = {};"," this.keys = [];"," this.limit = limit;","}","","/**"," * Touch `key`, promoting the object."," *"," * @param {String} key"," * @param {Number} i"," * @api private"," */","","Cache.prototype.touch = function(key, i){"," this.keys.splice(i,1);"," this.keys.push(key);","};","","/**"," * Remove `key`."," *"," * @param {String} key"," * @api private"," */","","Cache.prototype.remove = function(key){"," delete this.store[key];","};","","/**"," * Get the object stored for `key`."," *"," * @param {String} key"," * @return {Array}"," * @api private"," */","","Cache.prototype.get = function(key){"," return this.store[key];","};","","/**"," * Add a cache `key`."," *"," * @param {String} key"," * @return {Array}"," * @api private"," */","","Cache.prototype.add = function(key){"," // initialize store"," var len = this.keys.push(key);",""," // limit reached, invalidate LRU"," if (len &gt; this.limit) this.remove(this.keys.shift());",""," var arr = this.store[key] = [];"," arr.createdAt = new Date;"," return arr;","};"];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['connect.js']) {
_$jscoverage['connect.js'] = [];
_$jscoverage['connect.js'][13] = 0;
_$jscoverage['connect.js'][22] = 0;
_$jscoverage['connect.js'][26] = 0;
_$jscoverage['connect.js'][32] = 0;
_$jscoverage['connect.js'][38] = 0;
_$jscoverage['connect.js'][44] = 0;
_$jscoverage['connect.js'][50] = 0;
_$jscoverage['connect.js'][56] = 0;
_$jscoverage['connect.js'][65] = 0;
_$jscoverage['connect.js'][66] = 0;
_$jscoverage['connect.js'][67] = 0;
_$jscoverage['connect.js'][68] = 0;
_$jscoverage['connect.js'][69] = 0;
_$jscoverage['connect.js'][70] = 0;
_$jscoverage['connect.js'][71] = 0;
_$jscoverage['connect.js'][72] = 0;
_$jscoverage['connect.js'][74] = 0;
_$jscoverage['connect.js'][75] = 0;
_$jscoverage['connect.js'][81] = 0;
_$jscoverage['connect.js'][87] = 0;
_$jscoverage['connect.js'][88] = 0;
_$jscoverage['connect.js'][89] = 0;
_$jscoverage['connect.js'][90] = 0;
_$jscoverage['connect.js'][91] = 0;
_$jscoverage['connect.js'][92] = 0;
}
_$jscoverage['connect.js'][13]++;
var EventEmitter = require("events").EventEmitter, proto = require("./proto"), utils = require("./utils"), path = require("path"), basename = path.basename, fs = require("fs");
_$jscoverage['connect.js'][22]++;
require("./patch");
_$jscoverage['connect.js'][26]++;
exports = module.exports = createServer;
_$jscoverage['connect.js'][32]++;
exports.version = "2.6.1";
_$jscoverage['connect.js'][38]++;
exports.mime = require("./middleware/static").mime;
_$jscoverage['connect.js'][44]++;
exports.proto = proto;
_$jscoverage['connect.js'][50]++;
exports.middleware = {};
_$jscoverage['connect.js'][56]++;
exports.utils = utils;
_$jscoverage['connect.js'][65]++;
function createServer() {
_$jscoverage['connect.js'][66]++;
function app(req, res) {
_$jscoverage['connect.js'][66]++;
app.handle(req, res);
}
_$jscoverage['connect.js'][67]++;
utils.merge(app, proto);
_$jscoverage['connect.js'][68]++;
utils.merge(app, EventEmitter.prototype);
_$jscoverage['connect.js'][69]++;
app.route = "/";
_$jscoverage['connect.js'][70]++;
app.stack = [];
_$jscoverage['connect.js'][71]++;
for (var i = 0; i < arguments.length; ++i) {
_$jscoverage['connect.js'][72]++;
app.use(arguments[i]);
}
_$jscoverage['connect.js'][74]++;
return app;
}
_$jscoverage['connect.js'][75]++;
;
_$jscoverage['connect.js'][81]++;
createServer.createServer = createServer;
_$jscoverage['connect.js'][87]++;
fs.readdirSync(__dirname + "/middleware").forEach((function (filename) {
_$jscoverage['connect.js'][88]++;
if (! /\.js$/.test(filename)) {
_$jscoverage['connect.js'][88]++;
return;
}
_$jscoverage['connect.js'][89]++;
var name = basename(filename, ".js");
_$jscoverage['connect.js'][90]++;
function load() {
_$jscoverage['connect.js'][90]++;
return require("./middleware/" + name);
}
_$jscoverage['connect.js'][91]++;
exports.middleware.__defineGetter__(name, load);
_$jscoverage['connect.js'][92]++;
exports.__defineGetter__(name, load);
}));
_$jscoverage['connect.js'].source = ["","/*!"," * Connect"," * Copyright(c) 2010 Sencha Inc."," * Copyright(c) 2011 TJ Holowaychuk"," * MIT Licensed"," */","","/**"," * Module dependencies."," */","","var EventEmitter = require('events').EventEmitter"," , proto = require('./proto')"," , utils = require('./utils')"," , path = require('path')"," , basename = path.basename"," , fs = require('fs');","","// node patches","","require('./patch');","","// expose createServer() as the module","","exports = module.exports = createServer;","","/**"," * Framework version."," */","","exports.version = '2.6.1';","","/**"," * Expose mime module."," */","","exports.mime = require('./middleware/static').mime;","","/**"," * Expose the prototype."," */","","exports.proto = proto;","","/**"," * Auto-load middleware getters."," */","","exports.middleware = {};","","/**"," * Expose utilities."," */","","exports.utils = utils;","","/**"," * Create a new connect server."," *"," * @return {Function}"," * @api public"," */","","function createServer() {"," function app(req, res){ app.handle(req, res); }"," utils.merge(app, proto);"," utils.merge(app, EventEmitter.prototype);"," app.route = '/';"," app.stack = [];"," for (var i = 0; i &lt; arguments.length; ++i) {"," app.use(arguments[i]);"," }"," return app;","};","","/**"," * Support old `.createServer()` method."," */","","createServer.createServer = createServer;","","/**"," * Auto-load bundled middleware with getters."," */","","fs.readdirSync(__dirname + '/middleware').forEach(function(filename){"," if (!/\\.js$/.test(filename)) return;"," var name = basename(filename, '.js');"," function load(){ return require('./middleware/' + name); }"," exports.middleware.__defineGetter__(name, load);"," exports.__defineGetter__(name, load);","});"];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['index.js']) {
_$jscoverage['index.js'] = [];
}
_$jscoverage['index.js'].source = ["","/**"," * Connect is a middleware framework for node,"," * shipping with over 18 bundled middleware and a rich selection of"," * 3rd-party middleware."," *"," * var app = connect()"," * .use(connect.logger('dev'))"," * .use(connect.static('public'))"," * .use(function(req, res){"," * res.end('hello world\\n');"," * })"," * .listen(3000);"," * "," * Installation:"," * "," * $ npm install connect"," *"," * Middleware:"," *"," * - [logger](logger.html) request logger with custom format support"," * - [csrf](csrf.html) Cross-site request forgery protection"," * - [compress](compress.html) Gzip compression middleware"," * - [basicAuth](basicAuth.html) basic http authentication"," * - [bodyParser](bodyParser.html) extensible request body parser"," * - [json](json.html) application/json parser"," * - [urlencoded](urlencoded.html) application/x-www-form-urlencoded parser"," * - [multipart](multipart.html) multipart/form-data parser"," * - [timeout](timeout.html) request timeouts"," * - [cookieParser](cookieParser.html) cookie parser"," * - [session](session.html) session management support with bundled MemoryStore"," * - [cookieSession](cookieSession.html) cookie-based session support"," * - [methodOverride](methodOverride.html) faux HTTP method support"," * - [responseTime](responseTime.html) calculates response-time and exposes via X-Response-Time"," * - [staticCache](staticCache.html) memory cache layer for the static() middleware"," * - [static](static.html) streaming static file server supporting `Range` and more"," * - [directory](directory.html) directory listing middleware"," * - [vhost](vhost.html) virtual host sub-domain mapping middleware"," * - [favicon](favicon.html) efficient favicon server (with default icon)"," * - [limit](limit.html) limit the bytesize of request bodies"," * - [query](query.html) automatic querystring parser, populating `req.query`"," * - [errorHandler](errorHandler.html) flexible error handler"," *"," * Links:"," * "," * - list of [3rd-party](https://github.com/senchalabs/connect/wiki) middleware"," * - GitHub [repository](http://github.com/senchalabs/connect)"," * - [test documentation](https://github.com/senchalabs/connect/blob/gh-pages/tests.md)"," * "," */"];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['middleware/basicAuth.js']) {
_$jscoverage['middleware/basicAuth.js'] = [];
_$jscoverage['middleware/basicAuth.js'][13] = 0;
_$jscoverage['middleware/basicAuth.js'][48] = 0;
_$jscoverage['middleware/basicAuth.js'][49] = 0;
_$jscoverage['middleware/basicAuth.js'][52] = 0;
_$jscoverage['middleware/basicAuth.js'][53] = 0;
_$jscoverage['middleware/basicAuth.js'][54] = 0;
_$jscoverage['middleware/basicAuth.js'][55] = 0;
_$jscoverage['middleware/basicAuth.js'][56] = 0;
_$jscoverage['middleware/basicAuth.js'][57] = 0;
_$jscoverage['middleware/basicAuth.js'][58] = 0;
_$jscoverage['middleware/basicAuth.js'][62] = 0;
_$jscoverage['middleware/basicAuth.js'][64] = 0;
_$jscoverage['middleware/basicAuth.js'][65] = 0;
_$jscoverage['middleware/basicAuth.js'][67] = 0;
_$jscoverage['middleware/basicAuth.js'][68] = 0;
_$jscoverage['middleware/basicAuth.js'][70] = 0;
_$jscoverage['middleware/basicAuth.js'][72] = 0;
_$jscoverage['middleware/basicAuth.js'][74] = 0;
_$jscoverage['middleware/basicAuth.js'][78] = 0;
_$jscoverage['middleware/basicAuth.js'][80] = 0;
_$jscoverage['middleware/basicAuth.js'][84] = 0;
_$jscoverage['middleware/basicAuth.js'][85] = 0;
_$jscoverage['middleware/basicAuth.js'][86] = 0;
_$jscoverage['middleware/basicAuth.js'][87] = 0;
_$jscoverage['middleware/basicAuth.js'][88] = 0;
_$jscoverage['middleware/basicAuth.js'][89] = 0;
_$jscoverage['middleware/basicAuth.js'][90] = 0;
_$jscoverage['middleware/basicAuth.js'][94] = 0;
_$jscoverage['middleware/basicAuth.js'][95] = 0;
_$jscoverage['middleware/basicAuth.js'][96] = 0;
_$jscoverage['middleware/basicAuth.js'][98] = 0;
}
_$jscoverage['middleware/basicAuth.js'][13]++;
var utils = require("../utils"), unauthorized = utils.unauthorized;
_$jscoverage['middleware/basicAuth.js'][48]++;
module.exports = (function basicAuth(callback, realm) {
_$jscoverage['middleware/basicAuth.js'][49]++;
var username, password;
_$jscoverage['middleware/basicAuth.js'][52]++;
if ("string" == typeof callback) {
_$jscoverage['middleware/basicAuth.js'][53]++;
username = callback;
_$jscoverage['middleware/basicAuth.js'][54]++;
password = realm;
_$jscoverage['middleware/basicAuth.js'][55]++;
if ("string" != typeof password) {
_$jscoverage['middleware/basicAuth.js'][55]++;
throw new Error("password argument required");
}
_$jscoverage['middleware/basicAuth.js'][56]++;
realm = arguments[2];
_$jscoverage['middleware/basicAuth.js'][57]++;
callback = (function (user, pass) {
_$jscoverage['middleware/basicAuth.js'][58]++;
return user == username && pass == password;
});
}
_$jscoverage['middleware/basicAuth.js'][62]++;
realm = realm || "Authorization Required";
_$jscoverage['middleware/basicAuth.js'][64]++;
return (function (req, res, next) {
_$jscoverage['middleware/basicAuth.js'][65]++;
var authorization = req.headers.authorization;
_$jscoverage['middleware/basicAuth.js'][67]++;
if (req.user) {
_$jscoverage['middleware/basicAuth.js'][67]++;
return next();
}
_$jscoverage['middleware/basicAuth.js'][68]++;
if (! authorization) {
_$jscoverage['middleware/basicAuth.js'][68]++;
return unauthorized(res, realm);
}
_$jscoverage['middleware/basicAuth.js'][70]++;
var parts = authorization.split(" ");
_$jscoverage['middleware/basicAuth.js'][72]++;
if (parts.length !== 2) {
_$jscoverage['middleware/basicAuth.js'][72]++;
return next(utils.error(400));
}
_$jscoverage['middleware/basicAuth.js'][74]++;
var scheme = parts[0], credentials = new Buffer(parts[1], "base64").toString(), index = credentials.indexOf(":");
_$jscoverage['middleware/basicAuth.js'][78]++;
if ("Basic" != scheme || index < 0) {
_$jscoverage['middleware/basicAuth.js'][78]++;
return next(utils.error(400));
}
_$jscoverage['middleware/basicAuth.js'][80]++;
var user = credentials.slice(0, index), pass = credentials.slice(index + 1);
_$jscoverage['middleware/basicAuth.js'][84]++;
if (callback.length >= 3) {
_$jscoverage['middleware/basicAuth.js'][85]++;
var pause = utils.pause(req);
_$jscoverage['middleware/basicAuth.js'][86]++;
callback(user, pass, (function (err, user) {
_$jscoverage['middleware/basicAuth.js'][87]++;
if (err || ! user) {
_$jscoverage['middleware/basicAuth.js'][87]++;
return unauthorized(res, realm);
}
_$jscoverage['middleware/basicAuth.js'][88]++;
req.user = req.remoteUser = user;
_$jscoverage['middleware/basicAuth.js'][89]++;
next();
_$jscoverage['middleware/basicAuth.js'][90]++;
pause.resume();
}));
}
else {
_$jscoverage['middleware/basicAuth.js'][94]++;
if (callback(user, pass)) {
_$jscoverage['middleware/basicAuth.js'][95]++;
req.user = req.remoteUser = user;
_$jscoverage['middleware/basicAuth.js'][96]++;
next();
}
else {
_$jscoverage['middleware/basicAuth.js'][98]++;
unauthorized(res, realm);
}
}
});
});
_$jscoverage['middleware/basicAuth.js'].source = ["","/*!"," * Connect - basicAuth"," * Copyright(c) 2010 Sencha Inc."," * Copyright(c) 2011 TJ Holowaychuk"," * MIT Licensed"," */","","/**"," * Module dependencies."," */","","var utils = require('../utils')"," , unauthorized = utils.unauthorized;","","/**"," * Basic Auth:"," *"," * Enfore basic authentication by providing a `callback(user, pass)`,"," * which must return `true` in order to gain access. Alternatively an async"," * method is provided as well, invoking `callback(user, pass, callback)`. Populates"," * `req.user`. The final alternative is simply passing username / password"," * strings."," *"," * Simple username and password"," *"," * connect(connect.basicAuth('username', 'password'));"," *"," * Callback verification"," *"," * connect()"," * .use(connect.basicAuth(function(user, pass){"," * return 'tj' == user &amp; 'wahoo' == pass;"," * }))"," *"," * Async callback verification, accepting `fn(err, user)`."," *"," * connect()"," * .use(connect.basicAuth(function(user, pass, fn){"," * User.authenticate({ user: user, pass: pass }, fn);"," * }))"," *"," * @param {Function|String} callback or username"," * @param {String} realm"," * @api public"," */","","module.exports = function basicAuth(callback, realm) {"," var username, password;",""," // user / pass strings"," if ('string' == typeof callback) {"," username = callback;"," password = realm;"," if ('string' != typeof password) throw new Error('password argument required');"," realm = arguments[2];"," callback = function(user, pass){"," return user == username &amp;&amp; pass == password;"," }"," }",""," realm = realm || 'Authorization Required';",""," return function(req, res, next) {"," var authorization = req.headers.authorization;",""," if (req.user) return next();"," if (!authorization) return unauthorized(res, realm);",""," var parts = authorization.split(' ');",""," if (parts.length !== 2) return next(utils.error(400));",""," var scheme = parts[0]"," , credentials = new Buffer(parts[1], 'base64').toString()"," , index = credentials.indexOf(':');",""," if ('Basic' != scheme || index &lt; 0) return next(utils.error(400));"," "," var user = credentials.slice(0, index)"," , pass = credentials.slice(index + 1);",""," // async"," if (callback.length &gt;= 3) {"," var pause = utils.pause(req);"," callback(user, pass, function(err, user){"," if (err || !user) return unauthorized(res, realm);"," req.user = req.remoteUser = user;"," next();"," pause.resume();"," });"," // sync"," } else {"," if (callback(user, pass)) {"," req.user = req.remoteUser = user;"," next();"," } else {"," unauthorized(res, realm);"," }"," }"," }","};",""];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['middleware/bodyParser.js']) {
_$jscoverage['middleware/bodyParser.js'] = [];
_$jscoverage['middleware/bodyParser.js'][13] = 0;
_$jscoverage['middleware/bodyParser.js'][47] = 0;
_$jscoverage['middleware/bodyParser.js'][48] = 0;
_$jscoverage['middleware/bodyParser.js'][52] = 0;
_$jscoverage['middleware/bodyParser.js'][53] = 0;
_$jscoverage['middleware/bodyParser.js'][54] = 0;
_$jscoverage['middleware/bodyParser.js'][55] = 0;
_$jscoverage['middleware/bodyParser.js'][56] = 0;
_$jscoverage['middleware/bodyParser.js'][57] = 0;
}
_$jscoverage['middleware/bodyParser.js'][13]++;
var multipart = require("./multipart"), urlencoded = require("./urlencoded"), json = require("./json");
_$jscoverage['middleware/bodyParser.js'][47]++;
exports = module.exports = (function bodyParser(options) {
_$jscoverage['middleware/bodyParser.js'][48]++;
var _urlencoded = urlencoded(options), _multipart = multipart(options), _json = json(options);
_$jscoverage['middleware/bodyParser.js'][52]++;
return (function bodyParser(req, res, next) {
_$jscoverage['middleware/bodyParser.js'][53]++;
_json(req, res, (function (err) {
_$jscoverage['middleware/bodyParser.js'][54]++;
if (err) {
_$jscoverage['middleware/bodyParser.js'][54]++;
return next(err);
}
_$jscoverage['middleware/bodyParser.js'][55]++;
_urlencoded(req, res, (function (err) {
_$jscoverage['middleware/bodyParser.js'][56]++;
if (err) {
_$jscoverage['middleware/bodyParser.js'][56]++;
return next(err);
}
_$jscoverage['middleware/bodyParser.js'][57]++;
_multipart(req, res, next);
}));
}));
});
});
_$jscoverage['middleware/bodyParser.js'].source = ["","/*!"," * Connect - bodyParser"," * Copyright(c) 2010 Sencha Inc."," * Copyright(c) 2011 TJ Holowaychuk"," * MIT Licensed"," */","","/**"," * Module dependencies."," */","","var multipart = require('./multipart')"," , urlencoded = require('./urlencoded')"," , json = require('./json');","","/**"," * Body parser:"," * "," * Parse request bodies, supports _application/json_,"," * _application/x-www-form-urlencoded_, and _multipart/form-data_."," *"," * This is equivalent to: "," *"," * app.use(connect.json());"," * app.use(connect.urlencoded());"," * app.use(connect.multipart());"," *"," * Examples:"," *"," * connect()"," * .use(connect.bodyParser())"," * .use(function(req, res) {"," * res.end('viewing user ' + req.body.user.name);"," * });"," *"," * $ curl -d 'user[name]=tj' http://local/"," * $ curl -d '{\"user\":{\"name\":\"tj\"}}' -H \"Content-Type: application/json\" http://local/"," *"," * View [json](json.html), [urlencoded](urlencoded.html), and [multipart](multipart.html) for more info."," *"," * @param {Object} options"," * @return {Function}"," * @api public"," */","","exports = module.exports = function bodyParser(options){"," var _urlencoded = urlencoded(options)"," , _multipart = multipart(options)"," , _json = json(options);",""," return function bodyParser(req, res, next) {"," _json(req, res, function(err){"," if (err) return next(err);"," _urlencoded(req, res, function(err){"," if (err) return next(err);"," _multipart(req, res, next);"," });"," });"," }","};"];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['middleware/compress.js']) {
_$jscoverage['middleware/compress.js'] = [];
_$jscoverage['middleware/compress.js'][12] = 0;
_$jscoverage['middleware/compress.js'][18] = 0;
_$jscoverage['middleware/compress.js'][27] = 0;
_$jscoverage['middleware/compress.js'][28] = 0;
_$jscoverage['middleware/compress.js'][61] = 0;
_$jscoverage['middleware/compress.js'][62] = 0;
_$jscoverage['middleware/compress.js'][63] = 0;
_$jscoverage['middleware/compress.js'][66] = 0;
_$jscoverage['middleware/compress.js'][67] = 0;
_$jscoverage['middleware/compress.js'][74] = 0;
_$jscoverage['middleware/compress.js'][78] = 0;
_$jscoverage['middleware/compress.js'][79] = 0;
_$jscoverage['middleware/compress.js'][80] = 0;
_$jscoverage['middleware/compress.js'][85] = 0;
_$jscoverage['middleware/compress.js'][86] = 0;
_$jscoverage['middleware/compress.js'][87] = 0;
_$jscoverage['middleware/compress.js'][92] = 0;
_$jscoverage['middleware/compress.js'][93] = 0;
_$jscoverage['middleware/compress.js'][96] = 0;
_$jscoverage['middleware/compress.js'][99] = 0;
_$jscoverage['middleware/compress.js'][102] = 0;
_$jscoverage['middleware/compress.js'][105] = 0;
_$jscoverage['middleware/compress.js'][108] = 0;
_$jscoverage['middleware/compress.js'][111] = 0;
_$jscoverage['middleware/compress.js'][112] = 0;
_$jscoverage['middleware/compress.js'][113] = 0;
_$jscoverage['middleware/compress.js'][114] = 0;
_$jscoverage['middleware/compress.js'][115] = 0;
_$jscoverage['middleware/compress.js'][121] = 0;
_$jscoverage['middleware/compress.js'][124] = 0;
_$jscoverage['middleware/compress.js'][127] = 0;
_$jscoverage['middleware/compress.js'][128] = 0;
_$jscoverage['middleware/compress.js'][132] = 0;
_$jscoverage['middleware/compress.js'][133] = 0;
_$jscoverage['middleware/compress.js'][136] = 0;
_$jscoverage['middleware/compress.js'][137] = 0;
_$jscoverage['middleware/compress.js'][140] = 0;
_$jscoverage['middleware/compress.js'][141] = 0;
_$jscoverage['middleware/compress.js'][145] = 0;
}
_$jscoverage['middleware/compress.js'][12]++;
var zlib = require("zlib");
_$jscoverage['middleware/compress.js'][18]++;
exports.methods = {gzip: zlib.createGzip, deflate: zlib.createDeflate};
_$jscoverage['middleware/compress.js'][27]++;
exports.filter = (function (req, res) {
_$jscoverage['middleware/compress.js'][28]++;
return /json|text|javascript/.test(res.getHeader("Content-Type"));
});
_$jscoverage['middleware/compress.js'][61]++;
module.exports = (function compress(options) {
_$jscoverage['middleware/compress.js'][62]++;
options = options || {};
_$jscoverage['middleware/compress.js'][63]++;
var names = Object.keys(exports.methods), filter = options.filter || exports.filter;
_$jscoverage['middleware/compress.js'][66]++;
return (function (req, res, next) {
_$jscoverage['middleware/compress.js'][67]++;
var accept = req.headers["accept-encoding"], write = res.write, end = res.end, stream, method;
_$jscoverage['middleware/compress.js'][74]++;
res.setHeader("Vary", "Accept-Encoding");
_$jscoverage['middleware/compress.js'][78]++;
res.write = (function (chunk, encoding) {
_$jscoverage['middleware/compress.js'][79]++;
if (! this.headerSent) {
_$jscoverage['middleware/compress.js'][79]++;
this._implicitHeader();
}
_$jscoverage['middleware/compress.js'][80]++;
return stream? stream.write(new Buffer(chunk, encoding)): write.call(res, chunk, encoding);
});
_$jscoverage['middleware/compress.js'][85]++;
res.end = (function (chunk, encoding) {
_$jscoverage['middleware/compress.js'][86]++;
if (chunk) {
_$jscoverage['middleware/compress.js'][86]++;
this.write(chunk, encoding);
}
_$jscoverage['middleware/compress.js'][87]++;
return stream? stream.end(): end.call(res);
});
_$jscoverage['middleware/compress.js'][92]++;
res.on("header", (function () {
_$jscoverage['middleware/compress.js'][93]++;
var encoding = res.getHeader("Content-Encoding") || "identity";
_$jscoverage['middleware/compress.js'][96]++;
if ("identity" != encoding) {
_$jscoverage['middleware/compress.js'][96]++;
return;
}
_$jscoverage['middleware/compress.js'][99]++;
if (! filter(req, res)) {
_$jscoverage['middleware/compress.js'][99]++;
return;
}
_$jscoverage['middleware/compress.js'][102]++;
if (! accept) {
_$jscoverage['middleware/compress.js'][102]++;
return;
}
_$jscoverage['middleware/compress.js'][105]++;
if ("HEAD" == req.method) {
_$jscoverage['middleware/compress.js'][105]++;
return;
}
_$jscoverage['middleware/compress.js'][108]++;
if ("*" == accept.trim()) {
_$jscoverage['middleware/compress.js'][108]++;
method = "gzip";
}
_$jscoverage['middleware/compress.js'][111]++;
if (! method) {
_$jscoverage['middleware/compress.js'][112]++;
for (var i = 0, len = names.length; i < len; ++i) {
_$jscoverage['middleware/compress.js'][113]++;
if (~ accept.indexOf(names[i])) {
_$jscoverage['middleware/compress.js'][114]++;
method = names[i];
_$jscoverage['middleware/compress.js'][115]++;
break;
}
}
}
_$jscoverage['middleware/compress.js'][121]++;
if (! method) {
_$jscoverage['middleware/compress.js'][121]++;
return;
}
_$jscoverage['middleware/compress.js'][124]++;
stream = exports.methods[method](options);
_$jscoverage['middleware/compress.js'][127]++;
res.setHeader("Content-Encoding", method);
_$jscoverage['middleware/compress.js'][128]++;
res.removeHeader("Content-Length");
_$jscoverage['middleware/compress.js'][132]++;
stream.on("data", (function (chunk) {
_$jscoverage['middleware/compress.js'][133]++;
write.call(res, chunk);
}));
_$jscoverage['middleware/compress.js'][136]++;
stream.on("end", (function () {
_$jscoverage['middleware/compress.js'][137]++;
end.call(res);
}));
_$jscoverage['middleware/compress.js'][140]++;
stream.on("drain", (function () {
_$jscoverage['middleware/compress.js'][141]++;
res.emit("drain");
}));
}));
_$jscoverage['middleware/compress.js'][145]++;
next();
});
});
_$jscoverage['middleware/compress.js'].source = ["/*!"," * Connect - compress"," * Copyright(c) 2010 Sencha Inc."," * Copyright(c) 2011 TJ Holowaychuk"," * MIT Licensed"," */","","/**"," * Module dependencies."," */","","var zlib = require('zlib');","","/**"," * Supported content-encoding methods."," */","","exports.methods = {"," gzip: zlib.createGzip"," , deflate: zlib.createDeflate","};","","/**"," * Default filter function."," */","","exports.filter = function(req, res){"," return /json|text|javascript/.test(res.getHeader('Content-Type'));","};","","/**"," * Compress:"," *"," * Compress response data with gzip/deflate."," *"," * Filter:"," *"," * A `filter` callback function may be passed to"," * replace the default logic of:"," *"," * exports.filter = function(req, res){"," * return /json|text|javascript/.test(res.getHeader('Content-Type'));"," * };"," *"," * Options:"," *"," * All remaining options are passed to the gzip/deflate"," * creation functions. Consult node's docs for additional details."," *"," * - `chunkSize` (default: 16*1024)"," * - `windowBits`"," * - `level`: 0-9 where 0 is no compression, and 9 is slow but best compression"," * - `memLevel`: 1-9 low is slower but uses less memory, high is fast but uses more"," * - `strategy`: compression strategy"," *"," * @param {Object} options"," * @return {Function}"," * @api public"," */","","module.exports = function compress(options) {"," options = options || {};"," var names = Object.keys(exports.methods)"," , filter = options.filter || exports.filter;",""," return function(req, res, next){"," var accept = req.headers['accept-encoding']"," , write = res.write"," , end = res.end"," , stream"," , method;",""," // vary"," res.setHeader('Vary', 'Accept-Encoding');",""," // proxy",""," res.write = function(chunk, encoding){"," if (!this.headerSent) this._implicitHeader();"," return stream"," ? stream.write(new Buffer(chunk, encoding))"," : write.call(res, chunk, encoding);"," };",""," res.end = function(chunk, encoding){"," if (chunk) this.write(chunk, encoding);"," return stream"," ? stream.end()"," : end.call(res);"," };",""," res.on('header', function(){"," var encoding = res.getHeader('Content-Encoding') || 'identity';",""," // already encoded"," if ('identity' != encoding) return; ",""," // default request filter"," if (!filter(req, res)) return;",""," // SHOULD use identity"," if (!accept) return;",""," // head"," if ('HEAD' == req.method) return;",""," // default to gzip"," if ('*' == accept.trim()) method = 'gzip';",""," // compression method"," if (!method) {"," for (var i = 0, len = names.length; i &lt; len; ++i) {"," if (~accept.indexOf(names[i])) {"," method = names[i];"," break;"," }"," }"," }",""," // compression method"," if (!method) return;",""," // compression stream"," stream = exports.methods[method](options);",""," // header fields"," res.setHeader('Content-Encoding', method);"," res.removeHeader('Content-Length');",""," // compression",""," stream.on('data', function(chunk){"," write.call(res, chunk);"," });",""," stream.on('end', function(){"," end.call(res);"," });",""," stream.on('drain', function() {"," res.emit('drain');"," });"," });",""," next();"," };","};"];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['middleware/cookieParser.js']) {
_$jscoverage['middleware/cookieParser.js'] = [];
_$jscoverage['middleware/cookieParser.js'][13] = 0;
_$jscoverage['middleware/cookieParser.js'][38] = 0;
_$jscoverage['middleware/cookieParser.js'][39] = 0;
_$jscoverage['middleware/cookieParser.js'][40] = 0;
_$jscoverage['middleware/cookieParser.js'][41] = 0;
_$jscoverage['middleware/cookieParser.js'][43] = 0;
_$jscoverage['middleware/cookieParser.js'][44] = 0;
_$jscoverage['middleware/cookieParser.js'][45] = 0;
_$jscoverage['middleware/cookieParser.js'][47] = 0;
_$jscoverage['middleware/cookieParser.js'][48] = 0;
_$jscoverage['middleware/cookieParser.js'][49] = 0;
_$jscoverage['middleware/cookieParser.js'][50] = 0;
_$jscoverage['middleware/cookieParser.js'][51] = 0;
_$jscoverage['middleware/cookieParser.js'][52] = 0;
_$jscoverage['middleware/cookieParser.js'][54] = 0;
_$jscoverage['middleware/cookieParser.js'][56] = 0;
_$jscoverage['middleware/cookieParser.js'][57] = 0;
_$jscoverage['middleware/cookieParser.js'][60] = 0;
}
_$jscoverage['middleware/cookieParser.js'][13]++;
var utils = require("./../utils"), cookie = require("cookie");
_$jscoverage['middleware/cookieParser.js'][38]++;
module.exports = (function cookieParser(secret) {
_$jscoverage['middleware/cookieParser.js'][39]++;
return (function cookieParser(req, res, next) {
_$jscoverage['middleware/cookieParser.js'][40]++;
if (req.cookies) {
_$jscoverage['middleware/cookieParser.js'][40]++;
return next();
}
_$jscoverage['middleware/cookieParser.js'][41]++;
var cookies = req.headers.cookie;
_$jscoverage['middleware/cookieParser.js'][43]++;
req.secret = secret;
_$jscoverage['middleware/cookieParser.js'][44]++;
req.cookies = {};
_$jscoverage['middleware/cookieParser.js'][45]++;
req.signedCookies = {};
_$jscoverage['middleware/cookieParser.js'][47]++;
if (cookies) {
_$jscoverage['middleware/cookieParser.js'][48]++;
try {
_$jscoverage['middleware/cookieParser.js'][49]++;
req.cookies = cookie.parse(cookies);
_$jscoverage['middleware/cookieParser.js'][50]++;
if (secret) {
_$jscoverage['middleware/cookieParser.js'][51]++;
req.signedCookies = utils.parseSignedCookies(req.cookies, secret);
_$jscoverage['middleware/cookieParser.js'][52]++;
req.signedCookies = utils.parseJSONCookies(req.signedCookies);
}
_$jscoverage['middleware/cookieParser.js'][54]++;
req.cookies = utils.parseJSONCookies(req.cookies);
}
catch (err) {
_$jscoverage['middleware/cookieParser.js'][56]++;
err.status = 400;
_$jscoverage['middleware/cookieParser.js'][57]++;
return next(err);
}
}
_$jscoverage['middleware/cookieParser.js'][60]++;
next();
});
});
_$jscoverage['middleware/cookieParser.js'].source = ["","/*!"," * Connect - cookieParser"," * Copyright(c) 2010 Sencha Inc."," * Copyright(c) 2011 TJ Holowaychuk"," * MIT Licensed"," */","","/**"," * Module dependencies."," */","","var utils = require('./../utils')"," , cookie = require('cookie');","","/**"," * Cookie parser:"," *"," * Parse _Cookie_ header and populate `req.cookies`"," * with an object keyed by the cookie names. Optionally"," * you may enabled signed cookie support by passing"," * a `secret` string, which assigns `req.secret` so"," * it may be used by other middleware."," *"," * Examples:"," *"," * connect()"," * .use(connect.cookieParser('optional secret string'))"," * .use(function(req, res, next){"," * res.end(JSON.stringify(req.cookies));"," * })"," *"," * @param {String} secret"," * @return {Function}"," * @api public"," */","","module.exports = function cookieParser(secret){"," return function cookieParser(req, res, next) {"," if (req.cookies) return next();"," var cookies = req.headers.cookie;",""," req.secret = secret;"," req.cookies = {};"," req.signedCookies = {};",""," if (cookies) {"," try {"," req.cookies = cookie.parse(cookies);"," if (secret) {"," req.signedCookies = utils.parseSignedCookies(req.cookies, secret);"," req.signedCookies = utils.parseJSONCookies(req.signedCookies);"," }"," req.cookies = utils.parseJSONCookies(req.cookies);"," } catch (err) {"," err.status = 400;"," return next(err);"," }"," }"," next();"," };","};"];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['middleware/cookieSession.js']) {
_$jscoverage['middleware/cookieSession.js'] = [];
_$jscoverage['middleware/cookieSession.js'][12] = 0;
_$jscoverage['middleware/cookieSession.js'][46] = 0;
_$jscoverage['middleware/cookieSession.js'][48] = 0;
_$jscoverage['middleware/cookieSession.js'][49] = 0;
_$jscoverage['middleware/cookieSession.js'][52] = 0;
_$jscoverage['middleware/cookieSession.js'][55] = 0;
_$jscoverage['middleware/cookieSession.js'][56] = 0;
_$jscoverage['middleware/cookieSession.js'][59] = 0;
_$jscoverage['middleware/cookieSession.js'][60] = 0;
_$jscoverage['middleware/cookieSession.js'][63] = 0;
_$jscoverage['middleware/cookieSession.js'][66] = 0;
_$jscoverage['middleware/cookieSession.js'][67] = 0;
_$jscoverage['middleware/cookieSession.js'][70] = 0;
_$jscoverage['middleware/cookieSession.js'][71] = 0;
_$jscoverage['middleware/cookieSession.js'][72] = 0;
_$jscoverage['middleware/cookieSession.js'][73] = 0;
_$jscoverage['middleware/cookieSession.js'][74] = 0;
_$jscoverage['middleware/cookieSession.js'][75] = 0;
_$jscoverage['middleware/cookieSession.js'][80] = 0;
_$jscoverage['middleware/cookieSession.js'][82] = 0;
_$jscoverage['middleware/cookieSession.js'][83] = 0;
_$jscoverage['middleware/cookieSession.js'][84] = 0;
_$jscoverage['middleware/cookieSession.js'][85] = 0;
_$jscoverage['middleware/cookieSession.js'][86] = 0;
_$jscoverage['middleware/cookieSession.js'][89] = 0;
_$jscoverage['middleware/cookieSession.js'][92] = 0;
_$jscoverage['middleware/cookieSession.js'][97] = 0;
_$jscoverage['middleware/cookieSession.js'][100] = 0;
_$jscoverage['middleware/cookieSession.js'][101] = 0;
_$jscoverage['middleware/cookieSession.js'][104] = 0;
_$jscoverage['middleware/cookieSession.js'][107] = 0;
_$jscoverage['middleware/cookieSession.js'][108] = 0;
_$jscoverage['middleware/cookieSession.js'][109] = 0;
_$jscoverage['middleware/cookieSession.js'][110] = 0;
_$jscoverage['middleware/cookieSession.js'][113] = 0;
}
_$jscoverage['middleware/cookieSession.js'][12]++;
var utils = require("./../utils"), Cookie = require("./session/cookie"), debug = require("debug")("connect:cookieSession"), signature = require("cookie-signature"), crc16 = require("crc").crc16;
_$jscoverage['middleware/cookieSession.js'][46]++;
module.exports = (function cookieSession(options) {
_$jscoverage['middleware/cookieSession.js'][48]++;
options = options || {};
_$jscoverage['middleware/cookieSession.js'][49]++;
var key = options.key || "connect.sess", trustProxy = options.proxy;
_$jscoverage['middleware/cookieSession.js'][52]++;
return (function cookieSession(req, res, next) {
_$jscoverage['middleware/cookieSession.js'][55]++;
var secret = options.secret || req.secret;
_$jscoverage['middleware/cookieSession.js'][56]++;
if (! secret) {
_$jscoverage['middleware/cookieSession.js'][56]++;
throw new Error("`secret` option required for cookie sessions");
}
_$jscoverage['middleware/cookieSession.js'][59]++;
req.session = {};
_$jscoverage['middleware/cookieSession.js'][60]++;
var cookie = req.session.cookie = new Cookie(options.cookie);
_$jscoverage['middleware/cookieSession.js'][63]++;
if (0 != req.originalUrl.indexOf(cookie.path)) {
_$jscoverage['middleware/cookieSession.js'][63]++;
return next();
}
_$jscoverage['middleware/cookieSession.js'][66]++;
if (! options.secret && req.secret) {
_$jscoverage['middleware/cookieSession.js'][67]++;
req.session = req.signedCookies[key] || {};
}
else {
_$jscoverage['middleware/cookieSession.js'][70]++;
var rawCookie = req.cookies[key];
_$jscoverage['middleware/cookieSession.js'][71]++;
if (rawCookie) {
_$jscoverage['middleware/cookieSession.js'][72]++;
var unsigned = utils.parseSignedCookie(rawCookie, secret);
_$jscoverage['middleware/cookieSession.js'][73]++;
if (unsigned) {
_$jscoverage['middleware/cookieSession.js'][74]++;
var originalHash = crc16(unsigned);
_$jscoverage['middleware/cookieSession.js'][75]++;
req.session = utils.parseJSONCookie(unsigned) || {};
}
}
}
_$jscoverage['middleware/cookieSession.js'][80]++;
res.on("header", (function () {
_$jscoverage['middleware/cookieSession.js'][82]++;
if (! req.session) {
_$jscoverage['middleware/cookieSession.js'][83]++;
debug("clear session");
_$jscoverage['middleware/cookieSession.js'][84]++;
cookie.expires = new Date(0);
_$jscoverage['middleware/cookieSession.js'][85]++;
res.setHeader("Set-Cookie", cookie.serialize(key, ""));
_$jscoverage['middleware/cookieSession.js'][86]++;
return;
}
_$jscoverage['middleware/cookieSession.js'][89]++;
delete req.session.cookie;
_$jscoverage['middleware/cookieSession.js'][92]++;
var proto = (req.headers["x-forwarded-proto"] || "").toLowerCase(), tls = req.connection.encrypted || (trustProxy && "https" == proto), secured = cookie.secure && tls;
_$jscoverage['middleware/cookieSession.js'][97]++;
if (cookie.secure && ! secured) {
_$jscoverage['middleware/cookieSession.js'][97]++;
return debug("not secured");
}
_$jscoverage['middleware/cookieSession.js'][100]++;
debug("serializing %j", req.session);
_$jscoverage['middleware/cookieSession.js'][101]++;
var val = "j:" + JSON.stringify(req.session);
_$jscoverage['middleware/cookieSession.js'][104]++;
if (originalHash == crc16(val)) {
_$jscoverage['middleware/cookieSession.js'][104]++;
return debug("unmodified session");
}
_$jscoverage['middleware/cookieSession.js'][107]++;
val = "s:" + signature.sign(val, secret);
_$jscoverage['middleware/cookieSession.js'][108]++;
val = cookie.serialize(key, val);
_$jscoverage['middleware/cookieSession.js'][109]++;
debug("set-cookie %j", cookie);
_$jscoverage['middleware/cookieSession.js'][110]++;
res.setHeader("Set-Cookie", val);
}));
_$jscoverage['middleware/cookieSession.js'][113]++;
next();
});
});
_$jscoverage['middleware/cookieSession.js'].source = ["","/*!"," * Connect - cookieSession"," * Copyright(c) 2011 Sencha Inc."," * MIT Licensed"," */","","/**"," * Module dependencies."," */","","var utils = require('./../utils')"," , Cookie = require('./session/cookie')"," , debug = require('debug')('connect:cookieSession')"," , signature = require('cookie-signature')"," , crc16 = require('crc').crc16;","","/**"," * Cookie Session:"," *"," * Cookie session middleware."," *"," * var app = connect();"," * app.use(connect.cookieParser());"," * app.use(connect.cookieSession({ secret: 'tobo!', cookie: { maxAge: 60 * 60 * 1000 }}));"," *"," * Options:"," *"," * - `key` cookie name defaulting to `connect.sess`"," * - `secret` prevents cookie tampering"," * - `cookie` session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: null }`"," * - `proxy` trust the reverse proxy when setting secure cookies (via \"x-forwarded-proto\")"," *"," * Clearing sessions:"," *"," * To clear the session simply set its value to `null`,"," * `cookieSession()` will then respond with a 1970 Set-Cookie."," *"," * req.session = null;"," *"," * @param {Object} options"," * @return {Function}"," * @api public"," */","","module.exports = function cookieSession(options){"," // TODO: utilize Session/Cookie to unify API"," options = options || {};"," var key = options.key || 'connect.sess'"," , trustProxy = options.proxy;",""," return function cookieSession(req, res, next) {",""," // req.secret is for backwards compatibility"," var secret = options.secret || req.secret;"," if (!secret) throw new Error('`secret` option required for cookie sessions');",""," // default session"," req.session = {};"," var cookie = req.session.cookie = new Cookie(options.cookie);",""," // pathname mismatch"," if (0 != req.originalUrl.indexOf(cookie.path)) return next();",""," // cookieParser secret"," if (!options.secret &amp;&amp; req.secret) {"," req.session = req.signedCookies[key] || {};"," } else {"," // TODO: refactor"," var rawCookie = req.cookies[key];"," if (rawCookie) {"," var unsigned = utils.parseSignedCookie(rawCookie, secret);"," if (unsigned) {"," var originalHash = crc16(unsigned);"," req.session = utils.parseJSONCookie(unsigned) || {};"," }"," }"," }",""," res.on('header', function(){"," // removed"," if (!req.session) {"," debug('clear session');"," cookie.expires = new Date(0);"," res.setHeader('Set-Cookie', cookie.serialize(key, ''));"," return;"," }",""," delete req.session.cookie;",""," // check security"," var proto = (req.headers['x-forwarded-proto'] || '').toLowerCase()"," , tls = req.connection.encrypted || (trustProxy &amp;&amp; 'https' == proto)"," , secured = cookie.secure &amp;&amp; tls;",""," // only send secure cookies via https"," if (cookie.secure &amp;&amp; !secured) return debug('not secured');",""," // serialize"," debug('serializing %j', req.session);"," var val = 'j:' + JSON.stringify(req.session);",""," // compare hashes, no need to set-cookie if unchanged"," if (originalHash == crc16(val)) return debug('unmodified session');",""," // set-cookie"," val = 's:' + signature.sign(val, secret);"," val = cookie.serialize(key, val);"," debug('set-cookie %j', cookie);"," res.setHeader('Set-Cookie', val);"," });",""," next();"," };","};"];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['middleware/csrf.js']) {
_$jscoverage['middleware/csrf.js'] = [];
_$jscoverage['middleware/csrf.js'][11] = 0;
_$jscoverage['middleware/csrf.js'][39] = 0;
_$jscoverage['middleware/csrf.js'][40] = 0;
_$jscoverage['middleware/csrf.js'][41] = 0;
_$jscoverage['middleware/csrf.js'][43] = 0;
_$jscoverage['middleware/csrf.js'][45] = 0;
_$jscoverage['middleware/csrf.js'][48] = 0;
_$jscoverage['middleware/csrf.js'][51] = 0;
_$jscoverage['middleware/csrf.js'][54] = 0;
_$jscoverage['middleware/csrf.js'][56] = 0;
_$jscoverage['middleware/csrf.js'][69] = 0;
_$jscoverage['middleware/csrf.js'][70] = 0;
}
_$jscoverage['middleware/csrf.js'][11]++;
var utils = require("../utils");
_$jscoverage['middleware/csrf.js'][39]++;
module.exports = (function csrf(options) {
_$jscoverage['middleware/csrf.js'][40]++;
options = options || {};
_$jscoverage['middleware/csrf.js'][41]++;
var value = options.value || defaultValue;
_$jscoverage['middleware/csrf.js'][43]++;
return (function (req, res, next) {
_$jscoverage['middleware/csrf.js'][45]++;
var token = req.session._csrf || (req.session._csrf = utils.uid(24));
_$jscoverage['middleware/csrf.js'][48]++;
if ("GET" == req.method || "HEAD" == req.method || "OPTIONS" == req.method) {
_$jscoverage['middleware/csrf.js'][48]++;
return next();
}
_$jscoverage['middleware/csrf.js'][51]++;
var val = value(req);
_$jscoverage['middleware/csrf.js'][54]++;
if (val != token) {
_$jscoverage['middleware/csrf.js'][54]++;
return next(utils.error(403));
}
_$jscoverage['middleware/csrf.js'][56]++;
next();
});
});
_$jscoverage['middleware/csrf.js'][69]++;
function defaultValue(req) {
_$jscoverage['middleware/csrf.js'][70]++;
return (req.body && req.body._csrf) || (req.query && req.query._csrf) || req.headers["x-csrf-token"];
}
_$jscoverage['middleware/csrf.js'].source = ["/*!"," * Connect - csrf"," * Copyright(c) 2011 Sencha Inc."," * MIT Licensed"," */","","/**"," * Module dependencies."," */","","var utils = require('../utils');","","/**"," * Anti CSRF:"," *"," * CRSF protection middleware."," *"," * By default this middleware generates a token named \"_csrf\""," * which should be added to requests which mutate"," * state, within a hidden form field, query-string etc. This"," * token is validated against the visitor's `req.session._csrf`"," * property."," *"," * The default `value` function checks `req.body` generated"," * by the `bodyParser()` middleware, `req.query` generated"," * by `query()`, and the \"X-CSRF-Token\" header field."," *"," * This middleware requires session support, thus should be added"," * somewhere _below_ `session()` and `cookieParser()`."," *"," * Options:"," *"," * - `value` a function accepting the request, returning the token "," *"," * @param {Object} options"," * @api public"," */","","module.exports = function csrf(options) {"," options = options || {};"," var value = options.value || defaultValue;",""," return function(req, res, next){"," // generate CSRF token"," var token = req.session._csrf || (req.session._csrf = utils.uid(24));",""," // ignore these methods"," if ('GET' == req.method || 'HEAD' == req.method || 'OPTIONS' == req.method) return next();",""," // determine value"," var val = value(req);",""," // check"," if (val != token) return next(utils.error(403));"," "," next();"," }","};","","/**"," * Default value function, checking the `req.body`"," * and `req.query` for the CSRF token."," *"," * @param {IncomingMessage} req"," * @return {String}"," * @api private"," */","","function defaultValue(req) {"," return (req.body &amp;&amp; req.body._csrf)"," || (req.query &amp;&amp; req.query._csrf)"," || (req.headers['x-csrf-token']);","}"];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['middleware/directory.js']) {
_$jscoverage['middleware/directory.js'] = [];
_$jscoverage['middleware/directory.js'][17] = 0;
_$jscoverage['middleware/directory.js'][29] = 0;
_$jscoverage['middleware/directory.js'][48] = 0;
_$jscoverage['middleware/directory.js'][49] = 0;
_$jscoverage['middleware/directory.js'][52] = 0;
_$jscoverage['middleware/directory.js'][53] = 0;
_$jscoverage['middleware/directory.js'][58] = 0;
_$jscoverage['middleware/directory.js'][59] = 0;
_$jscoverage['middleware/directory.js'][61] = 0;
_$jscoverage['middleware/directory.js'][70] = 0;
_$jscoverage['middleware/directory.js'][73] = 0;
_$jscoverage['middleware/directory.js'][76] = 0;
_$jscoverage['middleware/directory.js'][77] = 0;
_$jscoverage['middleware/directory.js'][81] = 0;
_$jscoverage['middleware/directory.js'][84] = 0;
_$jscoverage['middleware/directory.js'][85] = 0;
_$jscoverage['middleware/directory.js'][86] = 0;
_$jscoverage['middleware/directory.js'][87] = 0;
_$jscoverage['middleware/directory.js'][88] = 0;
_$jscoverage['middleware/directory.js'][91] = 0;
_$jscoverage['middleware/directory.js'][92] = 0;
_$jscoverage['middleware/directory.js'][93] = 0;
_$jscoverage['middleware/directory.js'][94] = 0;
_$jscoverage['middleware/directory.js'][99] = 0;
_$jscoverage['middleware/directory.js'][109] = 0;
_$jscoverage['middleware/directory.js'][110] = 0;
_$jscoverage['middleware/directory.js'][111] = 0;
_$jscoverage['middleware/directory.js'][112] = 0;
_$jscoverage['middleware/directory.js'][113] = 0;
_$jscoverage['middleware/directory.js'][114] = 0;
_$jscoverage['middleware/directory.js'][115] = 0;
_$jscoverage['middleware/directory.js'][120] = 0;
_$jscoverage['middleware/directory.js'][121] = 0;
_$jscoverage['middleware/directory.js'][122] = 0;
_$jscoverage['middleware/directory.js'][131] = 0;
_$jscoverage['middleware/directory.js'][132] = 0;
_$jscoverage['middleware/directory.js'][133] = 0;
_$jscoverage['middleware/directory.js'][134] = 0;
_$jscoverage['middleware/directory.js'][135] = 0;
_$jscoverage['middleware/directory.js'][142] = 0;
_$jscoverage['middleware/directory.js'][143] = 0;
_$jscoverage['middleware/directory.js'][144] = 0;
_$jscoverage['middleware/directory.js'][145] = 0;
_$jscoverage['middleware/directory.js'][146] = 0;
_$jscoverage['middleware/directory.js'][153] = 0;
_$jscoverage['middleware/directory.js'][154] = 0;
_$jscoverage['middleware/directory.js'][155] = 0;
_$jscoverage['middleware/directory.js'][156] = 0;
_$jscoverage['middleware/directory.js'][157] = 0;
_$jscoverage['middleware/directory.js'][165] = 0;
_$jscoverage['middleware/directory.js'][166] = 0;
_$jscoverage['middleware/directory.js'][167] = 0;
_$jscoverage['middleware/directory.js'][170] = 0;
_$jscoverage['middleware/directory.js'][171] = 0;
_$jscoverage['middleware/directory.js'][172] = 0;
_$jscoverage['middleware/directory.js'][173] = 0;
_$jscoverage['middleware/directory.js'][176] = 0;
_$jscoverage['middleware/directory.js'][194] = 0;
_$jscoverage['middleware/directory.js'][195] = 0;
_$jscoverage['middleware/directory.js'][196] = 0;
_$jscoverage['middleware/directory.js'][208] = 0;
_$jscoverage['middleware/directory.js'][209] = 0;
_$jscoverage['middleware/directory.js'][210] = 0;
_$jscoverage['middleware/directory.js'][218] = 0;
}
_$jscoverage['middleware/directory.js'][17]++;
var fs = require("fs"), parse = require("url").parse, utils = require("../utils"), path = require("path"), normalize = path.normalize, extname = path.extname, join = path.join;
_$jscoverage['middleware/directory.js'][29]++;
var cache = {};
_$jscoverage['middleware/directory.js'][48]++;
exports = module.exports = (function directory(root, options) {
_$jscoverage['middleware/directory.js'][49]++;
options = options || {};
_$jscoverage['middleware/directory.js'][52]++;
if (! root) {
_$jscoverage['middleware/directory.js'][52]++;
throw new Error("directory() root path required");
}
_$jscoverage['middleware/directory.js'][53]++;
var hidden = options.hidden, icons = options.icons, filter = options.filter, root = normalize(root);
_$jscoverage['middleware/directory.js'][58]++;
return (function directory(req, res, next) {
_$jscoverage['middleware/directory.js'][59]++;
if ("GET" != req.method && "HEAD" != req.method) {
_$jscoverage['middleware/directory.js'][59]++;
return next();
}
_$jscoverage['middleware/directory.js'][61]++;
var accept = req.headers.accept || "text/plain", url = parse(req.url), dir = decodeURIComponent(url.pathname), path = normalize(join(root, dir)), originalUrl = parse(req.originalUrl), originalDir = decodeURIComponent(originalUrl.pathname), showUp = path != root && path != root + "/";
_$jscoverage['middleware/directory.js'][70]++;
if (~ path.indexOf("\u0000")) {
_$jscoverage['middleware/directory.js'][70]++;
return next(utils.error(400));
}
_$jscoverage['middleware/directory.js'][73]++;
if (0 != path.indexOf(root)) {
_$jscoverage['middleware/directory.js'][73]++;
return next(utils.error(403));
}
_$jscoverage['middleware/directory.js'][76]++;
fs.stat(path, (function (err, stat) {
_$jscoverage['middleware/directory.js'][77]++;
if (err) {
_$jscoverage['middleware/directory.js'][77]++;
return "ENOENT" == err.code? next(): next(err);
}
_$jscoverage['middleware/directory.js'][81]++;
if (! stat.isDirectory()) {
_$jscoverage['middleware/directory.js'][81]++;
return next();
}
_$jscoverage['middleware/directory.js'][84]++;
fs.readdir(path, (function (err, files) {
_$jscoverage['middleware/directory.js'][85]++;
if (err) {
_$jscoverage['middleware/directory.js'][85]++;
return next(err);
}
_$jscoverage['middleware/directory.js'][86]++;
if (! hidden) {
_$jscoverage['middleware/directory.js'][86]++;
files = removeHidden(files);
}
_$jscoverage['middleware/directory.js'][87]++;
if (filter) {
_$jscoverage['middleware/directory.js'][87]++;
files = files.filter(filter);
}
_$jscoverage['middleware/directory.js'][88]++;
files.sort();
_$jscoverage['middleware/directory.js'][91]++;
for (var key in exports) {
_$jscoverage['middleware/directory.js'][92]++;
if (~ accept.indexOf(key) || ~ accept.indexOf("*/*")) {
_$jscoverage['middleware/directory.js'][93]++;
exports[key](req, res, files, next, originalDir, showUp, icons);
_$jscoverage['middleware/directory.js'][94]++;
return;
}
}
_$jscoverage['middleware/directory.js'][99]++;
next(utils.error(406));
}));
}));
});
});
_$jscoverage['middleware/directory.js'][109]++;
exports.html = (function (req, res, files, next, dir, showUp, icons) {
_$jscoverage['middleware/directory.js'][110]++;
fs.readFile(__dirname + "/../public/directory.html", "utf8", (function (err, str) {
_$jscoverage['middleware/directory.js'][111]++;
if (err) {
_$jscoverage['middleware/directory.js'][111]++;
return next(err);
}
_$jscoverage['middleware/directory.js'][112]++;
fs.readFile(__dirname + "/../public/style.css", "utf8", (function (err, style) {
_$jscoverage['middleware/directory.js'][113]++;
if (err) {
_$jscoverage['middleware/directory.js'][113]++;
return next(err);
}
_$jscoverage['middleware/directory.js'][114]++;
if (showUp) {
_$jscoverage['middleware/directory.js'][114]++;
files.unshift("..");
}
_$jscoverage['middleware/directory.js'][115]++;
str = str.replace("{style}", style).replace("{files}", html(files, dir, icons)).replace("{directory}", dir).replace("{linked-path}", htmlPath(dir));
_$jscoverage['middleware/directory.js'][120]++;
res.setHeader("Content-Type", "text/html");
_$jscoverage['middleware/directory.js'][121]++;
res.setHeader("Content-Length", str.length);
_$jscoverage['middleware/directory.js'][122]++;
res.end(str);
}));
}));
});
_$jscoverage['middleware/directory.js'][131]++;
exports.json = (function (req, res, files) {
_$jscoverage['middleware/directory.js'][132]++;
files = JSON.stringify(files);
_$jscoverage['middleware/directory.js'][133]++;
res.setHeader("Content-Type", "application/json");
_$jscoverage['middleware/directory.js'][134]++;
res.setHeader("Content-Length", files.length);
_$jscoverage['middleware/directory.js'][135]++;
res.end(files);
});
_$jscoverage['middleware/directory.js'][142]++;
exports.plain = (function (req, res, files) {
_$jscoverage['middleware/directory.js'][143]++;
files = files.join("\n") + "\n";
_$jscoverage['middleware/directory.js'][144]++;
res.setHeader("Content-Type", "text/plain");
_$jscoverage['middleware/directory.js'][145]++;
res.setHeader("Content-Length", files.length);
_$jscoverage['middleware/directory.js'][146]++;
res.end(files);
});
_$jscoverage['middleware/directory.js'][153]++;
function htmlPath(dir) {
_$jscoverage['middleware/directory.js'][154]++;
var curr = [];
_$jscoverage['middleware/directory.js'][155]++;
return dir.split("/").map((function (part) {
_$jscoverage['middleware/directory.js'][156]++;
curr.push(part);
_$jscoverage['middleware/directory.js'][157]++;
return "<a href=\"" + curr.join("/") + "\">" + part + "</a>";
})).join(" / ");
}
_$jscoverage['middleware/directory.js'][165]++;
function html(files, dir, useIcons) {
_$jscoverage['middleware/directory.js'][166]++;
return "<ul id=\"files\">" + files.map((function (file) {
_$jscoverage['middleware/directory.js'][167]++;
var icon = "", classes = [];
_$jscoverage['middleware/directory.js'][170]++;
if (useIcons && ".." != file) {
_$jscoverage['middleware/directory.js'][171]++;
icon = icons[extname(file)] || icons["default"];
_$jscoverage['middleware/directory.js'][172]++;
icon = "<img src=\"data:image/png;base64," + load(icon) + "\" />";
_$jscoverage['middleware/directory.js'][173]++;
classes.push("icon");
}
_$jscoverage['middleware/directory.js'][176]++;
return "<li><a href=\"" + join(dir, file) + "\" class=\"" + classes.join(" ") + "\"" + " title=\"" + file + "\">" + icon + file + "</a></li>";
})).join("\n") + "</ul>";
}
_$jscoverage['middleware/directory.js'][194]++;
function load(icon) {
_$jscoverage['middleware/directory.js'][195]++;
if (cache[icon]) {
_$jscoverage['middleware/directory.js'][195]++;
return cache[icon];
}
_$jscoverage['middleware/directory.js'][196]++;
return cache[icon] = fs.readFileSync(__dirname + "/../public/icons/" + icon, "base64");
}
_$jscoverage['middleware/directory.js'][208]++;
function removeHidden(files) {
_$jscoverage['middleware/directory.js'][209]++;
return files.filter((function (file) {
_$jscoverage['middleware/directory.js'][210]++;
return "." != file[0];
}));
}
_$jscoverage['middleware/directory.js'][218]++;
var icons = {".js": "page_white_code_red.png", ".c": "page_white_c.png", ".h": "page_white_h.png", ".cc": "page_white_cplusplus.png", ".php": "page_white_php.png", ".rb": "page_white_ruby.png", ".cpp": "page_white_cplusplus.png", ".swf": "page_white_flash.png", ".pdf": "page_white_acrobat.png", "default": "page_white.png"};
_$jscoverage['middleware/directory.js'].source = ["","/*!"," * Connect - directory"," * Copyright(c) 2011 Sencha Inc."," * Copyright(c) 2011 TJ Holowaychuk"," * MIT Licensed"," */","","// TODO: icon / style for directories","// TODO: arrow key navigation","// TODO: make icons extensible","","/**"," * Module dependencies."," */","","var fs = require('fs')"," , parse = require('url').parse"," , utils = require('../utils')"," , path = require('path')"," , normalize = path.normalize"," , extname = path.extname"," , join = path.join;","","/*!"," * Icon cache."," */","","var cache = {};","","/**"," * Directory:"," *"," * Serve directory listings with the given `root` path."," *"," * Options:"," *"," * - `hidden` display hidden (dot) files. Defaults to false."," * - `icons` display icons. Defaults to false."," * - `filter` Apply this filter function to files. Defaults to false."," *"," * @param {String} root"," * @param {Object} options"," * @return {Function}"," * @api public"," */","","exports = module.exports = function directory(root, options){"," options = options || {};",""," // root required"," if (!root) throw new Error('directory() root path required');"," var hidden = options.hidden"," , icons = options.icons"," , filter = options.filter"," , root = normalize(root);",""," return function directory(req, res, next) {"," if ('GET' != req.method &amp;&amp; 'HEAD' != req.method) return next();",""," var accept = req.headers.accept || 'text/plain'"," , url = parse(req.url)"," , dir = decodeURIComponent(url.pathname)"," , path = normalize(join(root, dir))"," , originalUrl = parse(req.originalUrl)"," , originalDir = decodeURIComponent(originalUrl.pathname)"," , showUp = path != root &amp;&amp; path != root + '/';",""," // null byte(s), bad request"," if (~path.indexOf('\\0')) return next(utils.error(400));",""," // malicious path, forbidden"," if (0 != path.indexOf(root)) return next(utils.error(403));",""," // check if we have a directory"," fs.stat(path, function(err, stat){"," if (err) return 'ENOENT' == err.code"," ? next()"," : next(err);",""," if (!stat.isDirectory()) return next();",""," // fetch files"," fs.readdir(path, function(err, files){"," if (err) return next(err);"," if (!hidden) files = removeHidden(files);"," if (filter) files = files.filter(filter);"," files.sort();",""," // content-negotiation"," for (var key in exports) {"," if (~accept.indexOf(key) || ~accept.indexOf('*/*')) {"," exports[key](req, res, files, next, originalDir, showUp, icons);"," return;"," }"," }",""," // not acceptable"," next(utils.error(406));"," });"," });"," };","};","","/**"," * Respond with text/html."," */","","exports.html = function(req, res, files, next, dir, showUp, icons){"," fs.readFile(__dirname + '/../public/directory.html', 'utf8', function(err, str){"," if (err) return next(err);"," fs.readFile(__dirname + '/../public/style.css', 'utf8', function(err, style){"," if (err) return next(err);"," if (showUp) files.unshift('..');"," str = str"," .replace('{style}', style)"," .replace('{files}', html(files, dir, icons))"," .replace('{directory}', dir)"," .replace('{linked-path}', htmlPath(dir));"," res.setHeader('Content-Type', 'text/html');"," res.setHeader('Content-Length', str.length);"," res.end(str);"," });"," });","};","","/**"," * Respond with application/json."," */","","exports.json = function(req, res, files){"," files = JSON.stringify(files);"," res.setHeader('Content-Type', 'application/json');"," res.setHeader('Content-Length', files.length);"," res.end(files);","};","","/**"," * Respond with text/plain."," */","","exports.plain = function(req, res, files){"," files = files.join('\\n') + '\\n';"," res.setHeader('Content-Type', 'text/plain');"," res.setHeader('Content-Length', files.length);"," res.end(files);","};","","/**"," * Map html `dir`, returning a linked path."," */","","function htmlPath(dir) {"," var curr = [];"," return dir.split('/').map(function(part){"," curr.push(part);"," return '&lt;a href=\"' + curr.join('/') + '\"&gt;' + part + '&lt;/a&gt;';"," }).join(' / ');","}","","/**"," * Map html `files`, returning an html unordered list."," */","","function html(files, dir, useIcons) {"," return '&lt;ul id=\"files\"&gt;' + files.map(function(file){"," var icon = ''"," , classes = [];",""," if (useIcons &amp;&amp; '..' != file) {"," icon = icons[extname(file)] || icons.default;"," icon = '&lt;img src=\"data:image/png;base64,' + load(icon) + '\" /&gt;';"," classes.push('icon');"," }",""," return '&lt;li&gt;&lt;a href=\"'"," + join(dir, file)"," + '\" class=\"'"," + classes.join(' ') + '\"'"," + ' title=\"' + file + '\"&gt;'"," + icon + file + '&lt;/a&gt;&lt;/li&gt;';",""," }).join('\\n') + '&lt;/ul&gt;';","}","","/**"," * Load and cache the given `icon`."," *"," * @param {String} icon"," * @return {String}"," * @api private"," */","","function load(icon) {"," if (cache[icon]) return cache[icon];"," return cache[icon] = fs.readFileSync(__dirname + '/../public/icons/' + icon, 'base64');","}","","/**"," * Filter \"hidden\" `files`, aka files"," * beginning with a `.`."," *"," * @param {Array} files"," * @return {Array}"," * @api private"," */","","function removeHidden(files) {"," return files.filter(function(file){"," return '.' != file[0];"," });","}","","/**"," * Icon map."," */","","var icons = {"," '.js': 'page_white_code_red.png'"," , '.c': 'page_white_c.png'"," , '.h': 'page_white_h.png'"," , '.cc': 'page_white_cplusplus.png'"," , '.php': 'page_white_php.png'"," , '.rb': 'page_white_ruby.png'"," , '.cpp': 'page_white_cplusplus.png'"," , '.swf': 'page_white_flash.png'"," , '.pdf': 'page_white_acrobat.png'"," , 'default': 'page_white.png'","};"];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['middleware/errorHandler.js']) {
_$jscoverage['middleware/errorHandler.js'] = [];
_$jscoverage['middleware/errorHandler.js'][12] = 0;
_$jscoverage['middleware/errorHandler.js'][17] = 0;
_$jscoverage['middleware/errorHandler.js'][44] = 0;
_$jscoverage['middleware/errorHandler.js'][45] = 0;
_$jscoverage['middleware/errorHandler.js'][46] = 0;
_$jscoverage['middleware/errorHandler.js'][47] = 0;
_$jscoverage['middleware/errorHandler.js'][48] = 0;
_$jscoverage['middleware/errorHandler.js'][49] = 0;
_$jscoverage['middleware/errorHandler.js'][51] = 0;
_$jscoverage['middleware/errorHandler.js'][52] = 0;
_$jscoverage['middleware/errorHandler.js'][53] = 0;
_$jscoverage['middleware/errorHandler.js'][54] = 0;
_$jscoverage['middleware/errorHandler.js'][56] = 0;
_$jscoverage['middleware/errorHandler.js'][57] = 0;
_$jscoverage['middleware/errorHandler.js'][63] = 0;
_$jscoverage['middleware/errorHandler.js'][64] = 0;
_$jscoverage['middleware/errorHandler.js'][68] = 0;
_$jscoverage['middleware/errorHandler.js'][69] = 0;
_$jscoverage['middleware/errorHandler.js'][70] = 0;
_$jscoverage['middleware/errorHandler.js'][71] = 0;
_$jscoverage['middleware/errorHandler.js'][72] = 0;
_$jscoverage['middleware/errorHandler.js'][73] = 0;
_$jscoverage['middleware/errorHandler.js'][76] = 0;
_$jscoverage['middleware/errorHandler.js'][77] = 0;
_$jscoverage['middleware/errorHandler.js'][86] = 0;
}
_$jscoverage['middleware/errorHandler.js'][12]++;
var utils = require("../utils"), fs = require("fs");
_$jscoverage['middleware/errorHandler.js'][17]++;
var env = process.env.NODE_ENV || "development";
_$jscoverage['middleware/errorHandler.js'][44]++;
exports = module.exports = (function errorHandler() {
_$jscoverage['middleware/errorHandler.js'][45]++;
return (function errorHandler(err, req, res, next) {
_$jscoverage['middleware/errorHandler.js'][46]++;
if (err.status) {
_$jscoverage['middleware/errorHandler.js'][46]++;
res.statusCode = err.status;
}
_$jscoverage['middleware/errorHandler.js'][47]++;
if (res.statusCode < 400) {
_$jscoverage['middleware/errorHandler.js'][47]++;
res.statusCode = 500;
}
_$jscoverage['middleware/errorHandler.js'][48]++;
if ("test" != env) {
_$jscoverage['middleware/errorHandler.js'][48]++;
console.error(err.stack);
}
_$jscoverage['middleware/errorHandler.js'][49]++;
var accept = req.headers.accept || "";
_$jscoverage['middleware/errorHandler.js'][51]++;
if (~ accept.indexOf("html")) {
_$jscoverage['middleware/errorHandler.js'][52]++;
fs.readFile(__dirname + "/../public/style.css", "utf8", (function (e, style) {
_$jscoverage['middleware/errorHandler.js'][53]++;
fs.readFile(__dirname + "/../public/error.html", "utf8", (function (e, html) {
_$jscoverage['middleware/errorHandler.js'][54]++;
var stack = (err.stack || "").split("\n").slice(1).map((function (v) {
_$jscoverage['middleware/errorHandler.js'][56]++;
return "<li>" + v + "</li>";
})).join("");
_$jscoverage['middleware/errorHandler.js'][57]++;
html = html.replace("{style}", style).replace("{stack}", stack).replace("{title}", exports.title).replace("{statusCode}", res.statusCode).replace(/\{error\}/g, utils.escape(err.toString()));
_$jscoverage['middleware/errorHandler.js'][63]++;
res.setHeader("Content-Type", "text/html; charset=utf-8");
_$jscoverage['middleware/errorHandler.js'][64]++;
res.end(html);
}));
}));
}
else {
_$jscoverage['middleware/errorHandler.js'][68]++;
if (~ accept.indexOf("json")) {
_$jscoverage['middleware/errorHandler.js'][69]++;
var error = {message: err.message, stack: err.stack};
_$jscoverage['middleware/errorHandler.js'][70]++;
for (var prop in err) {
_$jscoverage['middleware/errorHandler.js'][70]++;
error[prop] = err[prop];
}
_$jscoverage['middleware/errorHandler.js'][71]++;
var json = JSON.stringify({error: error});
_$jscoverage['middleware/errorHandler.js'][72]++;
res.setHeader("Content-Type", "application/json");
_$jscoverage['middleware/errorHandler.js'][73]++;
res.end(json);
}
else {
_$jscoverage['middleware/errorHandler.js'][76]++;
res.writeHead(res.statusCode, {"Content-Type": "text/plain"});
_$jscoverage['middleware/errorHandler.js'][77]++;
res.end(err.stack);
}
}
});
});
_$jscoverage['middleware/errorHandler.js'][86]++;
exports.title = "Connect";
_$jscoverage['middleware/errorHandler.js'].source = ["/*!"," * Connect - errorHandler"," * Copyright(c) 2010 Sencha Inc."," * Copyright(c) 2011 TJ Holowaychuk"," * MIT Licensed"," */","","/**"," * Module dependencies."," */","","var utils = require('../utils')"," , fs = require('fs');","","// environment","","var env = process.env.NODE_ENV || 'development';","","/**"," * Error handler:"," *"," * Development error handler, providing stack traces"," * and error message responses for requests accepting text, html,"," * or json."," *"," * Text:"," *"," * By default, and when _text/plain_ is accepted a simple stack trace"," * or error message will be returned."," *"," * JSON:"," *"," * When _application/json_ is accepted, connect will respond with"," * an object in the form of `{ \"error\": error }`."," *"," * HTML:"," *"," * When accepted connect will output a nice html stack trace."," *"," * @return {Function}"," * @api public"," */","","exports = module.exports = function errorHandler(){"," return function errorHandler(err, req, res, next){"," if (err.status) res.statusCode = err.status;"," if (res.statusCode &lt; 400) res.statusCode = 500;"," if ('test' != env) console.error(err.stack);"," var accept = req.headers.accept || '';"," // html"," if (~accept.indexOf('html')) {"," fs.readFile(__dirname + '/../public/style.css', 'utf8', function(e, style){"," fs.readFile(__dirname + '/../public/error.html', 'utf8', function(e, html){"," var stack = (err.stack || '')"," .split('\\n').slice(1)"," .map(function(v){ return '&lt;li&gt;' + v + '&lt;/li&gt;'; }).join('');"," html = html"," .replace('{style}', style)"," .replace('{stack}', stack)"," .replace('{title}', exports.title)"," .replace('{statusCode}', res.statusCode)"," .replace(/\\{error\\}/g, utils.escape(err.toString()));"," res.setHeader('Content-Type', 'text/html; charset=utf-8');"," res.end(html);"," });"," });"," // json"," } else if (~accept.indexOf('json')) {"," var error = { message: err.message, stack: err.stack };"," for (var prop in err) error[prop] = err[prop];"," var json = JSON.stringify({ error: error });"," res.setHeader('Content-Type', 'application/json');"," res.end(json);"," // plain text"," } else {"," res.writeHead(res.statusCode, { 'Content-Type': 'text/plain' });"," res.end(err.stack);"," }"," };","};","","/**"," * Template title, framework authors may override this value."," */","","exports.title = 'Connect';"];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['middleware/favicon.js']) {
_$jscoverage['middleware/favicon.js'] = [];
_$jscoverage['middleware/favicon.js'][13] = 0;
_$jscoverage['middleware/favicon.js'][50] = 0;
_$jscoverage['middleware/favicon.js'][51] = 0;
_$jscoverage['middleware/favicon.js'][56] = 0;
_$jscoverage['middleware/favicon.js'][57] = 0;
_$jscoverage['middleware/favicon.js'][58] = 0;
_$jscoverage['middleware/favicon.js'][59] = 0;
_$jscoverage['middleware/favicon.js'][60] = 0;
_$jscoverage['middleware/favicon.js'][62] = 0;
_$jscoverage['middleware/favicon.js'][63] = 0;
_$jscoverage['middleware/favicon.js'][64] = 0;
_$jscoverage['middleware/favicon.js'][73] = 0;
_$jscoverage['middleware/favicon.js'][74] = 0;
_$jscoverage['middleware/favicon.js'][78] = 0;
}
_$jscoverage['middleware/favicon.js'][13]++;
var fs = require("fs"), utils = require("../utils");
_$jscoverage['middleware/favicon.js'][50]++;
module.exports = (function favicon(path, options) {
_$jscoverage['middleware/favicon.js'][51]++;
var options = options || {}, path = path || __dirname + "/../public/favicon.ico", maxAge = options.maxAge || 86400000, icon;
_$jscoverage['middleware/favicon.js'][56]++;
return (function favicon(req, res, next) {
_$jscoverage['middleware/favicon.js'][57]++;
if ("/favicon.ico" == req.url) {
_$jscoverage['middleware/favicon.js'][58]++;
if (icon) {
_$jscoverage['middleware/favicon.js'][59]++;
res.writeHead(200, icon.headers);
_$jscoverage['middleware/favicon.js'][60]++;
res.end(icon.body);
}
else {
_$jscoverage['middleware/favicon.js'][62]++;
fs.readFile(path, (function (err, buf) {
_$jscoverage['middleware/favicon.js'][63]++;
if (err) {
_$jscoverage['middleware/favicon.js'][63]++;
return next(err);
}
_$jscoverage['middleware/favicon.js'][64]++;
icon = {headers: {"Content-Type": "image/x-icon", "Content-Length": buf.length, "ETag": "\"" + utils.md5(buf) + "\"", "Cache-Control": "public, max-age=" + (maxAge / 1000)}, body: buf};
_$jscoverage['middleware/favicon.js'][73]++;
res.writeHead(200, icon.headers);
_$jscoverage['middleware/favicon.js'][74]++;
res.end(icon.body);
}));
}
}
else {
_$jscoverage['middleware/favicon.js'][78]++;
next();
}
});
});
_$jscoverage['middleware/favicon.js'].source = ["","/*!"," * Connect - favicon"," * Copyright(c) 2010 Sencha Inc."," * Copyright(c) 2011 TJ Holowaychuk"," * MIT Licensed"," */","","/**"," * Module dependencies."," */","","var fs = require('fs')"," , utils = require('../utils');","","/**"," * Favicon:"," *"," * By default serves the connect favicon, or the favicon"," * located by the given `path`."," *"," * Options:"," *"," * - `maxAge` cache-control max-age directive, defaulting to 1 day"," *"," * Examples:"," *"," * Serve default favicon:"," *"," * connect()"," * .use(connect.favicon())"," *"," * Serve favicon before logging for brevity:"," *"," * connect()"," * .use(connect.favicon())"," * .use(connect.logger('dev'))"," *"," * Serve custom favicon:"," *"," * connect()"," * .use(connect.favicon('public/favicon.ico))"," *"," * @param {String} path"," * @param {Object} options"," * @return {Function}"," * @api public"," */","","module.exports = function favicon(path, options){"," var options = options || {}"," , path = path || __dirname + '/../public/favicon.ico'"," , maxAge = options.maxAge || 86400000"," , icon; // favicon cache",""," return function favicon(req, res, next){"," if ('/favicon.ico' == req.url) {"," if (icon) {"," res.writeHead(200, icon.headers);"," res.end(icon.body);"," } else {"," fs.readFile(path, function(err, buf){"," if (err) return next(err);"," icon = {"," headers: {"," 'Content-Type': 'image/x-icon'"," , 'Content-Length': buf.length"," , 'ETag': '\"' + utils.md5(buf) + '\"'"," , 'Cache-Control': 'public, max-age=' + (maxAge / 1000)"," },"," body: buf"," };"," res.writeHead(200, icon.headers);"," res.end(icon.body);"," });"," }"," } else {"," next();"," }"," };","};"];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['middleware/json.js']) {
_$jscoverage['middleware/json.js'] = [];
_$jscoverage['middleware/json.js'][13] = 0;
_$jscoverage['middleware/json.js'][20] = 0;
_$jscoverage['middleware/json.js'][21] = 0;
_$jscoverage['middleware/json.js'][41] = 0;
_$jscoverage['middleware/json.js'][42] = 0;
_$jscoverage['middleware/json.js'][45] = 0;
_$jscoverage['middleware/json.js'][49] = 0;
_$jscoverage['middleware/json.js'][50] = 0;
_$jscoverage['middleware/json.js'][51] = 0;
_$jscoverage['middleware/json.js'][53] = 0;
_$jscoverage['middleware/json.js'][56] = 0;
_$jscoverage['middleware/json.js'][59] = 0;
_$jscoverage['middleware/json.js'][62] = 0;
_$jscoverage['middleware/json.js'][63] = 0;
_$jscoverage['middleware/json.js'][64] = 0;
_$jscoverage['middleware/json.js'][65] = 0;
_$jscoverage['middleware/json.js'][66] = 0;
_$jscoverage['middleware/json.js'][67] = 0;
_$jscoverage['middleware/json.js'][68] = 0;
_$jscoverage['middleware/json.js'][70] = 0;
_$jscoverage['middleware/json.js'][71] = 0;
_$jscoverage['middleware/json.js'][74] = 0;
_$jscoverage['middleware/json.js'][75] = 0;
_$jscoverage['middleware/json.js'][76] = 0;
_$jscoverage['middleware/json.js'][77] = 0;
_$jscoverage['middleware/json.js'][79] = 0;
_$jscoverage['middleware/json.js'][80] = 0;
_$jscoverage['middleware/json.js'][81] = 0;
}
_$jscoverage['middleware/json.js'][13]++;
var utils = require("../utils"), _limit = require("./limit");
_$jscoverage['middleware/json.js'][20]++;
function noop(req, res, next) {
_$jscoverage['middleware/json.js'][21]++;
next();
}
_$jscoverage['middleware/json.js'][41]++;
exports = module.exports = (function (options) {
_$jscoverage['middleware/json.js'][42]++;
var options = options || {}, strict = options.strict !== false;
_$jscoverage['middleware/json.js'][45]++;
var limit = options.limit? _limit(options.limit): noop;
_$jscoverage['middleware/json.js'][49]++;
return (function json(req, res, next) {
_$jscoverage['middleware/json.js'][50]++;
if (req._body) {
_$jscoverage['middleware/json.js'][50]++;
return next();
}
_$jscoverage['middleware/json.js'][51]++;
req.body = req.body || {};
_$jscoverage['middleware/json.js'][53]++;
if (! utils.hasBody(req)) {
_$jscoverage['middleware/json.js'][53]++;
return next();
}
_$jscoverage['middleware/json.js'][56]++;
if ("application/json" != utils.mime(req)) {
_$jscoverage['middleware/json.js'][56]++;
return next();
}
_$jscoverage['middleware/json.js'][59]++;
req._body = true;
_$jscoverage['middleware/json.js'][62]++;
limit(req, res, (function (err) {
_$jscoverage['middleware/json.js'][63]++;
if (err) {
_$jscoverage['middleware/json.js'][63]++;
return next(err);
}
_$jscoverage['middleware/json.js'][64]++;
var buf = "";
_$jscoverage['middleware/json.js'][65]++;
req.setEncoding("utf8");
_$jscoverage['middleware/json.js'][66]++;
req.on("data", (function (chunk) {
_$jscoverage['middleware/json.js'][66]++;
buf += chunk;
}));
_$jscoverage['middleware/json.js'][67]++;
req.on("end", (function () {
_$jscoverage['middleware/json.js'][68]++;
var first = buf.trim()[0];
_$jscoverage['middleware/json.js'][70]++;
if (0 == buf.length) {
_$jscoverage['middleware/json.js'][71]++;
return next(utils.error(400, "invalid json, empty body"));
}
_$jscoverage['middleware/json.js'][74]++;
if (strict && "{" != first && "[" != first) {
_$jscoverage['middleware/json.js'][74]++;
return next(utils.error(400, "invalid json"));
}
_$jscoverage['middleware/json.js'][75]++;
try {
_$jscoverage['middleware/json.js'][76]++;
req.body = JSON.parse(buf, options.reviver);
_$jscoverage['middleware/json.js'][77]++;
next();
}
catch (err) {
_$jscoverage['middleware/json.js'][79]++;
err.body = buf;
_$jscoverage['middleware/json.js'][80]++;
err.status = 400;
_$jscoverage['middleware/json.js'][81]++;
next(err);
}
}));
}));
});
});
_$jscoverage['middleware/json.js'].source = ["","/*!"," * Connect - json"," * Copyright(c) 2010 Sencha Inc."," * Copyright(c) 2011 TJ Holowaychuk"," * MIT Licensed"," */","","/**"," * Module dependencies."," */","","var utils = require('../utils')"," , _limit = require('./limit');","","/**"," * noop middleware."," */","","function noop(req, res, next) {"," next();","}","","/**"," * JSON:"," *"," * Parse JSON request bodies, providing the"," * parsed object as `req.body`."," *"," * Options:"," *"," * - `strict` when `false` anything `JSON.parse()` accepts will be parsed"," * - `reviver` used as the second \"reviver\" argument for JSON.parse"," * - `limit` byte limit disabled by default"," *"," * @param {Object} options"," * @return {Function}"," * @api public"," */","","exports = module.exports = function(options){"," var options = options || {}"," , strict = options.strict !== false;",""," var limit = options.limit"," ? _limit(options.limit)"," : noop;",""," return function json(req, res, next) {"," if (req._body) return next();"," req.body = req.body || {};",""," if (!utils.hasBody(req)) return next();",""," // check Content-Type"," if ('application/json' != utils.mime(req)) return next();",""," // flag as parsed"," req._body = true;",""," // parse"," limit(req, res, function(err){"," if (err) return next(err);"," var buf = '';"," req.setEncoding('utf8');"," req.on('data', function(chunk){ buf += chunk });"," req.on('end', function(){"," var first = buf.trim()[0];",""," if (0 == buf.length) {"," return next(utils.error(400, 'invalid json, empty body'));"," }"," "," if (strict &amp;&amp; '{' != first &amp;&amp; '[' != first) return next(utils.error(400, 'invalid json'));"," try {"," req.body = JSON.parse(buf, options.reviver);"," next();"," } catch (err){"," err.body = buf;"," err.status = 400;"," next(err);"," }"," });"," });"," }","};"];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['middleware/limit.js']) {
_$jscoverage['middleware/limit.js'] = [];
_$jscoverage['middleware/limit.js'][12] = 0;
_$jscoverage['middleware/limit.js'][31] = 0;
_$jscoverage['middleware/limit.js'][32] = 0;
_$jscoverage['middleware/limit.js'][33] = 0;
_$jscoverage['middleware/limit.js'][34] = 0;
_$jscoverage['middleware/limit.js'][35] = 0;
_$jscoverage['middleware/limit.js'][41] = 0;
_$jscoverage['middleware/limit.js'][42] = 0;
_$jscoverage['middleware/limit.js'][45] = 0;
_$jscoverage['middleware/limit.js'][48] = 0;
_$jscoverage['middleware/limit.js'][49] = 0;
_$jscoverage['middleware/limit.js'][50] = 0;
_$jscoverage['middleware/limit.js'][53] = 0;
}
_$jscoverage['middleware/limit.js'][12]++;
var utils = require("../utils");
_$jscoverage['middleware/limit.js'][31]++;
module.exports = (function limit(bytes) {
_$jscoverage['middleware/limit.js'][32]++;
if ("string" == typeof bytes) {
_$jscoverage['middleware/limit.js'][32]++;
bytes = utils.parseBytes(bytes);
}
_$jscoverage['middleware/limit.js'][33]++;
if ("number" != typeof bytes) {
_$jscoverage['middleware/limit.js'][33]++;
throw new Error("limit() bytes required");
}
_$jscoverage['middleware/limit.js'][34]++;
return (function limit(req, res, next) {
_$jscoverage['middleware/limit.js'][35]++;
var received = 0, len = req.headers["content-length"]? parseInt(req.headers["content-length"], 10): null;
_$jscoverage['middleware/limit.js'][41]++;
if (req._limit) {
_$jscoverage['middleware/limit.js'][41]++;
return next();
}
_$jscoverage['middleware/limit.js'][42]++;
req._limit = true;
_$jscoverage['middleware/limit.js'][45]++;
if (len && len > bytes) {
_$jscoverage['middleware/limit.js'][45]++;
return next(utils.error(413));
}
_$jscoverage['middleware/limit.js'][48]++;
req.on("data", (function (chunk) {
_$jscoverage['middleware/limit.js'][49]++;
received += chunk.length;
_$jscoverage['middleware/limit.js'][50]++;
if (received > bytes) {
_$jscoverage['middleware/limit.js'][50]++;
req.destroy();
}
}));
_$jscoverage['middleware/limit.js'][53]++;
next();
});
});
_$jscoverage['middleware/limit.js'].source = ["","/*!"," * Connect - limit"," * Copyright(c) 2011 TJ Holowaychuk"," * MIT Licensed"," */","","/**"," * Module dependencies."," */","","var utils = require('../utils');","","/**"," * Limit:"," *"," * Limit request bodies to the given size in `bytes`."," *"," * A string representation of the bytesize may also be passed,"," * for example \"5mb\", \"200kb\", \"1gb\", etc."," *"," * connect()"," * .use(connect.limit('5.5mb'))"," * .use(handleImageUpload)"," *"," * @param {Number|String} bytes"," * @return {Function}"," * @api public"," */","","module.exports = function limit(bytes){"," if ('string' == typeof bytes) bytes = utils.parseBytes(bytes);"," if ('number' != typeof bytes) throw new Error('limit() bytes required');"," return function limit(req, res, next){"," var received = 0"," , len = req.headers['content-length']"," ? parseInt(req.headers['content-length'], 10)"," : null;",""," // self-awareness"," if (req._limit) return next();"," req._limit = true;",""," // limit by content-length"," if (len &amp;&amp; len &gt; bytes) return next(utils.error(413));",""," // limit"," req.on('data', function(chunk){"," received += chunk.length;"," if (received &gt; bytes) req.destroy();"," });",""," next();"," };","};"];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['middleware/logger.js']) {
_$jscoverage['middleware/logger.js'] = [];
_$jscoverage['middleware/logger.js'][12] = 0;
_$jscoverage['middleware/logger.js'][18] = 0;
_$jscoverage['middleware/logger.js'][24] = 0;
_$jscoverage['middleware/logger.js'][90] = 0;
_$jscoverage['middleware/logger.js'][91] = 0;
_$jscoverage['middleware/logger.js'][92] = 0;
_$jscoverage['middleware/logger.js'][93] = 0;
_$jscoverage['middleware/logger.js'][94] = 0;
_$jscoverage['middleware/logger.js'][96] = 0;
_$jscoverage['middleware/logger.js'][100] = 0;
_$jscoverage['middleware/logger.js'][103] = 0;
_$jscoverage['middleware/logger.js'][106] = 0;
_$jscoverage['middleware/logger.js'][109] = 0;
_$jscoverage['middleware/logger.js'][113] = 0;
_$jscoverage['middleware/logger.js'][114] = 0;
_$jscoverage['middleware/logger.js'][120] = 0;
_$jscoverage['middleware/logger.js'][121] = 0;
_$jscoverage['middleware/logger.js'][122] = 0;
_$jscoverage['middleware/logger.js'][123] = 0;
_$jscoverage['middleware/logger.js'][128] = 0;
_$jscoverage['middleware/logger.js'][130] = 0;
_$jscoverage['middleware/logger.js'][135] = 0;
_$jscoverage['middleware/logger.js'][136] = 0;
_$jscoverage['middleware/logger.js'][139] = 0;
_$jscoverage['middleware/logger.js'][140] = 0;
_$jscoverage['middleware/logger.js'][141] = 0;
_$jscoverage['middleware/logger.js'][142] = 0;
_$jscoverage['middleware/logger.js'][145] = 0;
_$jscoverage['middleware/logger.js'][146] = 0;
_$jscoverage['middleware/logger.js'][147] = 0;
_$jscoverage['middleware/logger.js'][148] = 0;
_$jscoverage['middleware/logger.js'][149] = 0;
_$jscoverage['middleware/logger.js'][150] = 0;
_$jscoverage['middleware/logger.js'][151] = 0;
_$jscoverage['middleware/logger.js'][156] = 0;
_$jscoverage['middleware/logger.js'][168] = 0;
_$jscoverage['middleware/logger.js'][169] = 0;
_$jscoverage['middleware/logger.js'][170] = 0;
_$jscoverage['middleware/logger.js'][171] = 0;
_$jscoverage['middleware/logger.js'][173] = 0;
_$jscoverage['middleware/logger.js'][174] = 0;
_$jscoverage['middleware/logger.js'][186] = 0;
_$jscoverage['middleware/logger.js'][187] = 0;
_$jscoverage['middleware/logger.js'][188] = 0;
_$jscoverage['middleware/logger.js'][200] = 0;
_$jscoverage['middleware/logger.js'][201] = 0;
_$jscoverage['middleware/logger.js'][202] = 0;
_$jscoverage['middleware/logger.js'][209] = 0;
_$jscoverage['middleware/logger.js'][215] = 0;
_$jscoverage['middleware/logger.js'][221] = 0;
_$jscoverage['middleware/logger.js'][227] = 0;
_$jscoverage['middleware/logger.js'][228] = 0;
_$jscoverage['middleware/logger.js'][232] = 0;
_$jscoverage['middleware/logger.js'][233] = 0;
_$jscoverage['middleware/logger.js'][234] = 0;
_$jscoverage['middleware/logger.js'][236] = 0;
_$jscoverage['middleware/logger.js'][240] = 0;
_$jscoverage['middleware/logger.js'][253] = 0;
_$jscoverage['middleware/logger.js'][254] = 0;
_$jscoverage['middleware/logger.js'][261] = 0;
_$jscoverage['middleware/logger.js'][262] = 0;
_$jscoverage['middleware/logger.js'][269] = 0;
_$jscoverage['middleware/logger.js'][270] = 0;
_$jscoverage['middleware/logger.js'][277] = 0;
_$jscoverage['middleware/logger.js'][278] = 0;
_$jscoverage['middleware/logger.js'][285] = 0;
_$jscoverage['middleware/logger.js'][286] = 0;
_$jscoverage['middleware/logger.js'][293] = 0;
_$jscoverage['middleware/logger.js'][294] = 0;
_$jscoverage['middleware/logger.js'][301] = 0;
_$jscoverage['middleware/logger.js'][302] = 0;
_$jscoverage['middleware/logger.js'][303] = 0;
_$jscoverage['middleware/logger.js'][304] = 0;
_$jscoverage['middleware/logger.js'][305] = 0;
_$jscoverage['middleware/logger.js'][312] = 0;
_$jscoverage['middleware/logger.js'][313] = 0;
_$jscoverage['middleware/logger.js'][320] = 0;
_$jscoverage['middleware/logger.js'][321] = 0;
_$jscoverage['middleware/logger.js'][328] = 0;
_$jscoverage['middleware/logger.js'][329] = 0;
_$jscoverage['middleware/logger.js'][336] = 0;
_$jscoverage['middleware/logger.js'][337] = 0;
}
_$jscoverage['middleware/logger.js'][12]++;
var bytes = require("bytes");
_$jscoverage['middleware/logger.js'][18]++;
var buf = [];
_$jscoverage['middleware/logger.js'][24]++;
var defaultBufferDuration = 1000;
_$jscoverage['middleware/logger.js'][90]++;
exports = module.exports = (function logger(options) {
_$jscoverage['middleware/logger.js'][91]++;
if ("object" == typeof options) {
_$jscoverage['middleware/logger.js'][92]++;
options = options || {};
}
else {
_$jscoverage['middleware/logger.js'][93]++;
if (options) {
_$jscoverage['middleware/logger.js'][94]++;
options = {format: options};
}
else {
_$jscoverage['middleware/logger.js'][96]++;
options = {};
}
}
_$jscoverage['middleware/logger.js'][100]++;
var immediate = options.immediate;
_$jscoverage['middleware/logger.js'][103]++;
var fmt = exports[options.format] || options.format || exports["default"];
_$jscoverage['middleware/logger.js'][106]++;
if ("function" != typeof fmt) {
_$jscoverage['middleware/logger.js'][106]++;
fmt = compile(fmt);
}
_$jscoverage['middleware/logger.js'][109]++;
var stream = options.stream || process.stdout, buffer = options.buffer;
_$jscoverage['middleware/logger.js'][113]++;
if (buffer) {
_$jscoverage['middleware/logger.js'][114]++;
var realStream = stream, interval = "number" == typeof buffer? buffer: defaultBufferDuration;
_$jscoverage['middleware/logger.js'][120]++;
setInterval((function () {
_$jscoverage['middleware/logger.js'][121]++;
if (buf.length) {
_$jscoverage['middleware/logger.js'][122]++;
realStream.write(buf.join(""));
_$jscoverage['middleware/logger.js'][123]++;
buf.length = 0;
}
}), interval);
_$jscoverage['middleware/logger.js'][128]++;
stream = {write: (function (str) {
_$jscoverage['middleware/logger.js'][130]++;
buf.push(str);
})};
}
_$jscoverage['middleware/logger.js'][135]++;
return (function logger(req, res, next) {
_$jscoverage['middleware/logger.js'][136]++;
req._startTime = new Date();
_$jscoverage['middleware/logger.js'][139]++;
if (immediate) {
_$jscoverage['middleware/logger.js'][140]++;
var line = fmt(exports, req, res);
_$jscoverage['middleware/logger.js'][141]++;
if (null == line) {
_$jscoverage['middleware/logger.js'][141]++;
return;
}
_$jscoverage['middleware/logger.js'][142]++;
stream.write(line + "\n");
}
else {
_$jscoverage['middleware/logger.js'][145]++;
var end = res.end;
_$jscoverage['middleware/logger.js'][146]++;
res.end = (function (chunk, encoding) {
_$jscoverage['middleware/logger.js'][147]++;
res.end = end;
_$jscoverage['middleware/logger.js'][148]++;
res.end(chunk, encoding);
_$jscoverage['middleware/logger.js'][149]++;
var line = fmt(exports, req, res);
_$jscoverage['middleware/logger.js'][150]++;
if (null == line) {
_$jscoverage['middleware/logger.js'][150]++;
return;
}
_$jscoverage['middleware/logger.js'][151]++;
stream.write(line + "\n");
});
}
_$jscoverage['middleware/logger.js'][156]++;
next();
});
});
_$jscoverage['middleware/logger.js'][168]++;
function compile(fmt) {
_$jscoverage['middleware/logger.js'][169]++;
fmt = fmt.replace(/"/g, "\\\"");
_$jscoverage['middleware/logger.js'][170]++;
var js = " return \"" + fmt.replace(/:([-\w]{2,})(?:\[([^\]]+)\])?/g, (function (_, name, arg) {
_$jscoverage['middleware/logger.js'][171]++;
return "\"\n + (tokens[\"" + name + "\"](req, res, \"" + arg + "\") || \"-\") + \"";
})) + "\";";
_$jscoverage['middleware/logger.js'][173]++;
return new Function("tokens, req, res", js);
}
_$jscoverage['middleware/logger.js'][174]++;
;
_$jscoverage['middleware/logger.js'][186]++;
exports.token = (function (name, fn) {
_$jscoverage['middleware/logger.js'][187]++;
exports[name] = fn;
_$jscoverage['middleware/logger.js'][188]++;
return this;
});
_$jscoverage['middleware/logger.js'][200]++;
exports.format = (function (name, str) {
_$jscoverage['middleware/logger.js'][201]++;
exports[name] = str;
_$jscoverage['middleware/logger.js'][202]++;
return this;
});
_$jscoverage['middleware/logger.js'][209]++;
exports.format("default", ":remote-addr - - [:date] \":method :url HTTP/:http-version\" :status :res[content-length] \":referrer\" \":user-agent\"");
_$jscoverage['middleware/logger.js'][215]++;
exports.format("short", ":remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms");
_$jscoverage['middleware/logger.js'][221]++;
exports.format("tiny", ":method :url :status :res[content-length] - :response-time ms");
_$jscoverage['middleware/logger.js'][227]++;
exports.format("dev", (function (tokens, req, res) {
_$jscoverage['middleware/logger.js'][228]++;
var status = res.statusCode, len = parseInt(res.getHeader("Content-Length"), 10), color = 32;
_$jscoverage['middleware/logger.js'][232]++;
if (status >= 500) {
_$jscoverage['middleware/logger.js'][232]++;
color = 31;
}
else {
_$jscoverage['middleware/logger.js'][233]++;
if (status >= 400) {
_$jscoverage['middleware/logger.js'][233]++;
color = 33;
}
else {
_$jscoverage['middleware/logger.js'][234]++;
if (status >= 300) {
_$jscoverage['middleware/logger.js'][234]++;
color = 36;
}
}
}
_$jscoverage['middleware/logger.js'][236]++;
len = isNaN(len)? "": len = " - " + bytes(len);
_$jscoverage['middleware/logger.js'][240]++;
return "\u001b[90m" + req.method + " " + req.originalUrl + " " + "\u001b[" + color + "m" + res.statusCode + " \u001b[90m" + (new Date() - req._startTime) + "ms" + len + "\u001b[0m";
}));
_$jscoverage['middleware/logger.js'][253]++;
exports.token("url", (function (req) {
_$jscoverage['middleware/logger.js'][254]++;
return req.originalUrl || req.url;
}));
_$jscoverage['middleware/logger.js'][261]++;
exports.token("method", (function (req) {
_$jscoverage['middleware/logger.js'][262]++;
return req.method;
}));
_$jscoverage['middleware/logger.js'][269]++;
exports.token("response-time", (function (req) {
_$jscoverage['middleware/logger.js'][270]++;
return new Date() - req._startTime;
}));
_$jscoverage['middleware/logger.js'][277]++;
exports.token("date", (function () {
_$jscoverage['middleware/logger.js'][278]++;
return new Date().toUTCString();
}));
_$jscoverage['middleware/logger.js'][285]++;
exports.token("status", (function (req, res) {
_$jscoverage['middleware/logger.js'][286]++;
return res.statusCode;
}));
_$jscoverage['middleware/logger.js'][293]++;
exports.token("referrer", (function (req) {
_$jscoverage['middleware/logger.js'][294]++;
return req.headers.referer || req.headers.referrer;
}));
_$jscoverage['middleware/logger.js'][301]++;
exports.token("remote-addr", (function (req) {
_$jscoverage['middleware/logger.js'][302]++;
if (req.ip) {
_$jscoverage['middleware/logger.js'][302]++;
return req.ip;
}
_$jscoverage['middleware/logger.js'][303]++;
var sock = req.socket;
_$jscoverage['middleware/logger.js'][304]++;
if (sock.socket) {
_$jscoverage['middleware/logger.js'][304]++;
return sock.socket.remoteAddress;
}
_$jscoverage['middleware/logger.js'][305]++;
return sock.remoteAddress;
}));
_$jscoverage['middleware/logger.js'][312]++;
exports.token("http-version", (function (req) {
_$jscoverage['middleware/logger.js'][313]++;
return req.httpVersionMajor + "." + req.httpVersionMinor;
}));
_$jscoverage['middleware/logger.js'][320]++;
exports.token("user-agent", (function (req) {
_$jscoverage['middleware/logger.js'][321]++;
return req.headers["user-agent"];
}));
_$jscoverage['middleware/logger.js'][328]++;
exports.token("req", (function (req, res, field) {
_$jscoverage['middleware/logger.js'][329]++;
return req.headers[field.toLowerCase()];
}));
_$jscoverage['middleware/logger.js'][336]++;
exports.token("res", (function (req, res, field) {
_$jscoverage['middleware/logger.js'][337]++;
return (res._headers || {})[field.toLowerCase()];
}));
_$jscoverage['middleware/logger.js'].source = ["/*!"," * Connect - logger"," * Copyright(c) 2010 Sencha Inc."," * Copyright(c) 2011 TJ Holowaychuk"," * MIT Licensed"," */","","/**"," * Module dependencies."," */","","var bytes = require('bytes');","","/*!"," * Log buffer."," */","","var buf = [];","","/*!"," * Default log buffer duration."," */","","var defaultBufferDuration = 1000;","","/**"," * Logger:"," *"," * Log requests with the given `options` or a `format` string."," *"," * Options:"," *"," * - `format` Format string, see below for tokens"," * - `stream` Output stream, defaults to _stdout_"," * - `buffer` Buffer duration, defaults to 1000ms when _true_"," * - `immediate` Write log line on request instead of response (for response times)"," *"," * Tokens:"," *"," * - `:req[header]` ex: `:req[Accept]`"," * - `:res[header]` ex: `:res[Content-Length]`"," * - `:http-version`"," * - `:response-time`"," * - `:remote-addr`"," * - `:date`"," * - `:method`"," * - `:url`"," * - `:referrer`"," * - `:user-agent`"," * - `:status`"," *"," * Formats:"," *"," * Pre-defined formats that ship with connect:"," *"," * - `default` ':remote-addr - - [:date] \":method :url HTTP/:http-version\" :status :res[content-length] \":referrer\" \":user-agent\"'"," * - `short` ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms'"," * - `tiny` ':method :url :status :res[content-length] - :response-time ms'"," * - `dev` concise output colored by response status for development use"," *"," * Examples:"," *"," * connect.logger() // default"," * connect.logger('short')"," * connect.logger('tiny')"," * connect.logger({ immediate: true, format: 'dev' })"," * connect.logger(':method :url - :referrer')"," * connect.logger(':req[content-type] -&gt; :res[content-type]')"," * connect.logger(function(tokens, req, res){ return 'some format string' })"," *"," * Defining Tokens:"," *"," * To define a token, simply invoke `connect.logger.token()` with the"," * name and a callback function. The value returned is then available"," * as \":type\" in this case."," *"," * connect.logger.token('type', function(req, res){ return req.headers['content-type']; })"," *"," * Defining Formats:"," *"," * All default formats are defined this way, however it's public API as well:"," *"," * connect.logger.format('name', 'string or function')"," *"," * @param {String|Function|Object} format or options"," * @return {Function}"," * @api public"," */","","exports = module.exports = function logger(options) {"," if ('object' == typeof options) {"," options = options || {};"," } else if (options) {"," options = { format: options };"," } else {"," options = {};"," }",""," // output on request instead of response"," var immediate = options.immediate;",""," // format name"," var fmt = exports[options.format] || options.format || exports.default;",""," // compile format"," if ('function' != typeof fmt) fmt = compile(fmt);",""," // options"," var stream = options.stream || process.stdout"," , buffer = options.buffer;",""," // buffering support"," if (buffer) {"," var realStream = stream"," , interval = 'number' == typeof buffer"," ? buffer"," : defaultBufferDuration;",""," // flush interval"," setInterval(function(){"," if (buf.length) {"," realStream.write(buf.join(''));"," buf.length = 0;"," }"," }, interval); ",""," // swap the stream"," stream = {"," write: function(str){"," buf.push(str);"," }"," };"," }",""," return function logger(req, res, next) {"," req._startTime = new Date;",""," // immediate"," if (immediate) {"," var line = fmt(exports, req, res);"," if (null == line) return;"," stream.write(line + '\\n');"," // proxy end to output logging"," } else {"," var end = res.end;"," res.end = function(chunk, encoding){"," res.end = end;"," res.end(chunk, encoding);"," var line = fmt(exports, req, res);"," if (null == line) return;"," stream.write(line + '\\n');"," };"," }","",""," next();"," };","};","","/**"," * Compile `fmt` into a function."," *"," * @param {String} fmt"," * @return {Function}"," * @api private"," */","","function compile(fmt) {"," fmt = fmt.replace(/\"/g, '\\\\\"');"," var js = ' return \"' + fmt.replace(/:([-\\w]{2,})(?:\\[([^\\]]+)\\])?/g, function(_, name, arg){"," return '\"\\n + (tokens[\"' + name + '\"](req, res, \"' + arg + '\") || \"-\") + \"';"," }) + '\";'"," return new Function('tokens, req, res', js);","};","","/**"," * Define a token function with the given `name`,"," * and callback `fn(req, res)`."," *"," * @param {String} name"," * @param {Function} fn"," * @return {Object} exports for chaining"," * @api public"," */","","exports.token = function(name, fn) {"," exports[name] = fn;"," return this;","};","","/**"," * Define a `fmt` with the given `name`."," *"," * @param {String} name"," * @param {String|Function} fmt"," * @return {Object} exports for chaining"," * @api public"," */","","exports.format = function(name, str){"," exports[name] = str;"," return this;","};","","/**"," * Default format."," */","","exports.format('default', ':remote-addr - - [:date] \":method :url HTTP/:http-version\" :status :res[content-length] \":referrer\" \":user-agent\"');","","/**"," * Short format."," */","","exports.format('short', ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms');","","/**"," * Tiny format."," */","","exports.format('tiny', ':method :url :status :res[content-length] - :response-time ms');","","/**"," * dev (colored)"," */","","exports.format('dev', function(tokens, req, res){"," var status = res.statusCode"," , len = parseInt(res.getHeader('Content-Length'), 10)"," , color = 32;",""," if (status &gt;= 500) color = 31"," else if (status &gt;= 400) color = 33"," else if (status &gt;= 300) color = 36;",""," len = isNaN(len)"," ? ''"," : len = ' - ' + bytes(len);",""," return '\\033[90m' + req.method"," + ' ' + req.originalUrl + ' '"," + '\\033[' + color + 'm' + res.statusCode"," + ' \\033[90m'"," + (new Date - req._startTime)"," + 'ms' + len"," + '\\033[0m';","});","","/**"," * request url"," */","","exports.token('url', function(req){"," return req.originalUrl || req.url;","});","","/**"," * request method"," */","","exports.token('method', function(req){"," return req.method;","});","","/**"," * response time in milliseconds"," */","","exports.token('response-time', function(req){"," return new Date - req._startTime;","});","","/**"," * UTC date"," */","","exports.token('date', function(){"," return new Date().toUTCString();","});","","/**"," * response status code"," */","","exports.token('status', function(req, res){"," return res.statusCode;","});","","/**"," * normalized referrer"," */","","exports.token('referrer', function(req){"," return req.headers['referer'] || req.headers['referrer'];","});","","/**"," * remote address"," */","","exports.token('remote-addr', function(req){"," if (req.ip) return req.ip;"," var sock = req.socket;"," if (sock.socket) return sock.socket.remoteAddress;"," return sock.remoteAddress;","});","","/**"," * HTTP version"," */","","exports.token('http-version', function(req){"," return req.httpVersionMajor + '.' + req.httpVersionMinor;","});","","/**"," * UA string"," */","","exports.token('user-agent', function(req){"," return req.headers['user-agent'];","});","","/**"," * request header"," */","","exports.token('req', function(req, res, field){"," return req.headers[field.toLowerCase()];","});","","/**"," * response header"," */","","exports.token('res', function(req, res, field){"," return (res._headers || {})[field.toLowerCase()];","});",""];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['middleware/methodOverride.js']) {
_$jscoverage['middleware/methodOverride.js'] = [];
_$jscoverage['middleware/methodOverride.js'][23] = 0;
_$jscoverage['middleware/methodOverride.js'][24] = 0;
_$jscoverage['middleware/methodOverride.js'][25] = 0;
_$jscoverage['middleware/methodOverride.js'][26] = 0;
_$jscoverage['middleware/methodOverride.js'][29] = 0;
_$jscoverage['middleware/methodOverride.js'][30] = 0;
_$jscoverage['middleware/methodOverride.js'][31] = 0;
_$jscoverage['middleware/methodOverride.js'][33] = 0;
_$jscoverage['middleware/methodOverride.js'][34] = 0;
_$jscoverage['middleware/methodOverride.js'][37] = 0;
}
_$jscoverage['middleware/methodOverride.js'][23]++;
module.exports = (function methodOverride(key) {
_$jscoverage['middleware/methodOverride.js'][24]++;
key = key || "_method";
_$jscoverage['middleware/methodOverride.js'][25]++;
return (function methodOverride(req, res, next) {
_$jscoverage['middleware/methodOverride.js'][26]++;
req.originalMethod = req.originalMethod || req.method;
_$jscoverage['middleware/methodOverride.js'][29]++;
if (req.body && key in req.body) {
_$jscoverage['middleware/methodOverride.js'][30]++;
req.method = req.body[key].toUpperCase();
_$jscoverage['middleware/methodOverride.js'][31]++;
delete req.body[key];
}
else {
_$jscoverage['middleware/methodOverride.js'][33]++;
if (req.headers["x-http-method-override"]) {
_$jscoverage['middleware/methodOverride.js'][34]++;
req.method = req.headers["x-http-method-override"].toUpperCase();
}
}
_$jscoverage['middleware/methodOverride.js'][37]++;
next();
});
});
_$jscoverage['middleware/methodOverride.js'].source = ["","/*!"," * Connect - methodOverride"," * Copyright(c) 2010 Sencha Inc."," * Copyright(c) 2011 TJ Holowaychuk"," * MIT Licensed"," */","","/**"," * Method Override:"," * "," * Provides faux HTTP method support."," * "," * Pass an optional `key` to use when checking for"," * a method override, othewise defaults to _\\_method_."," * The original method is available via `req.originalMethod`."," *"," * @param {String} key"," * @return {Function}"," * @api public"," */","","module.exports = function methodOverride(key){"," key = key || \"_method\";"," return function methodOverride(req, res, next) {"," req.originalMethod = req.originalMethod || req.method;",""," // req.body"," if (req.body &amp;&amp; key in req.body) {"," req.method = req.body[key].toUpperCase();"," delete req.body[key];"," // check X-HTTP-Method-Override"," } else if (req.headers['x-http-method-override']) {"," req.method = req.headers['x-http-method-override'].toUpperCase();"," }"," "," next();"," };","};",""];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['middleware/multipart.js']) {
_$jscoverage['middleware/multipart.js'] = [];
_$jscoverage['middleware/multipart.js'][12] = 0;
_$jscoverage['middleware/multipart.js'][21] = 0;
_$jscoverage['middleware/multipart.js'][22] = 0;
_$jscoverage['middleware/multipart.js'][52] = 0;
_$jscoverage['middleware/multipart.js'][53] = 0;
_$jscoverage['middleware/multipart.js'][55] = 0;
_$jscoverage['middleware/multipart.js'][59] = 0;
_$jscoverage['middleware/multipart.js'][60] = 0;
_$jscoverage['middleware/multipart.js'][61] = 0;
_$jscoverage['middleware/multipart.js'][62] = 0;
_$jscoverage['middleware/multipart.js'][64] = 0;
_$jscoverage['middleware/multipart.js'][67] = 0;
_$jscoverage['middleware/multipart.js'][70] = 0;
_$jscoverage['middleware/multipart.js'][73] = 0;
_$jscoverage['middleware/multipart.js'][76] = 0;
_$jscoverage['middleware/multipart.js'][77] = 0;
_$jscoverage['middleware/multipart.js'][79] = 0;
_$jscoverage['middleware/multipart.js'][84] = 0;
_$jscoverage['middleware/multipart.js'][85] = 0;
_$jscoverage['middleware/multipart.js'][88] = 0;
_$jscoverage['middleware/multipart.js'][89] = 0;
_$jscoverage['middleware/multipart.js'][90] = 0;
_$jscoverage['middleware/multipart.js'][91] = 0;
_$jscoverage['middleware/multipart.js'][92] = 0;
_$jscoverage['middleware/multipart.js'][94] = 0;
_$jscoverage['middleware/multipart.js'][98] = 0;
_$jscoverage['middleware/multipart.js'][99] = 0;
_$jscoverage['middleware/multipart.js'][102] = 0;
_$jscoverage['middleware/multipart.js'][103] = 0;
_$jscoverage['middleware/multipart.js'][106] = 0;
_$jscoverage['middleware/multipart.js'][107] = 0;
_$jscoverage['middleware/multipart.js'][108] = 0;
_$jscoverage['middleware/multipart.js'][109] = 0;
_$jscoverage['middleware/multipart.js'][111] = 0;
_$jscoverage['middleware/multipart.js'][114] = 0;
_$jscoverage['middleware/multipart.js'][115] = 0;
_$jscoverage['middleware/multipart.js'][116] = 0;
_$jscoverage['middleware/multipart.js'][117] = 0;
_$jscoverage['middleware/multipart.js'][118] = 0;
_$jscoverage['middleware/multipart.js'][119] = 0;
_$jscoverage['middleware/multipart.js'][121] = 0;
_$jscoverage['middleware/multipart.js'][125] = 0;
_$jscoverage['middleware/multipart.js'][127] = 0;
_$jscoverage['middleware/multipart.js'][128] = 0;
_$jscoverage['middleware/multipart.js'][129] = 0;
}
_$jscoverage['middleware/multipart.js'][12]++;
var formidable = require("formidable"), _limit = require("./limit"), utils = require("../utils"), qs = require("qs");
_$jscoverage['middleware/multipart.js'][21]++;
function noop(req, res, next) {
_$jscoverage['middleware/multipart.js'][22]++;
next();
}
_$jscoverage['middleware/multipart.js'][52]++;
exports = module.exports = (function (options) {
_$jscoverage['middleware/multipart.js'][53]++;
options = options || {};
_$jscoverage['middleware/multipart.js'][55]++;
var limit = options.limit? _limit(options.limit): noop;
_$jscoverage['middleware/multipart.js'][59]++;
return (function multipart(req, res, next) {
_$jscoverage['middleware/multipart.js'][60]++;
if (req._body) {
_$jscoverage['middleware/multipart.js'][60]++;
return next();
}
_$jscoverage['middleware/multipart.js'][61]++;
req.body = req.body || {};
_$jscoverage['middleware/multipart.js'][62]++;
req.files = req.files || {};
_$jscoverage['middleware/multipart.js'][64]++;
if (! utils.hasBody(req)) {
_$jscoverage['middleware/multipart.js'][64]++;
return next();
}
_$jscoverage['middleware/multipart.js'][67]++;
if ("GET" == req.method || "HEAD" == req.method) {
_$jscoverage['middleware/multipart.js'][67]++;
return next();
}
_$jscoverage['middleware/multipart.js'][70]++;
if ("multipart/form-data" != utils.mime(req)) {
_$jscoverage['middleware/multipart.js'][70]++;
return next();
}
_$jscoverage['middleware/multipart.js'][73]++;
req._body = true;
_$jscoverage['middleware/multipart.js'][76]++;
limit(req, res, (function (err) {
_$jscoverage['middleware/multipart.js'][77]++;
if (err) {
_$jscoverage['middleware/multipart.js'][77]++;
return next(err);
}
_$jscoverage['middleware/multipart.js'][79]++;
var form = new formidable.IncomingForm(), data = {}, files = {}, done;
_$jscoverage['middleware/multipart.js'][84]++;
Object.keys(options).forEach((function (key) {
_$jscoverage['middleware/multipart.js'][85]++;
form[key] = options[key];
}));
_$jscoverage['middleware/multipart.js'][88]++;
function ondata(name, val, data) {
_$jscoverage['middleware/multipart.js'][89]++;
if (Array.isArray(data[name])) {
_$jscoverage['middleware/multipart.js'][90]++;
data[name].push(val);
}
else {
_$jscoverage['middleware/multipart.js'][91]++;
if (data[name]) {
_$jscoverage['middleware/multipart.js'][92]++;
data[name] = [data[name], val];
}
else {
_$jscoverage['middleware/multipart.js'][94]++;
data[name] = val;
}
}
}
_$jscoverage['middleware/multipart.js'][98]++;
form.on("field", (function (name, val) {
_$jscoverage['middleware/multipart.js'][99]++;
ondata(name, val, data);
}));
_$jscoverage['middleware/multipart.js'][102]++;
form.on("file", (function (name, val) {
_$jscoverage['middleware/multipart.js'][103]++;
ondata(name, val, files);
}));
_$jscoverage['middleware/multipart.js'][106]++;
form.on("error", (function (err) {
_$jscoverage['middleware/multipart.js'][107]++;
if (! options.defer) {
_$jscoverage['middleware/multipart.js'][108]++;
err.status = 400;
_$jscoverage['middleware/multipart.js'][109]++;
next(err);
}
_$jscoverage['middleware/multipart.js'][111]++;
done = true;
}));
_$jscoverage['middleware/multipart.js'][114]++;
form.on("end", (function () {
_$jscoverage['middleware/multipart.js'][115]++;
if (done) {
_$jscoverage['middleware/multipart.js'][115]++;
return;
}
_$jscoverage['middleware/multipart.js'][116]++;
try {
_$jscoverage['middleware/multipart.js'][117]++;
req.body = qs.parse(data);
_$jscoverage['middleware/multipart.js'][118]++;
req.files = qs.parse(files);
_$jscoverage['middleware/multipart.js'][119]++;
if (! options.defer) {
_$jscoverage['middleware/multipart.js'][119]++;
next();
}
}
catch (err) {
_$jscoverage['middleware/multipart.js'][121]++;
form.emit("error", err);
}
}));
_$jscoverage['middleware/multipart.js'][125]++;
form.parse(req);
_$jscoverage['middleware/multipart.js'][127]++;
if (options.defer) {
_$jscoverage['middleware/multipart.js'][128]++;
req.form = form;
_$jscoverage['middleware/multipart.js'][129]++;
next();
}
}));
});
});
_$jscoverage['middleware/multipart.js'].source = ["/*!"," * Connect - multipart"," * Copyright(c) 2010 Sencha Inc."," * Copyright(c) 2011 TJ Holowaychuk"," * MIT Licensed"," */","","/**"," * Module dependencies."," */","","var formidable = require('formidable')"," , _limit = require('./limit')"," , utils = require('../utils')"," , qs = require('qs');","","/**"," * noop middleware."," */","","function noop(req, res, next) {"," next();","}","","/**"," * Multipart:"," * "," * Parse multipart/form-data request bodies,"," * providing the parsed object as `req.body`"," * and `req.files`."," *"," * Configuration:"," *"," * The options passed are merged with [formidable](https://github.com/felixge/node-formidable)'s"," * `IncomingForm` object, allowing you to configure the upload directory,"," * size limits, etc. For example if you wish to change the upload dir do the following."," *"," * app.use(connect.multipart({ uploadDir: path }));"," *"," * Options:"," *"," * - `limit` byte limit defaulting to none"," * - `defer` defers processing and exposes the Formidable form object as `req.form`."," * `next()` is called without waiting for the form's \"end\" event."," * This option is useful if you need to bind to the \"progress\" event, for example."," *"," * @param {Object} options"," * @return {Function}"," * @api public"," */","","exports = module.exports = function(options){"," options = options || {};",""," var limit = options.limit"," ? _limit(options.limit)"," : noop;",""," return function multipart(req, res, next) {"," if (req._body) return next();"," req.body = req.body || {};"," req.files = req.files || {};",""," if (!utils.hasBody(req)) return next();",""," // ignore GET"," if ('GET' == req.method || 'HEAD' == req.method) return next();",""," // check Content-Type"," if ('multipart/form-data' != utils.mime(req)) return next();",""," // flag as parsed"," req._body = true;",""," // parse"," limit(req, res, function(err){"," if (err) return next(err);",""," var form = new formidable.IncomingForm"," , data = {}"," , files = {}"," , done;",""," Object.keys(options).forEach(function(key){"," form[key] = options[key];"," });",""," function ondata(name, val, data){"," if (Array.isArray(data[name])) {"," data[name].push(val);"," } else if (data[name]) {"," data[name] = [data[name], val];"," } else {"," data[name] = val;"," }"," }",""," form.on('field', function(name, val){"," ondata(name, val, data);"," });",""," form.on('file', function(name, val){"," ondata(name, val, files);"," });",""," form.on('error', function(err){"," if (!options.defer) {"," err.status = 400;"," next(err);"," }"," done = true;"," });",""," form.on('end', function(){"," if (done) return;"," try {"," req.body = qs.parse(data);"," req.files = qs.parse(files);"," if (!options.defer) next();"," } catch (err) {"," form.emit('error', err);"," }"," });",""," form.parse(req);",""," if (options.defer) {"," req.form = form;"," next();"," }"," });"," }","};"];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['middleware/query.js']) {
_$jscoverage['middleware/query.js'] = [];
_$jscoverage['middleware/query.js'][12] = 0;
_$jscoverage['middleware/query.js'][36] = 0;
_$jscoverage['middleware/query.js'][37] = 0;
_$jscoverage['middleware/query.js'][38] = 0;
_$jscoverage['middleware/query.js'][39] = 0;
_$jscoverage['middleware/query.js'][44] = 0;
}
_$jscoverage['middleware/query.js'][12]++;
var qs = require("qs"), parse = require("../utils").parseUrl;
_$jscoverage['middleware/query.js'][36]++;
module.exports = (function query(options) {
_$jscoverage['middleware/query.js'][37]++;
return (function query(req, res, next) {
_$jscoverage['middleware/query.js'][38]++;
if (! req.query) {
_$jscoverage['middleware/query.js'][39]++;
req.query = ~ req.url.indexOf("?")? qs.parse(parse(req).query, options): {};
}
_$jscoverage['middleware/query.js'][44]++;
next();
});
});
_$jscoverage['middleware/query.js'].source = ["/*!"," * Connect - query"," * Copyright(c) 2011 TJ Holowaychuk"," * Copyright(c) 2011 Sencha Inc."," * MIT Licensed"," */","","/**"," * Module dependencies."," */","","var qs = require('qs')"," , parse = require('../utils').parseUrl;","","/**"," * Query:"," *"," * Automatically parse the query-string when available,"," * populating the `req.query` object."," *"," * Examples:"," *"," * connect()"," * .use(connect.query())"," * .use(function(req, res){"," * res.end(JSON.stringify(req.query));"," * });"," *"," * The `options` passed are provided to qs.parse function."," *"," * @param {Object} options"," * @return {Function}"," * @api public"," */","","module.exports = function query(options){"," return function query(req, res, next){"," if (!req.query) {"," req.query = ~req.url.indexOf('?')"," ? qs.parse(parse(req).query, options)"," : {};"," }",""," next();"," };","};"];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['middleware/responseTime.js']) {
_$jscoverage['middleware/responseTime.js'] = [];
_$jscoverage['middleware/responseTime.js'][18] = 0;
_$jscoverage['middleware/responseTime.js'][19] = 0;
_$jscoverage['middleware/responseTime.js'][20] = 0;
_$jscoverage['middleware/responseTime.js'][22] = 0;
_$jscoverage['middleware/responseTime.js'][23] = 0;
_$jscoverage['middleware/responseTime.js'][25] = 0;
_$jscoverage['middleware/responseTime.js'][26] = 0;
_$jscoverage['middleware/responseTime.js'][27] = 0;
_$jscoverage['middleware/responseTime.js'][30] = 0;
}
_$jscoverage['middleware/responseTime.js'][18]++;
module.exports = (function responseTime() {
_$jscoverage['middleware/responseTime.js'][19]++;
return (function (req, res, next) {
_$jscoverage['middleware/responseTime.js'][20]++;
var start = new Date();
_$jscoverage['middleware/responseTime.js'][22]++;
if (res._responseTime) {
_$jscoverage['middleware/responseTime.js'][22]++;
return next();
}
_$jscoverage['middleware/responseTime.js'][23]++;
res._responseTime = true;
_$jscoverage['middleware/responseTime.js'][25]++;
res.on("header", (function () {
_$jscoverage['middleware/responseTime.js'][26]++;
var duration = new Date() - start;
_$jscoverage['middleware/responseTime.js'][27]++;
res.setHeader("X-Response-Time", duration + "ms");
}));
_$jscoverage['middleware/responseTime.js'][30]++;
next();
});
});
_$jscoverage['middleware/responseTime.js'].source = ["","/*!"," * Connect - responseTime"," * Copyright(c) 2011 TJ Holowaychuk"," * MIT Licensed"," */","","/**"," * Reponse time:"," *"," * Adds the `X-Response-Time` header displaying the response"," * duration in milliseconds."," *"," * @return {Function}"," * @api public"," */","","module.exports = function responseTime(){"," return function(req, res, next){"," var start = new Date;",""," if (res._responseTime) return next();"," res._responseTime = true;",""," res.on('header', function(){"," var duration = new Date - start;"," res.setHeader('X-Response-Time', duration + 'ms');"," });",""," next();"," };","};"];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['middleware/session.js']) {
_$jscoverage['middleware/session.js'] = [];
_$jscoverage['middleware/session.js'][13] = 0;
_$jscoverage['middleware/session.js'][25] = 0;
_$jscoverage['middleware/session.js'][31] = 0;
_$jscoverage['middleware/session.js'][37] = 0;
_$jscoverage['middleware/session.js'][38] = 0;
_$jscoverage['middleware/session.js'][39] = 0;
_$jscoverage['middleware/session.js'][40] = 0;
_$jscoverage['middleware/session.js'][46] = 0;
_$jscoverage['middleware/session.js'][188] = 0;
_$jscoverage['middleware/session.js'][189] = 0;
_$jscoverage['middleware/session.js'][198] = 0;
_$jscoverage['middleware/session.js'][199] = 0;
_$jscoverage['middleware/session.js'][203] = 0;
_$jscoverage['middleware/session.js'][204] = 0;
_$jscoverage['middleware/session.js'][205] = 0;
_$jscoverage['middleware/session.js'][206] = 0;
_$jscoverage['middleware/session.js'][209] = 0;
_$jscoverage['middleware/session.js'][210] = 0;
_$jscoverage['middleware/session.js'][212] = 0;
_$jscoverage['middleware/session.js'][214] = 0;
_$jscoverage['middleware/session.js'][218] = 0;
_$jscoverage['middleware/session.js'][221] = 0;
_$jscoverage['middleware/session.js'][225] = 0;
_$jscoverage['middleware/session.js'][228] = 0;
_$jscoverage['middleware/session.js'][231] = 0;
_$jscoverage['middleware/session.js'][235] = 0;
_$jscoverage['middleware/session.js'][238] = 0;
_$jscoverage['middleware/session.js'][241] = 0;
_$jscoverage['middleware/session.js'][243] = 0;
_$jscoverage['middleware/session.js'][244] = 0;
_$jscoverage['middleware/session.js'][248] = 0;
_$jscoverage['middleware/session.js'][249] = 0;
_$jscoverage['middleware/session.js'][250] = 0;
_$jscoverage['middleware/session.js'][257] = 0;
_$jscoverage['middleware/session.js'][260] = 0;
_$jscoverage['middleware/session.js'][261] = 0;
_$jscoverage['middleware/session.js'][263] = 0;
_$jscoverage['middleware/session.js'][264] = 0;
_$jscoverage['middleware/session.js'][267] = 0;
_$jscoverage['middleware/session.js'][268] = 0;
_$jscoverage['middleware/session.js'][269] = 0;
_$jscoverage['middleware/session.js'][270] = 0;
_$jscoverage['middleware/session.js'][274] = 0;
_$jscoverage['middleware/session.js'][275] = 0;
_$jscoverage['middleware/session.js'][276] = 0;
_$jscoverage['middleware/session.js'][277] = 0;
_$jscoverage['middleware/session.js'][278] = 0;
_$jscoverage['middleware/session.js'][279] = 0;
_$jscoverage['middleware/session.js'][280] = 0;
_$jscoverage['middleware/session.js'][281] = 0;
_$jscoverage['middleware/session.js'][282] = 0;
_$jscoverage['middleware/session.js'][287] = 0;
_$jscoverage['middleware/session.js'][288] = 0;
_$jscoverage['middleware/session.js'][292] = 0;
_$jscoverage['middleware/session.js'][295] = 0;
_$jscoverage['middleware/session.js'][296] = 0;
_$jscoverage['middleware/session.js'][297] = 0;
_$jscoverage['middleware/session.js'][298] = 0;
_$jscoverage['middleware/session.js'][299] = 0;
_$jscoverage['middleware/session.js'][303] = 0;
_$jscoverage['middleware/session.js'][304] = 0;
_$jscoverage['middleware/session.js'][305] = 0;
_$jscoverage['middleware/session.js'][307] = 0;
_$jscoverage['middleware/session.js'][308] = 0;
_$jscoverage['middleware/session.js'][309] = 0;
_$jscoverage['middleware/session.js'][310] = 0;
_$jscoverage['middleware/session.js'][314] = 0;
_$jscoverage['middleware/session.js'][315] = 0;
_$jscoverage['middleware/session.js'][316] = 0;
_$jscoverage['middleware/session.js'][317] = 0;
_$jscoverage['middleware/session.js'][318] = 0;
_$jscoverage['middleware/session.js'][320] = 0;
_$jscoverage['middleware/session.js'][323] = 0;
_$jscoverage['middleware/session.js'][324] = 0;
_$jscoverage['middleware/session.js'][325] = 0;
_$jscoverage['middleware/session.js'][326] = 0;
_$jscoverage['middleware/session.js'][329] = 0;
_$jscoverage['middleware/session.js'][330] = 0;
_$jscoverage['middleware/session.js'][331] = 0;
_$jscoverage['middleware/session.js'][332] = 0;
_$jscoverage['middleware/session.js'][333] = 0;
_$jscoverage['middleware/session.js'][337] = 0;
_$jscoverage['middleware/session.js'][348] = 0;
_$jscoverage['middleware/session.js'][349] = 0;
_$jscoverage['middleware/session.js'][350] = 0;
}
_$jscoverage['middleware/session.js'][13]++;
var Session = require("./session/session"), debug = require("debug")("connect:session"), MemoryStore = require("./session/memory"), signature = require("cookie-signature"), Cookie = require("./session/cookie"), Store = require("./session/store"), utils = require("./../utils"), parse = utils.parseUrl, crc16 = require("crc").crc16;
_$jscoverage['middleware/session.js'][25]++;
var env = process.env.NODE_ENV;
_$jscoverage['middleware/session.js'][31]++;
exports = module.exports = session;
_$jscoverage['middleware/session.js'][37]++;
exports.Store = Store;
_$jscoverage['middleware/session.js'][38]++;
exports.Cookie = Cookie;
_$jscoverage['middleware/session.js'][39]++;
exports.Session = Session;
_$jscoverage['middleware/session.js'][40]++;
exports.MemoryStore = MemoryStore;
_$jscoverage['middleware/session.js'][46]++;
var warning = "Warning: connection.session() MemoryStore is not\ndesigned for a production environment, as it will leak\nmemory, and will not scale past a single process.";
_$jscoverage['middleware/session.js'][188]++;
function session(options) {
_$jscoverage['middleware/session.js'][189]++;
var options = options || {}, key = options.key || "connect.sid", store = options.store || new MemoryStore(), cookie = options.cookie || {}, trustProxy = options.proxy, storeReady = true;
_$jscoverage['middleware/session.js'][198]++;
if ("production" == env && store instanceof MemoryStore) {
_$jscoverage['middleware/session.js'][199]++;
console.warn(warning);
}
_$jscoverage['middleware/session.js'][203]++;
store.generate = (function (req) {
_$jscoverage['middleware/session.js'][204]++;
req.sessionID = utils.uid(24);
_$jscoverage['middleware/session.js'][205]++;
req.session = new Session(req);
_$jscoverage['middleware/session.js'][206]++;
req.session.cookie = new Cookie(cookie);
});
_$jscoverage['middleware/session.js'][209]++;
store.on("disconnect", (function () {
_$jscoverage['middleware/session.js'][209]++;
storeReady = false;
}));
_$jscoverage['middleware/session.js'][210]++;
store.on("connect", (function () {
_$jscoverage['middleware/session.js'][210]++;
storeReady = true;
}));
_$jscoverage['middleware/session.js'][212]++;
return (function session(req, res, next) {
_$jscoverage['middleware/session.js'][214]++;
if (req.session) {
_$jscoverage['middleware/session.js'][214]++;
return next();
}
_$jscoverage['middleware/session.js'][218]++;
if (! storeReady) {
_$jscoverage['middleware/session.js'][218]++;
return debug("store is disconnected"), next();
}
_$jscoverage['middleware/session.js'][221]++;
if (0 != req.originalUrl.indexOf(cookie.path || "/")) {
_$jscoverage['middleware/session.js'][221]++;
return next();
}
_$jscoverage['middleware/session.js'][225]++;
var secret = options.secret || req.secret;
_$jscoverage['middleware/session.js'][228]++;
if (! secret) {
_$jscoverage['middleware/session.js'][228]++;
throw new Error("`secret` option required for sessions");
}
_$jscoverage['middleware/session.js'][231]++;
var originalHash, originalId;
_$jscoverage['middleware/session.js'][235]++;
req.sessionStore = store;
_$jscoverage['middleware/session.js'][238]++;
var rawCookie = req.cookies[key];
_$jscoverage['middleware/session.js'][241]++;
var unsignedCookie = req.signedCookies[key];
_$jscoverage['middleware/session.js'][243]++;
if (! unsignedCookie && rawCookie) {
_$jscoverage['middleware/session.js'][244]++;
unsignedCookie = utils.parseSignedCookie(rawCookie, secret);
}
_$jscoverage['middleware/session.js'][248]++;
res.on("header", (function () {
_$jscoverage['middleware/session.js'][249]++;
if (! req.session) {
_$jscoverage['middleware/session.js'][249]++;
return;
}
_$jscoverage['middleware/session.js'][250]++;
var cookie = req.session.cookie, proto = (req.headers["x-forwarded-proto"] || "").toLowerCase(), tls = req.connection.encrypted || (trustProxy && "https" == proto), secured = cookie.secure && tls, isNew = unsignedCookie != req.sessionID;
_$jscoverage['middleware/session.js'][257]++;
if (cookie.secure && ! secured) {
_$jscoverage['middleware/session.js'][257]++;
return debug("not secured");
}
_$jscoverage['middleware/session.js'][260]++;
if (null == cookie.expires) {
_$jscoverage['middleware/session.js'][261]++;
if (! isNew) {
_$jscoverage['middleware/session.js'][261]++;
return debug("already set browser-session cookie");
}
}
else {
_$jscoverage['middleware/session.js'][263]++;
if (originalHash == hash(req.session) && originalId == req.session.id) {
_$jscoverage['middleware/session.js'][264]++;
return debug("unmodified session");
}
}
_$jscoverage['middleware/session.js'][267]++;
var val = "s:" + signature.sign(req.sessionID, secret);
_$jscoverage['middleware/session.js'][268]++;
val = cookie.serialize(key, val);
_$jscoverage['middleware/session.js'][269]++;
debug("set-cookie %s", val);
_$jscoverage['middleware/session.js'][270]++;
res.setHeader("Set-Cookie", val);
}));
_$jscoverage['middleware/session.js'][274]++;
var end = res.end;
_$jscoverage['middleware/session.js'][275]++;
res.end = (function (data, encoding) {
_$jscoverage['middleware/session.js'][276]++;
res.end = end;
_$jscoverage['middleware/session.js'][277]++;
if (! req.session) {
_$jscoverage['middleware/session.js'][277]++;
return res.end(data, encoding);
}
_$jscoverage['middleware/session.js'][278]++;
debug("saving");
_$jscoverage['middleware/session.js'][279]++;
req.session.resetMaxAge();
_$jscoverage['middleware/session.js'][280]++;
req.session.save((function () {
_$jscoverage['middleware/session.js'][281]++;
debug("saved");
_$jscoverage['middleware/session.js'][282]++;
res.end(data, encoding);
}));
});
_$jscoverage['middleware/session.js'][287]++;
function generate() {
_$jscoverage['middleware/session.js'][288]++;
store.generate(req);
}
_$jscoverage['middleware/session.js'][292]++;
req.sessionID = unsignedCookie;
_$jscoverage['middleware/session.js'][295]++;
if (! req.sessionID) {
_$jscoverage['middleware/session.js'][296]++;
debug("no SID sent, generating session");
_$jscoverage['middleware/session.js'][297]++;
generate();
_$jscoverage['middleware/session.js'][298]++;
next();
_$jscoverage['middleware/session.js'][299]++;
return;
}
_$jscoverage['middleware/session.js'][303]++;
var pause = utils.pause(req);
_$jscoverage['middleware/session.js'][304]++;
debug("fetching %s", req.sessionID);
_$jscoverage['middleware/session.js'][305]++;
store.get(req.sessionID, (function (err, sess) {
_$jscoverage['middleware/session.js'][307]++;
var _next = next;
_$jscoverage['middleware/session.js'][308]++;
next = (function (err) {
_$jscoverage['middleware/session.js'][309]++;
_next(err);
_$jscoverage['middleware/session.js'][310]++;
pause.resume();
});
_$jscoverage['middleware/session.js'][314]++;
if (err) {
_$jscoverage['middleware/session.js'][315]++;
debug("error");
_$jscoverage['middleware/session.js'][316]++;
if ("ENOENT" == err.code) {
_$jscoverage['middleware/session.js'][317]++;
generate();
_$jscoverage['middleware/session.js'][318]++;
next();
}
else {
_$jscoverage['middleware/session.js'][320]++;
next(err);
}
}
else {
_$jscoverage['middleware/session.js'][323]++;
if (! sess) {
_$jscoverage['middleware/session.js'][324]++;
debug("no session found");
_$jscoverage['middleware/session.js'][325]++;
generate();
_$jscoverage['middleware/session.js'][326]++;
next();
}
else {
_$jscoverage['middleware/session.js'][329]++;
debug("session found");
_$jscoverage['middleware/session.js'][330]++;
store.createSession(req, sess);
_$jscoverage['middleware/session.js'][331]++;
originalId = req.sessionID;
_$jscoverage['middleware/session.js'][332]++;
originalHash = hash(sess);
_$jscoverage['middleware/session.js'][333]++;
next();
}
}
}));
});
}
_$jscoverage['middleware/session.js'][337]++;
;
_$jscoverage['middleware/session.js'][348]++;
function hash(sess) {
_$jscoverage['middleware/session.js'][349]++;
return crc16(JSON.stringify(sess, (function (key, val) {
_$jscoverage['middleware/session.js'][350]++;
if ("cookie" != key) {
_$jscoverage['middleware/session.js'][350]++;
return val;
}
})));
}
_$jscoverage['middleware/session.js'].source = ["","/*!"," * Connect - session"," * Copyright(c) 2010 Sencha Inc."," * Copyright(c) 2011 TJ Holowaychuk"," * MIT Licensed"," */","","/**"," * Module dependencies."," */","","var Session = require('./session/session')"," , debug = require('debug')('connect:session')"," , MemoryStore = require('./session/memory')"," , signature = require('cookie-signature')"," , Cookie = require('./session/cookie')"," , Store = require('./session/store')"," , utils = require('./../utils')"," , parse = utils.parseUrl"," , crc16 = require('crc').crc16;","","// environment","","var env = process.env.NODE_ENV;","","/**"," * Expose the middleware."," */","","exports = module.exports = session;","","/**"," * Expose constructors."," */","","exports.Store = Store;","exports.Cookie = Cookie;","exports.Session = Session;","exports.MemoryStore = MemoryStore;","","/**"," * Warning message for `MemoryStore` usage in production."," */","","var warning = 'Warning: connection.session() MemoryStore is not\\n'"," + 'designed for a production environment, as it will leak\\n'"," + 'memory, and will not scale past a single process.';","","/**"," * Session:"," * "," * Setup session store with the given `options`."," *"," * Session data is _not_ saved in the cookie itself, however"," * cookies are used, so we must use the [cookieParser()](cookieParser.html)"," * middleware _before_ `session()`."," *"," * Examples:"," *"," * connect()"," * .use(connect.cookieParser())"," * .use(connect.session({ secret: 'keyboard cat', key: 'sid', cookie: { secure: true }}))"," *"," * Options:"," *"," * - `key` cookie name defaulting to `connect.sid`"," * - `store` session store instance"," * - `secret` session cookie is signed with this secret to prevent tampering"," * - `cookie` session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: null }`"," * - `proxy` trust the reverse proxy when setting secure cookies (via \"x-forwarded-proto\")"," *"," * Cookie option:"," *"," * By default `cookie.maxAge` is `null`, meaning no \"expires\" parameter is set"," * so the cookie becomes a browser-session cookie. When the user closes the "," * browser the cookie (and session) will be removed."," *"," * ## req.session"," *"," * To store or access session data, simply use the request property `req.session`,"," * which is (generally) serialized as JSON by the store, so nested objects "," * are typically fine. For example below is a user-specific view counter:"," *"," * connect()"," * .use(connect.favicon())"," * .use(connect.cookieParser())"," * .use(connect.session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }}))"," * .use(function(req, res, next){"," * var sess = req.session;"," * if (sess.views) {"," * res.setHeader('Content-Type', 'text/html');"," * res.write('&lt;p&gt;views: ' + sess.views + '&lt;/p&gt;');"," * res.write('&lt;p&gt;expires in: ' + (sess.cookie.maxAge / 1000) + 's&lt;/p&gt;');"," * res.end();"," * sess.views++;"," * } else {"," * sess.views = 1;"," * res.end('welcome to the session demo. refresh!');"," * }"," * }"," * )).listen(3000);"," *"," * ## Session#regenerate()"," *"," * To regenerate the session simply invoke the method, once complete"," * a new SID and `Session` instance will be initialized at `req.session`."," *"," * req.session.regenerate(function(err){"," * // will have a new session here"," * });"," *"," * ## Session#destroy()"," *"," * Destroys the session, removing `req.session`, will be re-generated next request."," *"," * req.session.destroy(function(err){"," * // cannot access session here"," * });"," * "," * ## Session#reload()"," *"," * Reloads the session data."," *"," * req.session.reload(function(err){"," * // session updated"," * });"," *"," * ## Session#save()"," *"," * Save the session."," *"," * req.session.save(function(err){"," * // session saved"," * });"," *"," * ## Session#touch()"," *"," * Updates the `.maxAge` property. Typically this is"," * not necessary to call, as the session middleware does this for you."," *"," * ## Session#cookie"," *"," * Each session has a unique cookie object accompany it. This allows"," * you to alter the session cookie per visitor. For example we can"," * set `req.session.cookie.expires` to `false` to enable the cookie"," * to remain for only the duration of the user-agent."," *"," * ## Session#maxAge"," *"," * Alternatively `req.session.cookie.maxAge` will return the time"," * remaining in milliseconds, which we may also re-assign a new value"," * to adjust the `.expires` property appropriately. The following"," * are essentially equivalent"," *"," * var hour = 3600000;"," * req.session.cookie.expires = new Date(Date.now() + hour);"," * req.session.cookie.maxAge = hour;"," *"," * For example when `maxAge` is set to `60000` (one minute), and 30 seconds"," * has elapsed it will return `30000` until the current request has completed,"," * at which time `req.session.touch()` is called to reset `req.session.maxAge`"," * to its original value."," *"," * req.session.cookie.maxAge;"," * // =&gt; 30000"," *"," * Session Store Implementation:"," *"," * Every session store _must_ implement the following methods"," *"," * - `.get(sid, callback)`"," * - `.set(sid, session, callback)`"," * - `.destroy(sid, callback)`"," *"," * Recommended methods include, but are not limited to:"," *"," * - `.length(callback)`"," * - `.clear(callback)`"," *"," * For an example implementation view the [connect-redis](http://github.com/visionmedia/connect-redis) repo."," *"," * @param {Object} options"," * @return {Function}"," * @api public"," */","","function session(options){"," var options = options || {}"," , key = options.key || 'connect.sid'"," , store = options.store || new MemoryStore"," , cookie = options.cookie || {}"," , trustProxy = options.proxy"," , storeReady = true;",""," // notify user that this store is not"," // meant for a production environment"," if ('production' == env &amp;&amp; store instanceof MemoryStore) {"," console.warn(warning);"," }",""," // generates the new session"," store.generate = function(req){"," req.sessionID = utils.uid(24);"," req.session = new Session(req);"," req.session.cookie = new Cookie(cookie);"," };",""," store.on('disconnect', function(){ storeReady = false; });"," store.on('connect', function(){ storeReady = true; });",""," return function session(req, res, next) {"," // self-awareness"," if (req.session) return next();",""," // Handle connection as if there is no session if"," // the store has temporarily disconnected etc"," if (!storeReady) return debug('store is disconnected'), next();",""," // pathname mismatch"," if (0 != req.originalUrl.indexOf(cookie.path || '/')) return next();",""," // backwards compatibility for signed cookies"," // req.secret is passed from the cookie parser middleware"," var secret = options.secret || req.secret;",""," // ensure secret is available or bail"," if (!secret) throw new Error('`secret` option required for sessions');",""," // parse url"," var originalHash"," , originalId;",""," // expose store"," req.sessionStore = store;",""," // grab the session cookie value and check the signature"," var rawCookie = req.cookies[key];",""," // get signedCookies for backwards compat with signed cookies"," var unsignedCookie = req.signedCookies[key];",""," if (!unsignedCookie &amp;&amp; rawCookie) {"," unsignedCookie = utils.parseSignedCookie(rawCookie, secret);"," }",""," // set-cookie"," res.on('header', function(){"," if (!req.session) return;"," var cookie = req.session.cookie"," , proto = (req.headers['x-forwarded-proto'] || '').toLowerCase()"," , tls = req.connection.encrypted || (trustProxy &amp;&amp; 'https' == proto)"," , secured = cookie.secure &amp;&amp; tls"," , isNew = unsignedCookie != req.sessionID;",""," // only send secure cookies via https"," if (cookie.secure &amp;&amp; !secured) return debug('not secured');",""," // browser-session length cookie"," if (null == cookie.expires) {"," if (!isNew) return debug('already set browser-session cookie');"," // compare hashes and ids"," } else if (originalHash == hash(req.session) &amp;&amp; originalId == req.session.id) {"," return debug('unmodified session');"," }",""," var val = 's:' + signature.sign(req.sessionID, secret);"," val = cookie.serialize(key, val);"," debug('set-cookie %s', val);"," res.setHeader('Set-Cookie', val);"," });",""," // proxy end() to commit the session"," var end = res.end;"," res.end = function(data, encoding){"," res.end = end;"," if (!req.session) return res.end(data, encoding);"," debug('saving');"," req.session.resetMaxAge();"," req.session.save(function(){"," debug('saved');"," res.end(data, encoding);"," });"," };",""," // generate the session"," function generate() {"," store.generate(req);"," }",""," // get the sessionID from the cookie"," req.sessionID = unsignedCookie;",""," // generate a session if the browser doesn't send a sessionID"," if (!req.sessionID) {"," debug('no SID sent, generating session');"," generate();"," next();"," return;"," }",""," // generate the session object"," var pause = utils.pause(req);"," debug('fetching %s', req.sessionID);"," store.get(req.sessionID, function(err, sess){"," // proxy to resume() events"," var _next = next;"," next = function(err){"," _next(err);"," pause.resume();"," };",""," // error handling"," if (err) {"," debug('error');"," if ('ENOENT' == err.code) {"," generate();"," next();"," } else {"," next(err);"," }"," // no session"," } else if (!sess) {"," debug('no session found');"," generate();"," next();"," // populate req.session"," } else {"," debug('session found');"," store.createSession(req, sess);"," originalId = req.sessionID;"," originalHash = hash(sess);"," next();"," }"," });"," };","};","","/**"," * Hash the given `sess` object omitting changes"," * to `.cookie`."," *"," * @param {Object} sess"," * @return {String}"," * @api private"," */","","function hash(sess) {"," return crc16(JSON.stringify(sess, function(key, val){"," if ('cookie' != key) return val;"," }));","}"];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['middleware/session/memory.js']) {
_$jscoverage['middleware/session/memory.js'] = [];
_$jscoverage['middleware/session/memory.js'][13] = 0;
_$jscoverage['middleware/session/memory.js'][21] = 0;
_$jscoverage['middleware/session/memory.js'][22] = 0;
_$jscoverage['middleware/session/memory.js'][29] = 0;
_$jscoverage['middleware/session/memory.js'][39] = 0;
_$jscoverage['middleware/session/memory.js'][40] = 0;
_$jscoverage['middleware/session/memory.js'][41] = 0;
_$jscoverage['middleware/session/memory.js'][42] = 0;
_$jscoverage['middleware/session/memory.js'][44] = 0;
_$jscoverage['middleware/session/memory.js'][45] = 0;
_$jscoverage['middleware/session/memory.js'][46] = 0;
_$jscoverage['middleware/session/memory.js'][49] = 0;
_$jscoverage['middleware/session/memory.js'][50] = 0;
_$jscoverage['middleware/session/memory.js'][52] = 0;
_$jscoverage['middleware/session/memory.js'][55] = 0;
_$jscoverage['middleware/session/memory.js'][69] = 0;
_$jscoverage['middleware/session/memory.js'][70] = 0;
_$jscoverage['middleware/session/memory.js'][71] = 0;
_$jscoverage['middleware/session/memory.js'][72] = 0;
_$jscoverage['middleware/session/memory.js'][73] = 0;
_$jscoverage['middleware/session/memory.js'][84] = 0;
_$jscoverage['middleware/session/memory.js'][85] = 0;
_$jscoverage['middleware/session/memory.js'][86] = 0;
_$jscoverage['middleware/session/memory.js'][87] = 0;
_$jscoverage['middleware/session/memory.js'][88] = 0;
_$jscoverage['middleware/session/memory.js'][99] = 0;
_$jscoverage['middleware/session/memory.js'][100] = 0;
_$jscoverage['middleware/session/memory.js'][102] = 0;
_$jscoverage['middleware/session/memory.js'][103] = 0;
_$jscoverage['middleware/session/memory.js'][105] = 0;
_$jscoverage['middleware/session/memory.js'][115] = 0;
_$jscoverage['middleware/session/memory.js'][116] = 0;
_$jscoverage['middleware/session/memory.js'][117] = 0;
_$jscoverage['middleware/session/memory.js'][127] = 0;
_$jscoverage['middleware/session/memory.js'][128] = 0;
}
_$jscoverage['middleware/session/memory.js'][13]++;
var Store = require("./store");
_$jscoverage['middleware/session/memory.js'][21]++;
var MemoryStore = module.exports = (function MemoryStore() {
_$jscoverage['middleware/session/memory.js'][22]++;
this.sessions = {};
});
_$jscoverage['middleware/session/memory.js'][29]++;
MemoryStore.prototype.__proto__ = Store.prototype;
_$jscoverage['middleware/session/memory.js'][39]++;
MemoryStore.prototype.get = (function (sid, fn) {
_$jscoverage['middleware/session/memory.js'][40]++;
var self = this;
_$jscoverage['middleware/session/memory.js'][41]++;
process.nextTick((function () {
_$jscoverage['middleware/session/memory.js'][42]++;
var expires, sess = self.sessions[sid];
_$jscoverage['middleware/session/memory.js'][44]++;
if (sess) {
_$jscoverage['middleware/session/memory.js'][45]++;
sess = JSON.parse(sess);
_$jscoverage['middleware/session/memory.js'][46]++;
expires = "string" == typeof sess.cookie.expires? new Date(sess.cookie.expires): sess.cookie.expires;
_$jscoverage['middleware/session/memory.js'][49]++;
if (! expires || new Date() < expires) {
_$jscoverage['middleware/session/memory.js'][50]++;
fn(null, sess);
}
else {
_$jscoverage['middleware/session/memory.js'][52]++;
self.destroy(sid, fn);
}
}
else {
_$jscoverage['middleware/session/memory.js'][55]++;
fn();
}
}));
});
_$jscoverage['middleware/session/memory.js'][69]++;
MemoryStore.prototype.set = (function (sid, sess, fn) {
_$jscoverage['middleware/session/memory.js'][70]++;
var self = this;
_$jscoverage['middleware/session/memory.js'][71]++;
process.nextTick((function () {
_$jscoverage['middleware/session/memory.js'][72]++;
self.sessions[sid] = JSON.stringify(sess);
_$jscoverage['middleware/session/memory.js'][73]++;
fn && fn();
}));
});
_$jscoverage['middleware/session/memory.js'][84]++;
MemoryStore.prototype.destroy = (function (sid, fn) {
_$jscoverage['middleware/session/memory.js'][85]++;
var self = this;
_$jscoverage['middleware/session/memory.js'][86]++;
process.nextTick((function () {
_$jscoverage['middleware/session/memory.js'][87]++;
delete self.sessions[sid];
_$jscoverage['middleware/session/memory.js'][88]++;
fn && fn();
}));
});
_$jscoverage['middleware/session/memory.js'][99]++;
MemoryStore.prototype.all = (function (fn) {
_$jscoverage['middleware/session/memory.js'][100]++;
var arr = [], keys = Object.keys(this.sessions);
_$jscoverage['middleware/session/memory.js'][102]++;
for (var i = 0, len = keys.length; i < len; ++i) {
_$jscoverage['middleware/session/memory.js'][103]++;
arr.push(this.sessions[keys[i]]);
}
_$jscoverage['middleware/session/memory.js'][105]++;
fn(null, arr);
});
_$jscoverage['middleware/session/memory.js'][115]++;
MemoryStore.prototype.clear = (function (fn) {
_$jscoverage['middleware/session/memory.js'][116]++;
this.sessions = {};
_$jscoverage['middleware/session/memory.js'][117]++;
fn && fn();
});
_$jscoverage['middleware/session/memory.js'][127]++;
MemoryStore.prototype.length = (function (fn) {
_$jscoverage['middleware/session/memory.js'][128]++;
fn(null, Object.keys(this.sessions).length);
});
_$jscoverage['middleware/session/memory.js'].source = ["","/*!"," * Connect - session - MemoryStore"," * Copyright(c) 2010 Sencha Inc."," * Copyright(c) 2011 TJ Holowaychuk"," * MIT Licensed"," */","","/**"," * Module dependencies."," */","","var Store = require('./store');","","/**"," * Initialize a new `MemoryStore`."," *"," * @api public"," */","","var MemoryStore = module.exports = function MemoryStore() {"," this.sessions = {};","};","","/**"," * Inherit from `Store.prototype`."," */","","MemoryStore.prototype.__proto__ = Store.prototype;","","/**"," * Attempt to fetch session by the given `sid`."," *"," * @param {String} sid"," * @param {Function} fn"," * @api public"," */","","MemoryStore.prototype.get = function(sid, fn){"," var self = this;"," process.nextTick(function(){"," var expires"," , sess = self.sessions[sid];"," if (sess) {"," sess = JSON.parse(sess);"," expires = 'string' == typeof sess.cookie.expires"," ? new Date(sess.cookie.expires)"," : sess.cookie.expires;"," if (!expires || new Date &lt; expires) {"," fn(null, sess);"," } else {"," self.destroy(sid, fn);"," }"," } else {"," fn();"," }"," });","};","","/**"," * Commit the given `sess` object associated with the given `sid`."," *"," * @param {String} sid"," * @param {Session} sess"," * @param {Function} fn"," * @api public"," */","","MemoryStore.prototype.set = function(sid, sess, fn){"," var self = this;"," process.nextTick(function(){"," self.sessions[sid] = JSON.stringify(sess);"," fn &amp;&amp; fn();"," });","};","","/**"," * Destroy the session associated with the given `sid`."," *"," * @param {String} sid"," * @api public"," */","","MemoryStore.prototype.destroy = function(sid, fn){"," var self = this;"," process.nextTick(function(){"," delete self.sessions[sid];"," fn &amp;&amp; fn();"," });","};","","/**"," * Invoke the given callback `fn` with all active sessions."," *"," * @param {Function} fn"," * @api public"," */","","MemoryStore.prototype.all = function(fn){"," var arr = []"," , keys = Object.keys(this.sessions);"," for (var i = 0, len = keys.length; i &lt; len; ++i) {"," arr.push(this.sessions[keys[i]]);"," }"," fn(null, arr);","};","","/**"," * Clear all sessions."," *"," * @param {Function} fn"," * @api public"," */","","MemoryStore.prototype.clear = function(fn){"," this.sessions = {};"," fn &amp;&amp; fn();","};","","/**"," * Fetch number of sessions."," *"," * @param {Function} fn"," * @api public"," */","","MemoryStore.prototype.length = function(fn){"," fn(null, Object.keys(this.sessions).length);","};"];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['middleware/session/session.js']) {
_$jscoverage['middleware/session/session.js'] = [];
_$jscoverage['middleware/session/session.js'][13] = 0;
_$jscoverage['middleware/session/session.js'][23] = 0;
_$jscoverage['middleware/session/session.js'][24] = 0;
_$jscoverage['middleware/session/session.js'][25] = 0;
_$jscoverage['middleware/session/session.js'][26] = 0;
_$jscoverage['middleware/session/session.js'][38] = 0;
_$jscoverage['middleware/session/session.js'][39] = 0;
_$jscoverage['middleware/session/session.js'][49] = 0;
_$jscoverage['middleware/session/session.js'][50] = 0;
_$jscoverage['middleware/session/session.js'][51] = 0;
_$jscoverage['middleware/session/session.js'][62] = 0;
_$jscoverage['middleware/session/session.js'][63] = 0;
_$jscoverage['middleware/session/session.js'][64] = 0;
_$jscoverage['middleware/session/session.js'][79] = 0;
_$jscoverage['middleware/session/session.js'][80] = 0;
_$jscoverage['middleware/session/session.js'][82] = 0;
_$jscoverage['middleware/session/session.js'][83] = 0;
_$jscoverage['middleware/session/session.js'][84] = 0;
_$jscoverage['middleware/session/session.js'][85] = 0;
_$jscoverage['middleware/session/session.js'][86] = 0;
_$jscoverage['middleware/session/session.js'][88] = 0;
_$jscoverage['middleware/session/session.js'][99] = 0;
_$jscoverage['middleware/session/session.js'][100] = 0;
_$jscoverage['middleware/session/session.js'][101] = 0;
_$jscoverage['middleware/session/session.js'][102] = 0;
_$jscoverage['middleware/session/session.js'][113] = 0;
_$jscoverage['middleware/session/session.js'][114] = 0;
_$jscoverage['middleware/session/session.js'][115] = 0;
}
_$jscoverage['middleware/session/session.js'][13]++;
var utils = require("../../utils");
_$jscoverage['middleware/session/session.js'][23]++;
var Session = module.exports = (function Session(req, data) {
_$jscoverage['middleware/session/session.js'][24]++;
Object.defineProperty(this, "req", {value: req});
_$jscoverage['middleware/session/session.js'][25]++;
Object.defineProperty(this, "id", {value: req.sessionID});
_$jscoverage['middleware/session/session.js'][26]++;
if ("object" == typeof data) {
_$jscoverage['middleware/session/session.js'][26]++;
utils.merge(this, data);
}
});
_$jscoverage['middleware/session/session.js'][38]++;
Session.prototype.touch = (function () {
_$jscoverage['middleware/session/session.js'][39]++;
return this.resetMaxAge();
});
_$jscoverage['middleware/session/session.js'][49]++;
Session.prototype.resetMaxAge = (function () {
_$jscoverage['middleware/session/session.js'][50]++;
this.cookie.maxAge = this.cookie.originalMaxAge;
_$jscoverage['middleware/session/session.js'][51]++;
return this;
});
_$jscoverage['middleware/session/session.js'][62]++;
Session.prototype.save = (function (fn) {
_$jscoverage['middleware/session/session.js'][63]++;
this.req.sessionStore.set(this.id, this, fn || (function () {
}));
_$jscoverage['middleware/session/session.js'][64]++;
return this;
});
_$jscoverage['middleware/session/session.js'][79]++;
Session.prototype.reload = (function (fn) {
_$jscoverage['middleware/session/session.js'][80]++;
var req = this.req, store = this.req.sessionStore;
_$jscoverage['middleware/session/session.js'][82]++;
store.get(this.id, (function (err, sess) {
_$jscoverage['middleware/session/session.js'][83]++;
if (err) {
_$jscoverage['middleware/session/session.js'][83]++;
return fn(err);
}
_$jscoverage['middleware/session/session.js'][84]++;
if (! sess) {
_$jscoverage['middleware/session/session.js'][84]++;
return fn(new Error("failed to load session"));
}
_$jscoverage['middleware/session/session.js'][85]++;
store.createSession(req, sess);
_$jscoverage['middleware/session/session.js'][86]++;
fn();
}));
_$jscoverage['middleware/session/session.js'][88]++;
return this;
});
_$jscoverage['middleware/session/session.js'][99]++;
Session.prototype.destroy = (function (fn) {
_$jscoverage['middleware/session/session.js'][100]++;
delete this.req.session;
_$jscoverage['middleware/session/session.js'][101]++;
this.req.sessionStore.destroy(this.id, fn);
_$jscoverage['middleware/session/session.js'][102]++;
return this;
});
_$jscoverage['middleware/session/session.js'][113]++;
Session.prototype.regenerate = (function (fn) {
_$jscoverage['middleware/session/session.js'][114]++;
this.req.sessionStore.regenerate(this.req, fn);
_$jscoverage['middleware/session/session.js'][115]++;
return this;
});
_$jscoverage['middleware/session/session.js'].source = ["","/*!"," * Connect - session - Session"," * Copyright(c) 2010 Sencha Inc."," * Copyright(c) 2011 TJ Holowaychuk"," * MIT Licensed"," */","","/**"," * Module dependencies."," */","","var utils = require('../../utils');","","/**"," * Create a new `Session` with the given request and `data`."," *"," * @param {IncomingRequest} req"," * @param {Object} data"," * @api private"," */","","var Session = module.exports = function Session(req, data) {"," Object.defineProperty(this, 'req', { value: req });"," Object.defineProperty(this, 'id', { value: req.sessionID });"," if ('object' == typeof data) utils.merge(this, data);","};","","/**"," * Update reset `.cookie.maxAge` to prevent"," * the cookie from expiring when the"," * session is still active."," *"," * @return {Session} for chaining"," * @api public"," */","","Session.prototype.touch = function(){"," return this.resetMaxAge();","};","","/**"," * Reset `.maxAge` to `.originalMaxAge`."," *"," * @return {Session} for chaining"," * @api public"," */","","Session.prototype.resetMaxAge = function(){"," this.cookie.maxAge = this.cookie.originalMaxAge;"," return this;","};","","/**"," * Save the session data with optional callback `fn(err)`."," *"," * @param {Function} fn"," * @return {Session} for chaining"," * @api public"," */","","Session.prototype.save = function(fn){"," this.req.sessionStore.set(this.id, this, fn || function(){});"," return this;","};","","/**"," * Re-loads the session data _without_ altering"," * the maxAge properties. Invokes the callback `fn(err)`,"," * after which time if no exception has occurred the"," * `req.session` property will be a new `Session` object,"," * although representing the same session."," *"," * @param {Function} fn"," * @return {Session} for chaining"," * @api public"," */","","Session.prototype.reload = function(fn){"," var req = this.req"," , store = this.req.sessionStore;"," store.get(this.id, function(err, sess){"," if (err) return fn(err);"," if (!sess) return fn(new Error('failed to load session'));"," store.createSession(req, sess);"," fn();"," });"," return this;","};","","/**"," * Destroy `this` session."," *"," * @param {Function} fn"," * @return {Session} for chaining"," * @api public"," */","","Session.prototype.destroy = function(fn){"," delete this.req.session;"," this.req.sessionStore.destroy(this.id, fn);"," return this;","};","","/**"," * Regenerate this request's session."," *"," * @param {Function} fn"," * @return {Session} for chaining"," * @api public"," */","","Session.prototype.regenerate = function(fn){"," this.req.sessionStore.regenerate(this.req, fn);"," return this;","};"];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['middleware/session/store.js']) {
_$jscoverage['middleware/session/store.js'] = [];
_$jscoverage['middleware/session/store.js'][13] = 0;
_$jscoverage['middleware/session/store.js'][23] = 0;
_$jscoverage['middleware/session/store.js'][29] = 0;
_$jscoverage['middleware/session/store.js'][39] = 0;
_$jscoverage['middleware/session/store.js'][40] = 0;
_$jscoverage['middleware/session/store.js'][41] = 0;
_$jscoverage['middleware/session/store.js'][42] = 0;
_$jscoverage['middleware/session/store.js'][43] = 0;
_$jscoverage['middleware/session/store.js'][56] = 0;
_$jscoverage['middleware/session/store.js'][57] = 0;
_$jscoverage['middleware/session/store.js'][58] = 0;
_$jscoverage['middleware/session/store.js'][59] = 0;
_$jscoverage['middleware/session/store.js'][60] = 0;
_$jscoverage['middleware/session/store.js'][61] = 0;
_$jscoverage['middleware/session/store.js'][62] = 0;
_$jscoverage['middleware/session/store.js'][63] = 0;
_$jscoverage['middleware/session/store.js'][76] = 0;
_$jscoverage['middleware/session/store.js'][77] = 0;
_$jscoverage['middleware/session/store.js'][79] = 0;
_$jscoverage['middleware/session/store.js'][80] = 0;
_$jscoverage['middleware/session/store.js'][81] = 0;
_$jscoverage['middleware/session/store.js'][82] = 0;
_$jscoverage['middleware/session/store.js'][83] = 0;
}
_$jscoverage['middleware/session/store.js'][13]++;
var EventEmitter = require("events").EventEmitter, Session = require("./session"), Cookie = require("./cookie");
_$jscoverage['middleware/session/store.js'][23]++;
var Store = module.exports = (function Store(options) {
});
_$jscoverage['middleware/session/store.js'][29]++;
Store.prototype.__proto__ = EventEmitter.prototype;
_$jscoverage['middleware/session/store.js'][39]++;
Store.prototype.regenerate = (function (req, fn) {
_$jscoverage['middleware/session/store.js'][40]++;
var self = this;
_$jscoverage['middleware/session/store.js'][41]++;
this.destroy(req.sessionID, (function (err) {
_$jscoverage['middleware/session/store.js'][42]++;
self.generate(req);
_$jscoverage['middleware/session/store.js'][43]++;
fn(err);
}));
});
_$jscoverage['middleware/session/store.js'][56]++;
Store.prototype.load = (function (sid, fn) {
_$jscoverage['middleware/session/store.js'][57]++;
var self = this;
_$jscoverage['middleware/session/store.js'][58]++;
this.get(sid, (function (err, sess) {
_$jscoverage['middleware/session/store.js'][59]++;
if (err) {
_$jscoverage['middleware/session/store.js'][59]++;
return fn(err);
}
_$jscoverage['middleware/session/store.js'][60]++;
if (! sess) {
_$jscoverage['middleware/session/store.js'][60]++;
return fn();
}
_$jscoverage['middleware/session/store.js'][61]++;
var req = {sessionID: sid, sessionStore: self};
_$jscoverage['middleware/session/store.js'][62]++;
sess = self.createSession(req, sess);
_$jscoverage['middleware/session/store.js'][63]++;
fn(null, sess);
}));
});
_$jscoverage['middleware/session/store.js'][76]++;
Store.prototype.createSession = (function (req, sess) {
_$jscoverage['middleware/session/store.js'][77]++;
var expires = sess.cookie.expires, orig = sess.cookie.originalMaxAge;
_$jscoverage['middleware/session/store.js'][79]++;
sess.cookie = new Cookie(sess.cookie);
_$jscoverage['middleware/session/store.js'][80]++;
if ("string" == typeof expires) {
_$jscoverage['middleware/session/store.js'][80]++;
sess.cookie.expires = new Date(expires);
}
_$jscoverage['middleware/session/store.js'][81]++;
sess.cookie.originalMaxAge = orig;
_$jscoverage['middleware/session/store.js'][82]++;
req.session = new Session(req, sess);
_$jscoverage['middleware/session/store.js'][83]++;
return req.session;
});
_$jscoverage['middleware/session/store.js'].source = ["","/*!"," * Connect - session - Store"," * Copyright(c) 2010 Sencha Inc."," * Copyright(c) 2011 TJ Holowaychuk"," * MIT Licensed"," */","","/**"," * Module dependencies."," */","","var EventEmitter = require('events').EventEmitter"," , Session = require('./session')"," , Cookie = require('./cookie');","","/**"," * Initialize abstract `Store`."," *"," * @api private"," */","","var Store = module.exports = function Store(options){};","","/**"," * Inherit from `EventEmitter.prototype`."," */","","Store.prototype.__proto__ = EventEmitter.prototype;","","/**"," * Re-generate the given requests's session."," *"," * @param {IncomingRequest} req"," * @return {Function} fn"," * @api public"," */","","Store.prototype.regenerate = function(req, fn){"," var self = this;"," this.destroy(req.sessionID, function(err){"," self.generate(req);"," fn(err);"," });","};","","/**"," * Load a `Session` instance via the given `sid`"," * and invoke the callback `fn(err, sess)`."," *"," * @param {String} sid"," * @param {Function} fn"," * @api public"," */","","Store.prototype.load = function(sid, fn){"," var self = this;"," this.get(sid, function(err, sess){"," if (err) return fn(err);"," if (!sess) return fn();"," var req = { sessionID: sid, sessionStore: self };"," sess = self.createSession(req, sess);"," fn(null, sess);"," });","};","","/**"," * Create session from JSON `sess` data."," *"," * @param {IncomingRequest} req"," * @param {Object} sess"," * @return {Session}"," * @api private"," */","","Store.prototype.createSession = function(req, sess){"," var expires = sess.cookie.expires"," , orig = sess.cookie.originalMaxAge;"," sess.cookie = new Cookie(sess.cookie);"," if ('string' == typeof expires) sess.cookie.expires = new Date(expires);"," sess.cookie.originalMaxAge = orig;"," req.session = new Session(req, sess);"," return req.session;","};"];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['middleware/static.js']) {
_$jscoverage['middleware/static.js'] = [];
_$jscoverage['middleware/static.js'][13] = 0;
_$jscoverage['middleware/static.js'][45] = 0;
_$jscoverage['middleware/static.js'][46] = 0;
_$jscoverage['middleware/static.js'][49] = 0;
_$jscoverage['middleware/static.js'][52] = 0;
_$jscoverage['middleware/static.js'][54] = 0;
_$jscoverage['middleware/static.js'][55] = 0;
_$jscoverage['middleware/static.js'][56] = 0;
_$jscoverage['middleware/static.js'][57] = 0;
_$jscoverage['middleware/static.js'][59] = 0;
_$jscoverage['middleware/static.js'][60] = 0;
_$jscoverage['middleware/static.js'][61] = 0;
_$jscoverage['middleware/static.js'][64] = 0;
_$jscoverage['middleware/static.js'][65] = 0;
_$jscoverage['middleware/static.js'][66] = 0;
_$jscoverage['middleware/static.js'][67] = 0;
_$jscoverage['middleware/static.js'][68] = 0;
_$jscoverage['middleware/static.js'][69] = 0;
_$jscoverage['middleware/static.js'][72] = 0;
_$jscoverage['middleware/static.js'][73] = 0;
_$jscoverage['middleware/static.js'][74] = 0;
_$jscoverage['middleware/static.js'][77] = 0;
_$jscoverage['middleware/static.js'][94] = 0;
}
_$jscoverage['middleware/static.js'][13]++;
var send = require("send"), utils = require("../utils"), parse = utils.parseUrl, url = require("url");
_$jscoverage['middleware/static.js'][45]++;
exports = module.exports = (function static(root, options) {
_$jscoverage['middleware/static.js'][46]++;
options = options || {};
_$jscoverage['middleware/static.js'][49]++;
if (! root) {
_$jscoverage['middleware/static.js'][49]++;
throw new Error("static() root path required");
}
_$jscoverage['middleware/static.js'][52]++;
var redirect = false !== options.redirect;
_$jscoverage['middleware/static.js'][54]++;
return (function static(req, res, next) {
_$jscoverage['middleware/static.js'][55]++;
if ("GET" != req.method && "HEAD" != req.method) {
_$jscoverage['middleware/static.js'][55]++;
return next();
}
_$jscoverage['middleware/static.js'][56]++;
var path = parse(req).pathname;
_$jscoverage['middleware/static.js'][57]++;
var pause = utils.pause(req);
_$jscoverage['middleware/static.js'][59]++;
function resume() {
_$jscoverage['middleware/static.js'][60]++;
next();
_$jscoverage['middleware/static.js'][61]++;
pause.resume();
}
_$jscoverage['middleware/static.js'][64]++;
function directory() {
_$jscoverage['middleware/static.js'][65]++;
if (! redirect) {
_$jscoverage['middleware/static.js'][65]++;
return resume();
}
_$jscoverage['middleware/static.js'][66]++;
var pathname = url.parse(req.originalUrl).pathname;
_$jscoverage['middleware/static.js'][67]++;
res.statusCode = 301;
_$jscoverage['middleware/static.js'][68]++;
res.setHeader("Location", pathname + "/");
_$jscoverage['middleware/static.js'][69]++;
res.end("Redirecting to " + utils.escape(pathname) + "/");
}
_$jscoverage['middleware/static.js'][72]++;
function error(err) {
_$jscoverage['middleware/static.js'][73]++;
if (404 == err.status) {
_$jscoverage['middleware/static.js'][73]++;
return resume();
}
_$jscoverage['middleware/static.js'][74]++;
next(err);
}
_$jscoverage['middleware/static.js'][77]++;
send(req, path).maxage(options.maxAge || 0).root(root).hidden(options.hidden).on("error", error).on("directory", directory).pipe(res);
});
});
_$jscoverage['middleware/static.js'][94]++;
exports.mime = send.mime;
_$jscoverage['middleware/static.js'].source = ["","/*!"," * Connect - static"," * Copyright(c) 2010 Sencha Inc."," * Copyright(c) 2011 TJ Holowaychuk"," * MIT Licensed"," */","","/**"," * Module dependencies."," */","","var send = require('send')"," , utils = require('../utils')"," , parse = utils.parseUrl"," , url = require('url');","","/**"," * Static:"," *"," * Static file server with the given `root` path."," *"," * Examples:"," *"," * var oneDay = 86400000;"," *"," * connect()"," * .use(connect.static(__dirname + '/public'))"," *"," * connect()"," * .use(connect.static(__dirname + '/public', { maxAge: oneDay }))"," *"," * Options:"," *"," * - `maxAge` Browser cache maxAge in milliseconds. defaults to 0"," * - `hidden` Allow transfer of hidden files. defaults to false"," * - `redirect` Redirect to trailing \"/\" when the pathname is a dir. defaults to true"," *"," * @param {String} root"," * @param {Object} options"," * @return {Function}"," * @api public"," */","","exports = module.exports = function static(root, options){"," options = options || {};",""," // root required"," if (!root) throw new Error('static() root path required');",""," // default redirect"," var redirect = false !== options.redirect;",""," return function static(req, res, next) {"," if ('GET' != req.method &amp;&amp; 'HEAD' != req.method) return next();"," var path = parse(req).pathname;"," var pause = utils.pause(req);",""," function resume() {"," next();"," pause.resume();"," }",""," function directory() {"," if (!redirect) return resume();"," var pathname = url.parse(req.originalUrl).pathname;"," res.statusCode = 301;"," res.setHeader('Location', pathname + '/');"," res.end('Redirecting to ' + utils.escape(pathname) + '/');"," }",""," function error(err) {"," if (404 == err.status) return resume();"," next(err);"," }",""," send(req, path)"," .maxage(options.maxAge || 0)"," .root(root)"," .hidden(options.hidden)"," .on('error', error)"," .on('directory', directory)"," .pipe(res);"," };","};","","/**"," * Expose mime module."," * "," * If you wish to extend the mime table use this"," * reference to the \"mime\" module in the npm registry."," */","","exports.mime = send.mime;"];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['middleware/staticCache.js']) {
_$jscoverage['middleware/staticCache.js'] = [];
_$jscoverage['middleware/staticCache.js'][12] = 0;
_$jscoverage['middleware/staticCache.js'][51] = 0;
_$jscoverage['middleware/staticCache.js'][52] = 0;
_$jscoverage['middleware/staticCache.js'][56] = 0;
_$jscoverage['middleware/staticCache.js'][57] = 0;
_$jscoverage['middleware/staticCache.js'][59] = 0;
_$jscoverage['middleware/staticCache.js'][60] = 0;
_$jscoverage['middleware/staticCache.js'][68] = 0;
_$jscoverage['middleware/staticCache.js'][69] = 0;
_$jscoverage['middleware/staticCache.js'][75] = 0;
_$jscoverage['middleware/staticCache.js'][78] = 0;
_$jscoverage['middleware/staticCache.js'][81] = 0;
_$jscoverage['middleware/staticCache.js'][84] = 0;
_$jscoverage['middleware/staticCache.js'][88] = 0;
_$jscoverage['middleware/staticCache.js'][91] = 0;
_$jscoverage['middleware/staticCache.js'][94] = 0;
_$jscoverage['middleware/staticCache.js'][95] = 0;
_$jscoverage['middleware/staticCache.js'][96] = 0;
_$jscoverage['middleware/staticCache.js'][97] = 0;
_$jscoverage['middleware/staticCache.js'][99] = 0;
_$jscoverage['middleware/staticCache.js'][104] = 0;
_$jscoverage['middleware/staticCache.js'][107] = 0;
_$jscoverage['middleware/staticCache.js'][110] = 0;
_$jscoverage['middleware/staticCache.js'][111] = 0;
_$jscoverage['middleware/staticCache.js'][115] = 0;
_$jscoverage['middleware/staticCache.js'][116] = 0;
_$jscoverage['middleware/staticCache.js'][117] = 0;
_$jscoverage['middleware/staticCache.js'][118] = 0;
_$jscoverage['middleware/staticCache.js'][119] = 0;
_$jscoverage['middleware/staticCache.js'][120] = 0;
_$jscoverage['middleware/staticCache.js'][124] = 0;
_$jscoverage['middleware/staticCache.js'][125] = 0;
_$jscoverage['middleware/staticCache.js'][126] = 0;
_$jscoverage['middleware/staticCache.js'][127] = 0;
_$jscoverage['middleware/staticCache.js'][128] = 0;
_$jscoverage['middleware/staticCache.js'][129] = 0;
_$jscoverage['middleware/staticCache.js'][131] = 0;
_$jscoverage['middleware/staticCache.js'][132] = 0;
_$jscoverage['middleware/staticCache.js'][135] = 0;
_$jscoverage['middleware/staticCache.js'][151] = 0;
_$jscoverage['middleware/staticCache.js'][152] = 0;
_$jscoverage['middleware/staticCache.js'][156] = 0;
_$jscoverage['middleware/staticCache.js'][158] = 0;
_$jscoverage['middleware/staticCache.js'][160] = 0;
_$jscoverage['middleware/staticCache.js'][161] = 0;
_$jscoverage['middleware/staticCache.js'][162] = 0;
_$jscoverage['middleware/staticCache.js'][164] = 0;
_$jscoverage['middleware/staticCache.js'][165] = 0;
_$jscoverage['middleware/staticCache.js'][166] = 0;
_$jscoverage['middleware/staticCache.js'][167] = 0;
_$jscoverage['middleware/staticCache.js'][169] = 0;
_$jscoverage['middleware/staticCache.js'][171] = 0;
_$jscoverage['middleware/staticCache.js'][172] = 0;
_$jscoverage['middleware/staticCache.js'][173] = 0;
_$jscoverage['middleware/staticCache.js'][174] = 0;
_$jscoverage['middleware/staticCache.js'][175] = 0;
_$jscoverage['middleware/staticCache.js'][178] = 0;
_$jscoverage['middleware/staticCache.js'][181] = 0;
_$jscoverage['middleware/staticCache.js'][183] = 0;
_$jscoverage['middleware/staticCache.js'][186] = 0;
_$jscoverage['middleware/staticCache.js'][187] = 0;
_$jscoverage['middleware/staticCache.js'][200] = 0;
_$jscoverage['middleware/staticCache.js'][201] = 0;
_$jscoverage['middleware/staticCache.js'][206] = 0;
_$jscoverage['middleware/staticCache.js'][208] = 0;
_$jscoverage['middleware/staticCache.js'][210] = 0;
_$jscoverage['middleware/staticCache.js'][212] = 0;
_$jscoverage['middleware/staticCache.js'][214] = 0;
_$jscoverage['middleware/staticCache.js'][216] = 0;
_$jscoverage['middleware/staticCache.js'][229] = 0;
_$jscoverage['middleware/staticCache.js'][230] = 0;
}
_$jscoverage['middleware/staticCache.js'][12]++;
var utils = require("../utils"), Cache = require("../cache"), fresh = require("fresh");
_$jscoverage['middleware/staticCache.js'][51]++;
module.exports = (function staticCache(options) {
_$jscoverage['middleware/staticCache.js'][52]++;
var options = options || {}, cache = new Cache(options.maxObjects || 128), maxlen = options.maxLength || 262144;
_$jscoverage['middleware/staticCache.js'][56]++;
console.warn("connect.staticCache() is deprecated and will be removed in 3.0");
_$jscoverage['middleware/staticCache.js'][57]++;
console.warn("use varnish or similar reverse proxy caches.");
_$jscoverage['middleware/staticCache.js'][59]++;
return (function staticCache(req, res, next) {
_$jscoverage['middleware/staticCache.js'][60]++;
var key = cacheKey(req), ranges = req.headers.range, hasCookies = req.headers.cookie, hit = cache.get(key);
_$jscoverage['middleware/staticCache.js'][68]++;
req.on("static", (function (stream) {
_$jscoverage['middleware/staticCache.js'][69]++;
var headers = res._headers, cc = utils.parseCacheControl(headers["cache-control"] || ""), contentLength = headers["content-length"], hit;
_$jscoverage['middleware/staticCache.js'][75]++;
if (headers["set-cookie"]) {
_$jscoverage['middleware/staticCache.js'][75]++;
return hasCookies = true;
}
_$jscoverage['middleware/staticCache.js'][78]++;
if (hasCookies) {
_$jscoverage['middleware/staticCache.js'][78]++;
return;
}
_$jscoverage['middleware/staticCache.js'][81]++;
if (! contentLength || contentLength > maxlen) {
_$jscoverage['middleware/staticCache.js'][81]++;
return;
}
_$jscoverage['middleware/staticCache.js'][84]++;
if (headers["content-range"]) {
_$jscoverage['middleware/staticCache.js'][84]++;
return;
}
_$jscoverage['middleware/staticCache.js'][88]++;
if (cc["no-cache"] || cc["no-store"] || cc["private"] || cc["must-revalidate"]) {
_$jscoverage['middleware/staticCache.js'][91]++;
return;
}
_$jscoverage['middleware/staticCache.js'][94]++;
if (hit = cache.get(key)) {
_$jscoverage['middleware/staticCache.js'][95]++;
if (headers.etag == hit[0].etag) {
_$jscoverage['middleware/staticCache.js'][96]++;
hit[0].date = new Date();
_$jscoverage['middleware/staticCache.js'][97]++;
return;
}
else {
_$jscoverage['middleware/staticCache.js'][99]++;
cache.remove(key);
}
}
_$jscoverage['middleware/staticCache.js'][104]++;
if (null == stream) {
_$jscoverage['middleware/staticCache.js'][104]++;
return;
}
_$jscoverage['middleware/staticCache.js'][107]++;
var arr = [];
_$jscoverage['middleware/staticCache.js'][110]++;
stream.on("data", (function (chunk) {
_$jscoverage['middleware/staticCache.js'][111]++;
arr.push(chunk);
}));
_$jscoverage['middleware/staticCache.js'][115]++;
stream.on("end", (function () {
_$jscoverage['middleware/staticCache.js'][116]++;
var cacheEntry = cache.add(key);
_$jscoverage['middleware/staticCache.js'][117]++;
delete headers["x-cache"];
_$jscoverage['middleware/staticCache.js'][118]++;
cacheEntry.push(200);
_$jscoverage['middleware/staticCache.js'][119]++;
cacheEntry.push(headers);
_$jscoverage['middleware/staticCache.js'][120]++;
cacheEntry.push.apply(cacheEntry, arr);
}));
}));
_$jscoverage['middleware/staticCache.js'][124]++;
if (req.method == "GET" || req.method == "HEAD") {
_$jscoverage['middleware/staticCache.js'][125]++;
if (ranges) {
_$jscoverage['middleware/staticCache.js'][126]++;
next();
}
else {
_$jscoverage['middleware/staticCache.js'][127]++;
if (! hasCookies && hit && ! mustRevalidate(req, hit)) {
_$jscoverage['middleware/staticCache.js'][128]++;
res.setHeader("X-Cache", "HIT");
_$jscoverage['middleware/staticCache.js'][129]++;
respondFromCache(req, res, hit);
}
else {
_$jscoverage['middleware/staticCache.js'][131]++;
res.setHeader("X-Cache", "MISS");
_$jscoverage['middleware/staticCache.js'][132]++;
next();
}
}
}
else {
_$jscoverage['middleware/staticCache.js'][135]++;
next();
}
});
});
_$jscoverage['middleware/staticCache.js'][151]++;
function respondFromCache(req, res, cacheEntry) {
_$jscoverage['middleware/staticCache.js'][152]++;
var status = cacheEntry[0], headers = utils.merge({}, cacheEntry[1]), content = cacheEntry.slice(2);
_$jscoverage['middleware/staticCache.js'][156]++;
headers.age = (new Date() - new Date(headers.date)) / 1000 || 0;
_$jscoverage['middleware/staticCache.js'][158]++;
switch (req.method) {
case "HEAD":
_$jscoverage['middleware/staticCache.js'][160]++;
res.writeHead(status, headers);
_$jscoverage['middleware/staticCache.js'][161]++;
res.end();
_$jscoverage['middleware/staticCache.js'][162]++;
break;
case "GET":
_$jscoverage['middleware/staticCache.js'][164]++;
if (utils.conditionalGET(req) && fresh(req.headers, headers)) {
_$jscoverage['middleware/staticCache.js'][165]++;
headers["content-length"] = 0;
_$jscoverage['middleware/staticCache.js'][166]++;
res.writeHead(304, headers);
_$jscoverage['middleware/staticCache.js'][167]++;
res.end();
}
else {
_$jscoverage['middleware/staticCache.js'][169]++;
res.writeHead(status, headers);
_$jscoverage['middleware/staticCache.js'][171]++;
function write() {
_$jscoverage['middleware/staticCache.js'][172]++;
while (content.length) {
_$jscoverage['middleware/staticCache.js'][173]++;
if (false === res.write(content.shift())) {
_$jscoverage['middleware/staticCache.js'][174]++;
res.once("drain", write);
_$jscoverage['middleware/staticCache.js'][175]++;
return;
}
}
_$jscoverage['middleware/staticCache.js'][178]++;
res.end();
}
_$jscoverage['middleware/staticCache.js'][181]++;
write();
}
_$jscoverage['middleware/staticCache.js'][183]++;
break;
default:
_$jscoverage['middleware/staticCache.js'][186]++;
res.writeHead(500, "");
_$jscoverage['middleware/staticCache.js'][187]++;
res.end();
}
}
_$jscoverage['middleware/staticCache.js'][200]++;
function mustRevalidate(req, cacheEntry) {
_$jscoverage['middleware/staticCache.js'][201]++;
var cacheHeaders = cacheEntry[1], reqCC = utils.parseCacheControl(req.headers["cache-control"] || ""), cacheCC = utils.parseCacheControl(cacheHeaders["cache-control"] || ""), cacheAge = (new Date() - new Date(cacheHeaders.date)) / 1000 || 0;
_$jscoverage['middleware/staticCache.js'][206]++;
if (cacheCC["no-cache"] || cacheCC["must-revalidate"] || cacheCC["proxy-revalidate"]) {
_$jscoverage['middleware/staticCache.js'][208]++;
return true;
}
_$jscoverage['middleware/staticCache.js'][210]++;
if (reqCC["no-cache"]) {
_$jscoverage['middleware/staticCache.js'][210]++;
return true;
}
_$jscoverage['middleware/staticCache.js'][212]++;
if (null != reqCC["max-age"]) {
_$jscoverage['middleware/staticCache.js'][212]++;
return reqCC["max-age"] < cacheAge;
}
_$jscoverage['middleware/staticCache.js'][214]++;
if (null != cacheCC["max-age"]) {
_$jscoverage['middleware/staticCache.js'][214]++;
return cacheCC["max-age"] < cacheAge;
}
_$jscoverage['middleware/staticCache.js'][216]++;
return false;
}
_$jscoverage['middleware/staticCache.js'][229]++;
function cacheKey(req) {
_$jscoverage['middleware/staticCache.js'][230]++;
return utils.parseUrl(req).path;
}
_$jscoverage['middleware/staticCache.js'].source = ["","/*!"," * Connect - staticCache"," * Copyright(c) 2011 Sencha Inc."," * MIT Licensed"," */","","/**"," * Module dependencies."," */","","var utils = require('../utils')"," , Cache = require('../cache')"," , fresh = require('fresh');","","/**"," * Static cache:"," *"," * Enables a memory cache layer on top of"," * the `static()` middleware, serving popular"," * static files."," *"," * By default a maximum of 128 objects are"," * held in cache, with a max of 256k each,"," * totalling ~32mb."," *"," * A Least-Recently-Used (LRU) cache algo"," * is implemented through the `Cache` object,"," * simply rotating cache objects as they are"," * hit. This means that increasingly popular"," * objects maintain their positions while"," * others get shoved out of the stack and"," * garbage collected."," *"," * Benchmarks:"," *"," * static(): 2700 rps"," * node-static: 5300 rps"," * static() + staticCache(): 7500 rps"," *"," * Options:"," *"," * - `maxObjects` max cache objects [128]"," * - `maxLength` max cache object length 256kb"," *"," * @param {Object} options"," * @return {Function}"," * @api public"," */","","module.exports = function staticCache(options){"," var options = options || {}"," , cache = new Cache(options.maxObjects || 128)"," , maxlen = options.maxLength || 1024 * 256;",""," console.warn('connect.staticCache() is deprecated and will be removed in 3.0');"," console.warn('use varnish or similar reverse proxy caches.');",""," return function staticCache(req, res, next){"," var key = cacheKey(req)"," , ranges = req.headers.range"," , hasCookies = req.headers.cookie"," , hit = cache.get(key);",""," // cache static"," // TODO: change from staticCache() -&gt; cache()"," // and make this work for any request"," req.on('static', function(stream){"," var headers = res._headers"," , cc = utils.parseCacheControl(headers['cache-control'] || '')"," , contentLength = headers['content-length']"," , hit;",""," // dont cache set-cookie responses"," if (headers['set-cookie']) return hasCookies = true;",""," // dont cache when cookies are present"," if (hasCookies) return;",""," // ignore larger files"," if (!contentLength || contentLength &gt; maxlen) return;",""," // don't cache partial files"," if (headers['content-range']) return;",""," // dont cache items we shouldn't be"," // TODO: real support for must-revalidate / no-cache"," if ( cc['no-cache']"," || cc['no-store']"," || cc['private']"," || cc['must-revalidate']) return;",""," // if already in cache then validate"," if (hit = cache.get(key)){"," if (headers.etag == hit[0].etag) {"," hit[0].date = new Date;"," return;"," } else {"," cache.remove(key);"," }"," }",""," // validation notifiactions don't contain a steam"," if (null == stream) return;",""," // add the cache object"," var arr = [];",""," // store the chunks"," stream.on('data', function(chunk){"," arr.push(chunk);"," });",""," // flag it as complete"," stream.on('end', function(){"," var cacheEntry = cache.add(key);"," delete headers['x-cache']; // Clean up (TODO: others)"," cacheEntry.push(200);"," cacheEntry.push(headers);"," cacheEntry.push.apply(cacheEntry, arr);"," });"," });",""," if (req.method == 'GET' || req.method == 'HEAD') {"," if (ranges) {"," next();"," } else if (!hasCookies &amp;&amp; hit &amp;&amp; !mustRevalidate(req, hit)) {"," res.setHeader('X-Cache', 'HIT');"," respondFromCache(req, res, hit);"," } else {"," res.setHeader('X-Cache', 'MISS');"," next();"," }"," } else {"," next();"," }"," }","};","","/**"," * Respond with the provided cached value."," * TODO: Assume 200 code, that's iffy."," *"," * @param {Object} req"," * @param {Object} res"," * @param {Object} cacheEntry"," * @return {String}"," * @api private"," */","","function respondFromCache(req, res, cacheEntry) {"," var status = cacheEntry[0]"," , headers = utils.merge({}, cacheEntry[1])"," , content = cacheEntry.slice(2);",""," headers.age = (new Date - new Date(headers.date)) / 1000 || 0;",""," switch (req.method) {"," case 'HEAD':"," res.writeHead(status, headers);"," res.end();"," break;"," case 'GET':"," if (utils.conditionalGET(req) &amp;&amp; fresh(req.headers, headers)) {"," headers['content-length'] = 0;"," res.writeHead(304, headers);"," res.end();"," } else {"," res.writeHead(status, headers);",""," function write() {"," while (content.length) {"," if (false === res.write(content.shift())) {"," res.once('drain', write);"," return;"," }"," }"," res.end();"," }",""," write();"," }"," break;"," default:"," // This should never happen."," res.writeHead(500, '');"," res.end();"," }","}","","/**"," * Determine whether or not a cached value must be revalidated."," *"," * @param {Object} req"," * @param {Object} cacheEntry"," * @return {String}"," * @api private"," */","","function mustRevalidate(req, cacheEntry) {"," var cacheHeaders = cacheEntry[1]"," , reqCC = utils.parseCacheControl(req.headers['cache-control'] || '')"," , cacheCC = utils.parseCacheControl(cacheHeaders['cache-control'] || '')"," , cacheAge = (new Date - new Date(cacheHeaders.date)) / 1000 || 0;",""," if ( cacheCC['no-cache']"," || cacheCC['must-revalidate']"," || cacheCC['proxy-revalidate']) return true;",""," if (reqCC['no-cache']) return true;",""," if (null != reqCC['max-age']) return reqCC['max-age'] &lt; cacheAge;",""," if (null != cacheCC['max-age']) return cacheCC['max-age'] &lt; cacheAge;",""," return false;","}","","/**"," * The key to use in the cache. For now, this is the URL path and query."," *"," * 'http://example.com?key=value' -&gt; '/?key=value'"," *"," * @param {Object} req"," * @return {String}"," * @api private"," */","","function cacheKey(req) {"," return utils.parseUrl(req).path;","}"];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['middleware/timeout.js']) {
_$jscoverage['middleware/timeout.js'] = [];
_$jscoverage['middleware/timeout.js'][12] = 0;
_$jscoverage['middleware/timeout.js'][30] = 0;
_$jscoverage['middleware/timeout.js'][31] = 0;
_$jscoverage['middleware/timeout.js'][33] = 0;
_$jscoverage['middleware/timeout.js'][34] = 0;
_$jscoverage['middleware/timeout.js'][35] = 0;
_$jscoverage['middleware/timeout.js'][38] = 0;
_$jscoverage['middleware/timeout.js'][39] = 0;
_$jscoverage['middleware/timeout.js'][40] = 0;
_$jscoverage['middleware/timeout.js'][41] = 0;
_$jscoverage['middleware/timeout.js'][42] = 0;
_$jscoverage['middleware/timeout.js'][43] = 0;
_$jscoverage['middleware/timeout.js'][46] = 0;
_$jscoverage['middleware/timeout.js'][47] = 0;
_$jscoverage['middleware/timeout.js'][50] = 0;
_$jscoverage['middleware/timeout.js'][51] = 0;
_$jscoverage['middleware/timeout.js'][54] = 0;
}
_$jscoverage['middleware/timeout.js'][12]++;
var debug = require("debug")("connect:timeout");
_$jscoverage['middleware/timeout.js'][30]++;
module.exports = (function timeout(ms) {
_$jscoverage['middleware/timeout.js'][31]++;
ms = ms || 5000;
_$jscoverage['middleware/timeout.js'][33]++;
return (function (req, res, next) {
_$jscoverage['middleware/timeout.js'][34]++;
var id = setTimeout((function () {
_$jscoverage['middleware/timeout.js'][35]++;
req.emit("timeout", ms);
}), ms);
_$jscoverage['middleware/timeout.js'][38]++;
req.on("timeout", (function () {
_$jscoverage['middleware/timeout.js'][39]++;
if (req.headerSent) {
_$jscoverage['middleware/timeout.js'][39]++;
return debug("response started, cannot timeout");
}
_$jscoverage['middleware/timeout.js'][40]++;
var err = new Error("Request timeout");
_$jscoverage['middleware/timeout.js'][41]++;
err.timeout = ms;
_$jscoverage['middleware/timeout.js'][42]++;
err.status = 408;
_$jscoverage['middleware/timeout.js'][43]++;
next(err);
}));
_$jscoverage['middleware/timeout.js'][46]++;
req.clearTimeout = (function () {
_$jscoverage['middleware/timeout.js'][47]++;
clearTimeout(id);
});
_$jscoverage['middleware/timeout.js'][50]++;
res.on("header", (function () {
_$jscoverage['middleware/timeout.js'][51]++;
clearTimeout(id);
}));
_$jscoverage['middleware/timeout.js'][54]++;
next();
});
});
_$jscoverage['middleware/timeout.js'].source = ["","/*!"," * Connect - timeout"," * Ported from https://github.com/LearnBoost/connect-timeout"," * MIT Licensed"," */","","/**"," * Module dependencies."," */","","var debug = require('debug')('connect:timeout');","","/**"," * Timeout:"," *"," * Times out the request in `ms`, defaulting to `5000`. The"," * method `req.clearTimeout()` is added to revert this behaviour"," * programmatically within your application's middleware, routes, etc."," *"," * The timeout error is passed to `next()` so that you may customize"," * the response behaviour. This error has the `.timeout` property as"," * well as `.status == 408`."," *"," * @param {Number} ms"," * @return {Function}"," * @api public"," */","","module.exports = function timeout(ms) {"," ms = ms || 5000;",""," return function(req, res, next) {"," var id = setTimeout(function(){"," req.emit('timeout', ms);"," }, ms);",""," req.on('timeout', function(){"," if (req.headerSent) return debug('response started, cannot timeout');"," var err = new Error('Request timeout');"," err.timeout = ms;"," err.status = 408;"," next(err);"," });",""," req.clearTimeout = function(){"," clearTimeout(id);"," };",""," res.on('header', function(){"," clearTimeout(id);"," });",""," next();"," };","};"];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['middleware/urlencoded.js']) {
_$jscoverage['middleware/urlencoded.js'] = [];
_$jscoverage['middleware/urlencoded.js'][13] = 0;
_$jscoverage['middleware/urlencoded.js'][21] = 0;
_$jscoverage['middleware/urlencoded.js'][22] = 0;
_$jscoverage['middleware/urlencoded.js'][40] = 0;
_$jscoverage['middleware/urlencoded.js'][41] = 0;
_$jscoverage['middleware/urlencoded.js'][43] = 0;
_$jscoverage['middleware/urlencoded.js'][47] = 0;
_$jscoverage['middleware/urlencoded.js'][48] = 0;
_$jscoverage['middleware/urlencoded.js'][49] = 0;
_$jscoverage['middleware/urlencoded.js'][51] = 0;
_$jscoverage['middleware/urlencoded.js'][54] = 0;
_$jscoverage['middleware/urlencoded.js'][57] = 0;
_$jscoverage['middleware/urlencoded.js'][60] = 0;
_$jscoverage['middleware/urlencoded.js'][61] = 0;
_$jscoverage['middleware/urlencoded.js'][62] = 0;
_$jscoverage['middleware/urlencoded.js'][63] = 0;
_$jscoverage['middleware/urlencoded.js'][64] = 0;
_$jscoverage['middleware/urlencoded.js'][65] = 0;
_$jscoverage['middleware/urlencoded.js'][66] = 0;
_$jscoverage['middleware/urlencoded.js'][67] = 0;
_$jscoverage['middleware/urlencoded.js'][70] = 0;
_$jscoverage['middleware/urlencoded.js'][72] = 0;
_$jscoverage['middleware/urlencoded.js'][73] = 0;
}
_$jscoverage['middleware/urlencoded.js'][13]++;
var utils = require("../utils"), _limit = require("./limit"), qs = require("qs");
_$jscoverage['middleware/urlencoded.js'][21]++;
function noop(req, res, next) {
_$jscoverage['middleware/urlencoded.js'][22]++;
next();
}
_$jscoverage['middleware/urlencoded.js'][40]++;
exports = module.exports = (function (options) {
_$jscoverage['middleware/urlencoded.js'][41]++;
options = options || {};
_$jscoverage['middleware/urlencoded.js'][43]++;
var limit = options.limit? _limit(options.limit): noop;
_$jscoverage['middleware/urlencoded.js'][47]++;
return (function urlencoded(req, res, next) {
_$jscoverage['middleware/urlencoded.js'][48]++;
if (req._body) {
_$jscoverage['middleware/urlencoded.js'][48]++;
return next();
}
_$jscoverage['middleware/urlencoded.js'][49]++;
req.body = req.body || {};
_$jscoverage['middleware/urlencoded.js'][51]++;
if (! utils.hasBody(req)) {
_$jscoverage['middleware/urlencoded.js'][51]++;
return next();
}
_$jscoverage['middleware/urlencoded.js'][54]++;
if ("application/x-www-form-urlencoded" != utils.mime(req)) {
_$jscoverage['middleware/urlencoded.js'][54]++;
return next();
}
_$jscoverage['middleware/urlencoded.js'][57]++;
req._body = true;
_$jscoverage['middleware/urlencoded.js'][60]++;
limit(req, res, (function (err) {
_$jscoverage['middleware/urlencoded.js'][61]++;
if (err) {
_$jscoverage['middleware/urlencoded.js'][61]++;
return next(err);
}
_$jscoverage['middleware/urlencoded.js'][62]++;
var buf = "";
_$jscoverage['middleware/urlencoded.js'][63]++;
req.setEncoding("utf8");
_$jscoverage['middleware/urlencoded.js'][64]++;
req.on("data", (function (chunk) {
_$jscoverage['middleware/urlencoded.js'][64]++;
buf += chunk;
}));
_$jscoverage['middleware/urlencoded.js'][65]++;
req.on("end", (function () {
_$jscoverage['middleware/urlencoded.js'][66]++;
try {
_$jscoverage['middleware/urlencoded.js'][67]++;
req.body = buf.length? qs.parse(buf, options): {};
_$jscoverage['middleware/urlencoded.js'][70]++;
next();
}
catch (err) {
_$jscoverage['middleware/urlencoded.js'][72]++;
err.body = buf;
_$jscoverage['middleware/urlencoded.js'][73]++;
next(err);
}
}));
}));
});
});
_$jscoverage['middleware/urlencoded.js'].source = ["","/*!"," * Connect - urlencoded"," * Copyright(c) 2010 Sencha Inc."," * Copyright(c) 2011 TJ Holowaychuk"," * MIT Licensed"," */","","/**"," * Module dependencies."," */","","var utils = require('../utils')"," , _limit = require('./limit')"," , qs = require('qs');","","/**"," * noop middleware."," */","","function noop(req, res, next) {"," next();","}","","/**"," * Urlencoded:"," * "," * Parse x-ww-form-urlencoded request bodies,"," * providing the parsed object as `req.body`."," *"," * Options:"," *"," * - `limit` byte limit disabled by default"," *"," * @param {Object} options"," * @return {Function}"," * @api public"," */","","exports = module.exports = function(options){"," options = options || {};",""," var limit = options.limit"," ? _limit(options.limit)"," : noop;",""," return function urlencoded(req, res, next) {"," if (req._body) return next();"," req.body = req.body || {};",""," if (!utils.hasBody(req)) return next();",""," // check Content-Type"," if ('application/x-www-form-urlencoded' != utils.mime(req)) return next();",""," // flag as parsed"," req._body = true;",""," // parse"," limit(req, res, function(err){"," if (err) return next(err);"," var buf = '';"," req.setEncoding('utf8');"," req.on('data', function(chunk){ buf += chunk });"," req.on('end', function(){"," try {"," req.body = buf.length"," ? qs.parse(buf, options)"," : {};"," next();"," } catch (err){"," err.body = buf;"," next(err);"," }"," });"," });"," }","};"];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['middleware/vhost.js']) {
_$jscoverage['middleware/vhost.js'] = [];
_$jscoverage['middleware/vhost.js'][28] = 0;
_$jscoverage['middleware/vhost.js'][29] = 0;
_$jscoverage['middleware/vhost.js'][30] = 0;
_$jscoverage['middleware/vhost.js'][31] = 0;
_$jscoverage['middleware/vhost.js'][32] = 0;
_$jscoverage['middleware/vhost.js'][33] = 0;
_$jscoverage['middleware/vhost.js'][34] = 0;
_$jscoverage['middleware/vhost.js'][35] = 0;
_$jscoverage['middleware/vhost.js'][36] = 0;
_$jscoverage['middleware/vhost.js'][37] = 0;
_$jscoverage['middleware/vhost.js'][38] = 0;
}
_$jscoverage['middleware/vhost.js'][28]++;
module.exports = (function vhost(hostname, server) {
_$jscoverage['middleware/vhost.js'][29]++;
if (! hostname) {
_$jscoverage['middleware/vhost.js'][29]++;
throw new Error("vhost hostname required");
}
_$jscoverage['middleware/vhost.js'][30]++;
if (! server) {
_$jscoverage['middleware/vhost.js'][30]++;
throw new Error("vhost server required");
}
_$jscoverage['middleware/vhost.js'][31]++;
var regexp = new RegExp("^" + hostname.replace(/[*]/g, "(.*?)") + "$", "i");
_$jscoverage['middleware/vhost.js'][32]++;
if (server.onvhost) {
_$jscoverage['middleware/vhost.js'][32]++;
server.onvhost(hostname);
}
_$jscoverage['middleware/vhost.js'][33]++;
return (function vhost(req, res, next) {
_$jscoverage['middleware/vhost.js'][34]++;
if (! req.headers.host) {
_$jscoverage['middleware/vhost.js'][34]++;
return next();
}
_$jscoverage['middleware/vhost.js'][35]++;
var host = req.headers.host.split(":")[0];
_$jscoverage['middleware/vhost.js'][36]++;
if (! regexp.test(host)) {
_$jscoverage['middleware/vhost.js'][36]++;
return next();
}
_$jscoverage['middleware/vhost.js'][37]++;
if ("function" == typeof server) {
_$jscoverage['middleware/vhost.js'][37]++;
return server(req, res, next);
}
_$jscoverage['middleware/vhost.js'][38]++;
server.emit("request", req, res);
});
});
_$jscoverage['middleware/vhost.js'].source = ["","/*!"," * Connect - vhost"," * Copyright(c) 2010 Sencha Inc."," * Copyright(c) 2011 TJ Holowaychuk"," * MIT Licensed"," */","","/**"," * Vhost:"," * "," * Setup vhost for the given `hostname` and `server`."," *"," * connect()"," * .use(connect.vhost('foo.com', fooApp))"," * .use(connect.vhost('bar.com', barApp))"," * .use(connect.vhost('*.com', mainApp))"," *"," * The `server` may be a Connect server or"," * a regular Node `http.Server`. "," *"," * @param {String} hostname"," * @param {Server} server"," * @return {Function}"," * @api public"," */","","module.exports = function vhost(hostname, server){"," if (!hostname) throw new Error('vhost hostname required');"," if (!server) throw new Error('vhost server required');"," var regexp = new RegExp('^' + hostname.replace(/[*]/g, '(.*?)') + '$', 'i');"," if (server.onvhost) server.onvhost(hostname);"," return function vhost(req, res, next){"," if (!req.headers.host) return next();"," var host = req.headers.host.split(':')[0];"," if (!regexp.test(host)) return next();"," if ('function' == typeof server) return server(req, res, next);"," server.emit('request', req, res);"," };","};"];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['patch.js']) {
_$jscoverage['patch.js'] = [];
_$jscoverage['patch.js'][12] = 0;
_$jscoverage['patch.js'][20] = 0;
_$jscoverage['patch.js'][30] = 0;
_$jscoverage['patch.js'][31] = 0;
_$jscoverage['patch.js'][43] = 0;
_$jscoverage['patch.js'][44] = 0;
_$jscoverage['patch.js'][48] = 0;
_$jscoverage['patch.js'][49] = 0;
_$jscoverage['patch.js'][50] = 0;
_$jscoverage['patch.js'][55] = 0;
_$jscoverage['patch.js'][56] = 0;
_$jscoverage['patch.js'][59] = 0;
_$jscoverage['patch.js'][66] = 0;
_$jscoverage['patch.js'][67] = 0;
_$jscoverage['patch.js'][68] = 0;
_$jscoverage['patch.js'][69] = 0;
_$jscoverage['patch.js'][72] = 0;
_$jscoverage['patch.js'][73] = 0;
_$jscoverage['patch.js'][74] = 0;
_$jscoverage['patch.js'][75] = 0;
_$jscoverage['patch.js'][78] = 0;
}
_$jscoverage['patch.js'][12]++;
var http = require("http"), res = http.ServerResponse.prototype, setHeader = res.setHeader, _renderHeaders = res._renderHeaders, writeHead = res.writeHead;
_$jscoverage['patch.js'][20]++;
if (! res._hasConnectPatch) {
_$jscoverage['patch.js'][30]++;
res.__defineGetter__("headerSent", (function () {
_$jscoverage['patch.js'][31]++;
return this._header;
}));
_$jscoverage['patch.js'][43]++;
res.setHeader = (function (field, val) {
_$jscoverage['patch.js'][44]++;
var key = field.toLowerCase(), prev;
_$jscoverage['patch.js'][48]++;
if (this._headers && "set-cookie" == key) {
_$jscoverage['patch.js'][49]++;
if (prev = this.getHeader(field)) {
_$jscoverage['patch.js'][50]++;
val = Array.isArray(prev)? prev.concat(val): [prev, val];
}
}
else {
_$jscoverage['patch.js'][55]++;
if ("content-type" == key && this.charset) {
_$jscoverage['patch.js'][56]++;
val += "; charset=" + this.charset;
}
}
_$jscoverage['patch.js'][59]++;
return setHeader.call(this, field, val);
});
_$jscoverage['patch.js'][66]++;
res._renderHeaders = (function () {
_$jscoverage['patch.js'][67]++;
if (! this._emittedHeader) {
_$jscoverage['patch.js'][67]++;
this.emit("header");
}
_$jscoverage['patch.js'][68]++;
this._emittedHeader = true;
_$jscoverage['patch.js'][69]++;
return _renderHeaders.call(this);
});
_$jscoverage['patch.js'][72]++;
res.writeHead = (function () {
_$jscoverage['patch.js'][73]++;
if (! this._emittedHeader) {
_$jscoverage['patch.js'][73]++;
this.emit("header");
}
_$jscoverage['patch.js'][74]++;
this._emittedHeader = true;
_$jscoverage['patch.js'][75]++;
return writeHead.apply(this, arguments);
});
_$jscoverage['patch.js'][78]++;
res._hasConnectPatch = true;
}
_$jscoverage['patch.js'].source = ["","/*!"," * Connect"," * Copyright(c) 2011 TJ Holowaychuk"," * MIT Licensed"," */","","/**"," * Module dependencies."," */","","var http = require('http')"," , res = http.ServerResponse.prototype"," , setHeader = res.setHeader"," , _renderHeaders = res._renderHeaders"," , writeHead = res.writeHead;","","// apply only once","","if (!res._hasConnectPatch) {",""," /**"," * Provide a public \"header sent\" flag"," * until node does."," *"," * @return {Boolean}"," * @api public"," */",""," res.__defineGetter__('headerSent', function(){"," return this._header;"," });",""," /**"," * Set header `field` to `val`, special-casing"," * the `Set-Cookie` field for multiple support."," *"," * @param {String} field"," * @param {String} val"," * @api public"," */",""," res.setHeader = function(field, val){"," var key = field.toLowerCase()"," , prev;",""," // special-case Set-Cookie"," if (this._headers &amp;&amp; 'set-cookie' == key) {"," if (prev = this.getHeader(field)) {"," val = Array.isArray(prev)"," ? prev.concat(val)"," : [prev, val];"," }"," // charset"," } else if ('content-type' == key &amp;&amp; this.charset) {"," val += '; charset=' + this.charset;"," }",""," return setHeader.call(this, field, val);"," };",""," /**"," * Proxy to emit \"header\" event."," */",""," res._renderHeaders = function(){"," if (!this._emittedHeader) this.emit('header');"," this._emittedHeader = true;"," return _renderHeaders.call(this);"," };",""," res.writeHead = function(){"," if (!this._emittedHeader) this.emit('header');"," this._emittedHeader = true;"," return writeHead.apply(this, arguments);"," };",""," res._hasConnectPatch = true;","}"];
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['proto.js']) {
_$jscoverage['proto.js'] = [];
_$jscoverage['proto.js'][13] = 0;
_$jscoverage['proto.js'][19] = 0;
_$jscoverage['proto.js'][23] = 0;
_$jscoverage['proto.js'][62] = 0;
_$jscoverage['proto.js'][64] = 0;
_$jscoverage['proto.js'][65] = 0;
_$jscoverage['proto.js'][66] = 0;
_$jscoverage['proto.js'][70] = 0;
_$jscoverage['proto.js'][71] = 0;
_$jscoverage['proto.js'][72] = 0;
_$jscoverage['proto.js'][73] = 0;
_$jscoverage['proto.js'][74] = 0;
_$jscoverage['proto.js'][79] = 0;
_$jscoverage['proto.js'][80] = 0;
_$jscoverage['proto.js'][84] = 0;
_$jscoverage['proto.js'][85] = 0;
_$jscoverage['proto.js'][89] = 0;
_$jscoverage['proto.js'][90] = 0;
_$jscoverage['proto.js'][92] = 0;
_$jscoverage['proto.js'][102] = 0;
_$jscoverage['proto.js'][103] = 0;
_$jscoverage['proto.js'][109] = 0;
_$jscoverage['proto.js'][110] = 0;
_$jscoverage['proto.js'][112] = 0;
_$jscoverage['proto.js'][113] = 0;
_$jscoverage['proto.js'][114] = 0;
_$jscoverage['proto.js'][117] = 0;
_$jscoverage['proto.js'][118] = 0;
_$jscoverage['proto.js'][119] = 0;
_$jscoverage['proto.js'][122] = 0;
_$jscoverage['proto.js'][125] = 0;
_$jscoverage['proto.js'][127] = 0;
_$jscoverage['proto.js'][130] = 0;
_$jscoverage['proto.js'][132] = 0;
_$jscoverage['proto.js'][133] = 0;
_$jscoverage['proto.js'][136] = 0;
_$jscoverage['proto.js'][139] = 0;
_$jscoverage['proto.js'][144] = 0;
_$jscoverage['proto.js'][145] = 0;
_$jscoverage['proto.js'][146] = 0;
_$jscoverage['proto.js'][147] = 0;
_$jscoverage['proto.js'][148] = 0;
_$jscoverage['proto.js'][149] = 0;
_$jscoverage['proto.js'][151] = 0;
_$jscoverage['proto.js'][152] = 0;
_$jscoverage['proto.js'][153] = 0;
_$jscoverage['proto.js'][154] = 0;
_$jscoverage['proto.js'][155] = 0;
_$jscoverage['proto.js'][157] = 0;
_$jscoverage['proto.js'][160] = 0;
_$jscoverage['proto.js'][161] = 0;
_$jscoverage['proto.js'][162] = 0;
_$jscoverage['proto.js'][165] = 0;
_$jscoverage['proto.js'][167] = 0;
_$jscoverage['proto.js'][168] = 0;
_$jscoverage['proto.js'][172] = 0;
_$jscoverage['proto.js'][173] = 0;
_$jscoverage['proto.js'][176] = 0;
_$jscoverage['proto.js'][177] = 0;
_$jscoverage['proto.js'][178] = 0;
_$jscoverage['proto.js'][181] = 0;
_$jscoverage['proto.js'][182] = 0;
_$jscoverage['proto.js'][183] = 0;
_$jscoverage['proto.js'][184] = 0;
_$jscoverage['proto.js'][185] = 0;
_$jscoverage['proto.js'][187] = 0;
_$jscoverage['proto.js'][189] = 0;
_$jscoverage['proto.js'][190] = 0;
_$jscoverage['proto.js'][192] = 0;
_$jscoverage['proto.js'][195] = 0;
_$jscoverage['proto.js'][198] = 0;
_$jscoverage['proto.js'][227] = 0;
_$jscoverage['proto.js'][228] = 0;
_$jscoverage['proto.js'][229] = 0;
}
_$jscoverage['proto.js'][13]++;
var http = require("http"), utils = require("./utils"), debug = require("debug")("connect:dispatcher");
_$jscoverage['proto.js'][19]++;
var app = module.exports = {};
_$jscoverage['proto.js'][23]++;
var env = process.env.NODE_ENV || "development";
_$jscoverage['proto.js'][62]++;
app.use = (function (route, fn) {
_$jscoverage['proto.js'][64]++;
if ("string" != typeof route) {
_$jscoverage['proto.js'][65]++;
fn = route;
_$jscoverage['proto.js'][66]++;
route = "/";
}
_$jscoverage['proto.js'][70]++;
if ("function" == typeof fn.handle) {
_$jscoverage['proto.js'][71]++;
var server = fn;
_$jscoverage['proto.js'][72]++;
fn.route = route;
_$jscoverage['proto.js'][73]++;
fn = (function (req, res, next) {
_$jscoverage['proto.js'][74]++;
server.handle(req, res, next);
});
}
_$jscoverage['proto.js'][79]++;
if (fn instanceof http.Server) {
_$jscoverage['proto.js'][80]++;
fn = fn.listeners("request")[0];
}
_$jscoverage['proto.js'][84]++;
if ("/" == route[route.length - 1]) {
_$jscoverage['proto.js'][85]++;
route = route.slice(0, -1);
}
_$jscoverage['proto.js'][89]++;
debug("use %s %s", route || "/", fn.name || "anonymous");
_$jscoverage['proto.js'][90]++;
this.stack.push({route: route, handle: fn});
_$jscoverage['proto.js'][92]++;
return this;
});
_$jscoverage['proto.js'][102]++;
app.handle = (function (req, res, out) {
_$jscoverage['proto.js'][103]++;
var stack = this.stack, fqdn = ~ req.url.indexOf("://"), removed = "", slashAdded = false, index = 0;
_$jscoverage['proto.js'][109]++;
function next(err) {
_$jscoverage['proto.js'][110]++;
var layer, path, status, c;
_$jscoverage['proto.js'][112]++;
if (slashAdded) {
_$jscoverage['proto.js'][113]++;
req.url = req.url.substr(1);
_$jscoverage['proto.js'][114]++;
slashAdded = false;
}
_$jscoverage['proto.js'][117]++;
req.url = removed + req.url;
_$jscoverage['proto.js'][118]++;
req.originalUrl = req.originalUrl || req.url;
_$jscoverage['proto.js'][119]++;
removed = "";
_$jscoverage['proto.js'][122]++;
layer = stack[index++];
_$jscoverage['proto.js'][125]++;
if (! layer || res.headerSent) {
_$jscoverage['proto.js'][127]++;
if (out) {
_$jscoverage['proto.js'][127]++;
return out(err);
}
_$jscoverage['proto.js'][130]++;
if (err) {
_$jscoverage['proto.js'][132]++;
if (res.statusCode < 400) {
_$jscoverage['proto.js'][132]++;
res.statusCode = 500;
}
_$jscoverage['proto.js'][133]++;
debug("default %s", res.statusCode);
_$jscoverage['proto.js'][136]++;
if (err.status) {
_$jscoverage['proto.js'][136]++;
res.statusCode = err.status;
}
_$jscoverage['proto.js'][139]++;
var msg = "production" == env? http.STATUS_CODES[res.statusCode]: err.stack || err.toString();
_$jscoverage['proto.js'][144]++;
if ("test" != env) {
_$jscoverage['proto.js'][144]++;
console.error(err.stack || err.toString());
}
_$jscoverage['proto.js'][145]++;
if (res.headerSent) {
_$jscoverage['proto.js'][145]++;
return req.socket.destroy();
}
_$jscoverage['proto.js'][146]++;
res.setHeader("Content-Type", "text/plain");
_$jscoverage['proto.js'][147]++;
res.setHeader("Content-Length", Buffer.byteLength(msg));
_$jscoverage['proto.js'][148]++;
if ("HEAD" == req.method) {
_$jscoverage['proto.js'][148]++;
return res.end();
}
_$jscoverage['proto.js'][149]++;
res.end(msg);
}
else {
_$jscoverage['proto.js'][151]++;
debug("default 404");
_$jscoverage['proto.js'][152]++;
res.statusCode = 404;
_$jscoverage['proto.js'][153]++;
res.setHeader("Content-Type", "text/plain");
_$jscoverage['proto.js'][154]++;
if ("HEAD" == req.method) {
_$jscoverage['proto.js'][154]++;
return res.end();
}
_$jscoverage['proto.js'][155]++;
res.end("Cannot " + req.method + " " + utils.escape(req.originalUrl));
}
_$jscoverage['proto.js'][157]++;
return;
}
_$jscoverage['proto.js'][160]++;
try {
_$jscoverage['proto.js'][161]++;
path = utils.parseUrl(req).pathname;
_$jscoverage['proto.js'][162]++;
if (undefined == path) {
_$jscoverage['proto.js'][162]++;
path = "/";
}
_$jscoverage['proto.js'][165]++;
if (0 != path.toLowerCase().indexOf(layer.route.toLowerCase())) {
_$jscoverage['proto.js'][165]++;
return next(err);
}
_$jscoverage['proto.js'][167]++;
c = path[layer.route.length];
_$jscoverage['proto.js'][168]++;
if (c && "/" != c && "." != c) {
_$jscoverage['proto.js'][168]++;
return next(err);
}
_$jscoverage['proto.js'][172]++;
removed = layer.route;
_$jscoverage['proto.js'][173]++;
req.url = req.url.substr(removed.length);
_$jscoverage['proto.js'][176]++;
if (! fqdn && "/" != req.url[0]) {
_$jscoverage['proto.js'][177]++;
req.url = "/" + req.url;
_$jscoverage['proto.js'][178]++;
slashAdded = true;
}
_$jscoverage['proto.js'][181]++;
debug("%s", layer.handle.name || "anonymous");
_$jscoverage['proto.js'][182]++;
var arity = layer.handle.length;
_$jscoverage['proto.js'][183]++;
if (err) {
_$jscoverage['proto.js'][184]++;
if (arity === 4) {
_$jscoverage['proto.js'][185]++;
layer.handle(err, req, res, next);
}
else {
_$jscoverage['proto.js'][187]++;
next(err);
}
}
else {
_$jscoverage['proto.js'][189]++;
if (arity < 4) {
_$jscoverage['proto.js'][190]++;
layer.handle(req, res, next);
}
else {
_$jscoverage['proto.js'][192]++;
next();
}
}
}
catch (e) {
_$jscoverage['proto.js'][195]++;
next(e);
}
}
_$jscoverage['proto.js'][198]++;
next();
});
_$jscoverage['proto.js'][227]++;
app.listen = (function () {
_$jscoverage['proto.js'][228]++;
var server = http.createServer(this);
_$jscoverage['proto.js'][229]++;
return server.listen.apply(server, arguments);
});
_$jscoverage['proto.js'].source = ["","/*!"," * Connect - HTTPServer"," * Copyright(c) 2010 Sencha Inc."," * Copyright(c) 2011 TJ Holowaychuk"," * MIT Licensed"," */","","/**"," * Module dependencies."," */","","var http = require('http')"," , utils = require('./utils')"," , debug = require('debug')('connect:dispatcher');","","// prototype","","var app = module.exports = {};","","// environment","","var env = process.env.NODE_ENV || 'development';","","/**"," * Utilize the given middleware `handle` to the given `route`,"," * defaulting to _/_. This \"route\" is the mount-point for the"," * middleware, when given a value other than _/_ the middleware"," * is only effective when that segment is present in the request's"," * pathname."," *"," * For example if we were to mount a function at _/admin_, it would"," * be invoked on _/admin_, and _/admin/settings_, however it would"," * not be invoked for _/_, or _/posts_."," *"," * Examples:"," *"," * var app = connect();"," * app.use(connect.favicon());"," * app.use(connect.logger());"," * app.use(connect.static(__dirname + '/public'));"," *"," * If we wanted to prefix static files with _/public_, we could"," * \"mount\" the `static()` middleware:"," *"," * app.use('/public', connect.static(__dirname + '/public'));"," *"," * This api is chainable, so the following is valid:"," *"," * connect()"," * .use(connect.favicon())"," * .use(connect.logger())"," * .use(connect.static(__dirname + '/public'))"," * .listen(3000);"," *"," * @param {String|Function|Server} route, callback or server"," * @param {Function|Server} callback or server"," * @return {Server} for chaining"," * @api public"," */","","app.use = function(route, fn){"," // default route to '/'"," if ('string' != typeof route) {"," fn = route;"," route = '/';"," }",""," // wrap sub-apps"," if ('function' == typeof fn.handle) {"," var server = fn;"," fn.route = route;"," fn = function(req, res, next){"," server.handle(req, res, next);"," };"," }",""," // wrap vanilla http.Servers"," if (fn instanceof http.Server) {"," fn = fn.listeners('request')[0];"," }",""," // strip trailing slash"," if ('/' == route[route.length - 1]) {"," route = route.slice(0, -1);"," }",""," // add the middleware"," debug('use %s %s', route || '/', fn.name || 'anonymous');"," this.stack.push({ route: route, handle: fn });",""," return this;","};","","/**"," * Handle server requests, punting them down"," * the middleware stack."," *"," * @api private"," */","","app.handle = function(req, res, out) {"," var stack = this.stack"," , fqdn = ~req.url.indexOf('://')"," , removed = ''"," , slashAdded = false"," , index = 0;",""," function next(err) {"," var layer, path, status, c;",""," if (slashAdded) {"," req.url = req.url.substr(1);"," slashAdded = false;"," }",""," req.url = removed + req.url;"," req.originalUrl = req.originalUrl || req.url;"," removed = '';",""," // next callback"," layer = stack[index++];",""," // all done"," if (!layer || res.headerSent) {"," // delegate to parent"," if (out) return out(err);",""," // unhandled error"," if (err) {"," // default to 500"," if (res.statusCode &lt; 400) res.statusCode = 500;"," debug('default %s', res.statusCode);",""," // respect err.status"," if (err.status) res.statusCode = err.status;",""," // production gets a basic error message"," var msg = 'production' == env"," ? http.STATUS_CODES[res.statusCode]"," : err.stack || err.toString();",""," // log to stderr in a non-test env"," if ('test' != env) console.error(err.stack || err.toString());"," if (res.headerSent) return req.socket.destroy();"," res.setHeader('Content-Type', 'text/plain');"," res.setHeader('Content-Length', Buffer.byteLength(msg));"," if ('HEAD' == req.method) return res.end();"," res.end(msg);"," } else {"," debug('default 404');"," res.statusCode = 404;"," res.setHeader('Content-Type', 'text/plain');"," if ('HEAD' == req.method) return res.end();"," res.end('Cannot ' + req.method + ' ' + utils.escape(req.originalUrl));"," }"," return;"," }",""," try {"," path = utils.parseUrl(req).pathname;"," if (undefined == path) path = '/';",""," // skip this layer if the route doesn't match."," if (0 != path.toLowerCase().indexOf(layer.route.toLowerCase())) return next(err);",""," c = path[layer.route.length];"," if (c &amp;&amp; '/' != c &amp;&amp; '.' != c) return next(err);",""," // Call the layer handler"," // Trim off the part of the url that matches the route"," removed = layer.route;"," req.url = req.url.substr(removed.length);",""," // Ensure leading slash"," if (!fqdn &amp;&amp; '/' != req.url[0]) {"," req.url = '/' + req.url;"," slashAdded = true;"," }",""," debug('%s', layer.handle.name || 'anonymous');"," var arity = layer.handle.length;"," if (err) {"," if (arity === 4) {"," layer.handle(err, req, res, next);"," } else {"," next(err);"," }"," } else if (arity &lt; 4) {"," layer.handle(req, res, next);"," } else {"," next();"," }"," } catch (e) {"," next(e);"," }"," }"," next();","};","","/**"," * Listen for connections."," *"," * This method takes the same arguments"," * as node's `http.Server#listen()`. "," *"," * HTTP and HTTPS:"," *"," * If you run your application both as HTTP"," * and HTTPS you may wrap them individually,"," * since your Connect \"server\" is really just"," * a JavaScript `Function`."," *"," * var connect = require('connect')"," * , http = require('http')"," * , https = require('https');"," * "," * var app = connect();"," * "," * http.createServer(app).listen(80);"," * https.createServer(options, app).listen(443);"," *"," * @return {http.Server}"," * @api public"," */","","app.listen = function(){"," var server = http.createServer(this);"," return server.listen.apply(server, arguments);","};"];
<html>
<head>
<title>listing directory {directory}</title>
<style>{style}</style>
<script>
function $(id){
var el = 'string' == typeof id
? document.getElementById(id)
: id;
el.on = function(event, fn){
if ('content loaded' == event) event = 'DOMContentLoaded';
el.addEventListener(event, fn, false);
};
el.all = function(selector){
return $(el.querySelectorAll(selector));
};
el.each = function(fn){
for (var i = 0, len = el.length; i < len; ++i) {
fn($(el[i]), i);
}
};
el.getClasses = function(){
return this.getAttribute('class').split(/\s+/);
};
el.addClass = function(name){
var classes = this.getAttribute('class');
el.setAttribute('class', classes
? classes + ' ' + name
: name);
};
el.removeClass = function(name){
var classes = this.getClasses().filter(function(curr){
return curr != name;
});
this.setAttribute('class', classes);
};
return el;
}
function search() {
var str = $('search').value
, links = $('files').all('a');
links.each(function(link){
var text = link.textContent;
if ('..' == text) return;
if (str.length && ~text.indexOf(str)) {
link.addClass('highlight');
} else {
link.removeClass('highlight');
}
});
}
$(window).on('content loaded', function(){
$('search').on('keyup', search);
});
</script>
</head>
<body class="directory">
<input id="search" type="text" placeholder="Search" autocomplete="off" />
<div id="wrapper">
<h1>{linked-path}</h1>
{files}
</div>
</body>
</html>
<html>
<head>
<title>{error}</title>
<style>{style}</style>
</head>
<body>
<div id="wrapper">
<h1>{title}</h1>
<h2><em>{statusCode}</em> {error}</h2>
<ul id="stacktrace">{stack}</ul>
</div>
</body>
</html>
h( ��}@�_�U�C˩��~�6�G�����c�c�<�e�p›l�u4�ơu 
 
     
 
��������������������
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e< IDAT����s���>�{��SG��3�;1Ј���.��bc#61�l��I��AKD"$�X$ �TD�y����UI��ޥ�w�O�6�9�D�B����כ��Y�}���o*��>���'o�{t�:& ���ﱋ����oG�����g��p�fS=�3Og~�jUiִe�[ǫ����;�k�ҏ�x��O���T��$��4ls1 ������w���}�؝��>��``�ʨ2��*c*��u˽��=v���̝���*� �D)��ke���������{���O�y,0CB0��(�4�;�.ݓ�3�*J �4� PC�%# 0C/$4
I��2O!E��6k3tGB��T����%`��YC��am�)6Ӱl0C/щ���*�ER4���\�g��� ˲ZW�7��{谆��$$|u����̰u/�ٮ�+���Jt�(��<W/k/0�������t׻�o�� ���� awS��f�֥�� U��ŷ/�RUODNA8��o��"�D8V5�jIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<uIDAT�M��U��=ߙ;�c�YA!Y؟H*FE�n�Z�)�����U��-K���T�r��Ybj?��D�V�N)��{���<��������f&�*a=� �A6��~[<�_�^:�g� 2Ӷ׏�����ʤ�dB:{i���������:�g�T(]�>��ʅt%� }6�q�2�=����V}��.�vDžw}z�᷶/���� �b�P����fvf`džY��:���L�I@A J��D(JΜ���#w�
�o�^7�=  ��BFh}RB�dq�\��ֆX=)jC�L5��QB ��Z�BP!�A�D6&:@ч,�!���d��LP
Z�]�A�B��P����$)H ��~b�Ԝ��/�G���&�F�d�HВ��:}�so��UkZ����q��7+�qj�^�a(�d��4��'�?�/��g�:x�#�m���;+�ǽ�gvf�}7-�>h�gߞ1+<��Y��#�;��*��Z���^|�g�EJZr�ҿN��G��u�7<c����FW�� /�Ngf�4��˪}��9��6ߵ�܉�Q��0��i�΃;ǣ|<"�M�@�Hi����P�*}k�����'!1f����IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT�K��e���7�{'�P�eD�IF��a&F Q�D�jE���t1�27� !#($o�ٽ ��0�2-%Ǚ��Ή�t�{�O�=T�LB�@Yu�;{:?��<�w˪q��L+7���� �ӓF� ����:��_.����G.۷e�Eh�4q�`�L��M� �J?��K&�^7ͭsZ���)Y�Y��{�~���"b(3���(�ASh��@5cxЪ�3̾�7���H
JP"�%B�P�p�� f M����m�k���d�6��j?)�m���i�vj��hK-d�h�H)%��Ma�RC��T�ZHTDB"���E�C�T� �P;2�d&(5�M������� ���̜���n��{
Ԛ2�$3H �SǏڻs���{��M�]�a����B��O�R$�ɯ?��7͛��������1�=y��` �K5�s�� ��A��_���vݬEvM_��uk<��j�G�ߺnv ]���3cx��+�����ߏ�j�V?M���8��
���'�#�X;��+O�.��՚�}FN����w��m�⯟=�l�[V���w��yk�ȶ�&��6W<s����,������Ο;���=v���׷�ɽ�s�"��O�7"nN9 l4s��^��;�w�[�侱Z����I�? ��NIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT=�Kh�e��������%��!5������ Jt!�dcA�������.7�t�BJp�Ľ A7�Q�X���`�X i�ƙI����s����w���wN��fU8
��Kp#������d�~j��L�]��t=����7�N�ʐC��;���[�\������K#ߟ�iEz4Ƚy C�Tܠp#%g�S����ND~��������_+="���!J��BEc| g��8��+ǁ�J��l�T@EPTA����6w�w�oDx��;Yx1�c(-4iΩ�F��\��`v�F B��� �m �6O��C�&e�C^�<f��@E A� g�6i��,(}y��Jy�� �>�����UW&��k�Q��##�'�d�QP)��?�Y�m�,*y�E�w���}�PZ�wx�H��Zā�r|��Z31^���B��B JaP����.��vF���b��Fwg�V�_� E叵6O�W�T�*J�P$G/}2���R}��u+��Ͼ�Fa0�p�jI������OL ��98�%���tM�����;��n��rx���lބ���h.t��q��sϼ���1K�7���/�S��]��98���������IDzR�,�y�@~\)0q���\5!F�TX��tv��jF�~�]uw���m��r�r&�`Y��E�qw�����d�� "�����������1��
���r;�Q\�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<)IDAT8�u�=hTA������l�nv��B0I%VA�Q��JA0�(Z�������`!��N'Q �e�i��$�Ƹ�w�������L3�c�332v����|t���& �* ���j�y�Tz6?5^�C��G��^��m�� �'gaza��ō7��7n�=�Pm`�HO��veK��#����y=fO�cd���H������N'0
b�2V�X!�1ln�� ' ���\��D ��
j��3�.�>����qk�KE��Nݯ���_4K�'�S�5�� XcZ*JJ#��~�0[�@j��Ӳ�^�~���1<zc�S��v"�@��D�YUV�c��vj�3�݌ �e�ř���NU�0b
V@I׬Kg��&����s]7 jH�o�-'�Z6�%��j�_5%r'jm×��͝l貈��(��f��|���Q#�H���FT AT��D�]��x��)�� ��,���1�@�U��L�k7���Kq�k=�]�CL�O�֥6���H0�:m�������!Қ^��jۀ�w޿�F��V�ڴX%hR.��?��)�zIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<vIDAT�K��e����o��l��4x��FA����EA����hF�R��h.�u�PW��h�`�j"� ATDJQ �6���xΜ�{{��L��~����gJ؆)d�͸�3W.�B\�����{F��v�����l���X�t�LH��-{��+Ο^?��/k�<�gJw j���?�A��>��8--���&;�T߶řlw^~p������=,+2�t�D�]� "(�������6�69]�f߅I@A J��D(J��wɆ��^�߹V7�=  ��BFh}RB�d��4jc��<�yR�2�
�$j)%��@6�+ (-��I�(�B�!��lLt�(�YRC&P��ɤ!����P�$�$���7�Bk)3IR�@��G�Y>��S���1�Xe�
}�O��$hɍ�#�N}ྦྷ�3��K?}b��B����8�L ��A##=}�-���`���x���U6o���_��
�q���u]ђ>郖���[6���༮��
�ak��rԋo��Z��%�Wλ��1�G_4\:�:�]����*,��/���_�w4��E�+�����;}����V� �����I��L��}�o���G��)g$���[?��/������`��/}���� -%nQP`IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT�Oh�u���y�w��9�ge��&"2�&A�:u�Vt�.AA]<L�:����:dE��<Ě�jH3�ܜ��M�������Ia��_�^���"م�H !�U9O.����֍W� ���p��g>9�롢H낆 ��Ҋ?/���}�_'֏ jC E#m�*�Ưi)��LYU��ھ�}��ظx��q`�u��#Rk��RJ���j4$!� d�D!iOn��9�C/��i��m&N{�� A�� DJ�D��)u\�~���'ו:��nһaK A� I"%���wyĖU���־zRWO��؄�wR�D(S�HI�F��^<mK|����Z�}(5oh�����^?����g�
d�D��"%�+_Z���՚V4Wtn�o��y�{�2Ud( WD��}�k=�?���3:��4�B��}fFF���6lWg���CDL��Խ𓕼�ՋGd-���6sn��ޣR��ͤ�Pg� 2�?�𞗭�gĥ/��f��wc�{GճY��(T�
����#��K�����Ww<���ɱI?����+��*pbS�J;���V� �m���?�{���;,=yܣ}�� � �*��J�%T휫��SK�^���&%��HK�D�9)˔�:WP�J��Y�ո뵡Κ�(��]���IJr���*OA )�{O�r���=�@ @+�<ZN���X��WyIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT�K��e���?�� �yi 1+��Z�IH7 "(!*
�Em���m#\D� iэ�p�A��V&�!RV�V�86�s����L����Ʌ#��K؄� ���_.N侘�|���ms���{������tC)1�4�LH�.�{�ۋ�>5{��/�r�Y�Aib�`�=vVS"��eնiz��u�[�{�s��^?y׳�-���g D���l�b�� �BDP���A�6��������[P ((A�P"�%Bi�_��^<o���Ԗ+4�#�Ȥ�BF�]RB�a0��'�\m�:�k�WZ(�I�E�PД0Є^��#V]x�Psق��HTDP"�%Bd�C�?�|�MF�ݣ�+*2��%��Df"����=���hdl���{�gO�*]
Ԛ2�$3��?9���Q�ԧ������7��MP��tIV�JW�jUO�o���qx�;�N�3͞9��kAj�j����R ��?���I�KV�~%���7�l}��_���?zж��cld��+����v�p�z��6=�N�;c�� �������=�U�����5�:�>ݙ:�����Z4|^�D㻏N��3',_���f���Gf��}'��r���s(3��Ǐ�����l'�(����s��w|�i������|0"6�\�ښ�)k���ZeMYk�5K�mdw�+RO�����IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT�M�UU��{���� ���S#
�r�� �-�M��RT�ڄ�K
�E�aBD!�Ѣ�H!j�M �dI�� e�c�yw�9}_�9[�������,G?ȁ��)�v�|8\�|�؞��!��w&�}���%1�Y�B g�.^��w⊿�M�����w{�OA ����b��19�䤮�N���™V�Q:�.�x��W��v���!�9碯��H("E ��d�p����36�(��>��Ԏ�gS�5�B��e㏻|�o~�+�U�Фںe����KZU�ݝ�齓���WU%N����[;�?�~�S'��S۲���nj�vG2j|�ӎ���4m�m-��5Dl���� y��аEw�S�A��^�nw��\[ּoxhD_����EB���M��'{_L�d`����ݢ���� kw�Z�2�+
�2J���n.����]���M�q璻M�&��㐲�*�2e5�&��7nz�Z��j��r����G<k�%��n�Չ<�kL�A�"�U��Dl#�8}�/gЙn|r�#O�=gd�l�7/��֕2R&�*�z��w���͉ξ���/^����/�rb���I!D#�7�"U �7�@ u�hF��ڲv7���^�꩔�2@Y�T7��z���P_1G� 圣L� � g�(�*�M��C !�k��BX��A��,tSJ��h�Y+X�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<IDAT�Kh�U���;��g&�d�&Mh�K��&h�Z��� ��Huݍ�.�U�� ^6"�(���؂��!B���" �bjB�m�$3��d�&M:�̜s>�GT�W?��VK&y��� �p!�m��o��~r��`@T�ß_����C�����*�R��d� �������u�uzp;0V�'"�cfkD@@x 8�Ԛ��{�y�шˡܪ�o�wFw����_w./�,�7���_�t��?=���S� ϋ�)fʊ���E~����j�ή�O:����:5I��������`.;þ�X<J�Mz�ʞ6��=I�O��}���NO[-��W�s��$��� �?�G�l�Y!a 7ׄˋ� 7�$c�Dƙ��g�ת��������(߹K&�ή�ݴ�����"bkH&,��%��Q ��<���v�=�/#CTV�t�%(�����7��s�� [!6B֒� P��=��2��n-�X��2��a
�y^<�r����"��
����s.�';;��j��R�1��7�QX�@D!2�T �)����b~�z�F>�������;\�fY])�V.T�
����(�x����g�8��`O���­ ���U��|v� �*`hwLs; �
���k�'�M}9��CP�
^ ((�
�0��8� �w���\����OE���5� BIp>��Y��t����@#���t�D�BK,�b+[ޅ��*Ϝ���k�"򤢭((�((�”����4���LIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT�Mh�e����~��|���ϗ������HF�!E�^�
"�<��:tAt)�."#���{��@�"�R+�T��mn�9����=�>���`���E�^��t!��HD�.���XN7o�wt��Y�^���_��am�iqP " \�5��qCoO�u�L�O�߆r�謫���rJ$��D�n���3�-���_˵�(�����K�|��v��҂��:��#S'�L�H�,�X�������=0��^4�+�$�ȉ��������\%W�O�k��u}ɛO.UuT/C A]�$���9�+:#�g,̖�Rfm�g�T�6�A�NY����(D�M]s���
��A ���H�@�ы&G.X��Q]�:��Z���ȡ�6-�J�
�0q��ի�4}��V�eŊ�ç ܫ���՞={zj(%DA=}����588���ۺu�LMMͫ�Ov�:��)4A�BS8��eR��r��Y�v�o�+����˖-�����޽{���%‡��JBI옘PU���~�V�G��)�Z���I�.]r��y5�ۍ�a��[Y ��/�|����!k֬��o�K�f�Jccc����Ҫ�}��v)1�H�\n�B��+��]khh���133�… z{{��U�an���Yݱ������Ɨ:p���o�r�� ���6=�9����4�,���7�6)"l�uhW{.v��� �����FFF��z}��r"s���/���0Wjk;vUIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT�K�Ve���ΙGm�$�d7�fe�"��EIѢUPm�M�v�"ڹ+�6��.�v����]�2»6�8�f����ޞ'2Ӷw�>>1�J 1d�����+y �M�}xώ@d��>8z��77�-%'� �䍡�'��tf������Ȟs�Bi�ѶY�ۿ�A��>��K3���n�����:9?��SϾ����?|~�@D,��f�)F
m�� �"P���㩕�l��X�
$%(J��D(M��ߌ{=�4�|�v�H�2��� !d��'%� �Y����S����c�-��I��"�D��J6�QJ �6R!
(����D(J��0҄��8�ώn6��@�ڑIE"3�J�Dh溡U������J_�jM�I���v+��Π�\����\����}���A }�O�R]���k��ګ҅�֭���`�O���{��h�v�fz�灐j���:}�/����а�6w��1���?Gf[�^߳rbĆ�EM\����;&���^����3�.\��٣��y:g����Z�ZsЋc�{5ҭn��c� ��l7�f�ZO�����G���d|r��S??��p���`�Y�κ���,���/`�x ^�{�(�&�O�r��v<-D���oz)"�H9@�H���sS����_]}r���m��
aS��/IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT�?��s����~~����TI�!!�b�F� ,H8���b�1a5�l� �N�QB� b`�^8M�A��~����y*��޿������\�)(��0���k��������J�������i�ΆIH ���q�����~�����{�СM�кOg��Ԫ(2X2�s��,�}�O>�};���x��3o}~�W�tܠ��$��S�j�bjLEMa8�����y�޿��ww>�����J�Ҫ�*m*��u�=g6=W�|�v�jz :@B�(%U�Z��4�\��1����m��f��j"�j��A�ƚ6��hT��*J � V��ZJZ $@�1�0PHZ�(}
)B�e� ���� @)zc�Ԋe� ���0�2FH����d�#�����W?�9��</���;���C�9�A��x�y���轍y3t�-�;��w^�t'I����WM����eС*>��W����i!�Gc��{s���ގl6�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT�_��s������w��Ι���2-�!���I(vaŅ\p��"nȕ;q��j��f�����$�!�q���眝�����<���zeϣ ��=\��G�@Y�j�����ϼ�w��@d�{_�f���l���X�4�LH'����Y�������K�޾uZ(M��͒��5%� +]V�Q�8�l�j�[ֶ�� ��?��靗|��}s"b,3�~S�
m�� �"P���z�
W\9oA;��=(���D(J��4���V� ]�4<��RM�yZ�Lچ2B�چ~��J�:R���5�D[F�B&�6��QB +�z����6�v�n!V���J��D� �&�J;��K��f�#���Z?(PGdR��L�R(���U�&��d�]z Vzj��]Ϯy��ZSf�� �޹�M�z�n���V����z˵����-t�.�J��&��J�3*�IQ���O2;㿣sM u�j�W���a��!z�Ģ�:�U�Y�b9�q�_9�D �Q��X1�s�eEM������ݸQ>�>N�Y�oN=0��|i���\��ZsЉo�:5�c�>�~�'�k� ?~���������K=�ܷs��p�;���,{����,���F4S�y��bFoݓ^��~��~�Ѝ�������mqCʅ�my���}���#��sth����n����o��?N#=�ƙ?IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT�Kh�U���9ߙ[&��IzPR�5 �Ġ.�Z+�f��ƅ�Fp!"� Bw��ݹ�Ѕ�p!�`m�l��%hSm &�:��|3��}' �'����Z�r�;&�*�p�Ȉf � }붷޺xf��$���.~63y��nH�!��ڝ�ٟ[�,v����tf�|���!�}��;d�d�(�"q����bk}����^�zW84���-��Ɗ���d(%,D��8r��l���jr��R��\�4l��&�L�J}/}�ݨ����^N�5����Xe7˛9c��R`�##\���<�����赬T�v��|K�N��/�~�r��Ḳ���6�R� >���G�J����8�a�
�.[������<O(�2e��0��'XJG���AsȚP�\{��_Q*r
h�}Wn"/ � (�'ՑG�y,�`����������̡��]�p$�d�-��w�.���F������ݡ������C|�<������ȼ�Zr�(�$�x��|vf�ھp�j�~n�V)��@w�����dB7=�߽� E>�&��0�7�|Y?K�6�F����+Qt�p}Χ�[|U{���� ��@�_W#2Qt"`�Π��k��!���9!&p�;�9Bp�����\�}�ѫK� �$���a���Nі�$�N�? =�;"��@����]�0�?c�|�5$�#IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT�K��e��������Z��Y���L ����( Z�)�.�$��"ZDTAD���(�Tav��ݴ2�15o3�x�9�?���ĝ���>�d�%l�Bd�UW��S�q��ڱ��m}��O���G��/%�%� ҉����v�����~�w�g/o�hKkG�fٯ�5%� +ì�.] ݾ�b�^��X�u�ԛ/޼v�X�2{rr���2�i�^� �BDP��%#��<n��ѫ����u�=�5s��mPA
�JP�p��W_�(�V��1�z��?y��ɳ���I�BF�ä��a$��N���+Ͽm���>��~���� v��$�(RJD ��dS��]y�6�>���?<Y�͕��=s�_�%B�zMh�'��y�����{ϯ��A���}���R;2�Hd&���I3?���'Ml�0�C����w�`:���5e&IJ0��~3�{�n���3~�f�SƮ�d�}� +�$+����C�ػO{�U6�t��k�����Z���5w�5E����K5�?�-�36�˖_��y����"u��Ε+����|�v��p���O�ɞSG�8w��7:fb�+V����㝬i0�h��Z�Z�?��A5R
P��ҡ��,��жQ�a������#��7�gf�T���d2� j���aW�h#���ވ�1�"I"%�`���}[��R�Y^��13IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<QIDAT�1��e����}���AW��`^� E�h 6�\C�� N��m-
E) ��RX�AD�V�Y������������_~�����.��(�^z�Q���]�w{፳�����:�ó��޺�ҩ �`��g^9�o�{����2S�m��t��>KGO�̵�ο�,.���W���1޶��;d"]�����w�W�����Eu��Ve���i-Cp�-���^}��1[������|nm{�h���g��?�6�7�[�1 �ila������}�>���:���2�΍�鏍�ui���v��C;?��Ҥ[�6�OD��:�ƹ�M������/&}�8�\��v�N^|b�:�b��q.k����-�RX��$�bq�\�7M��y|� Cg��sQ���A��T}�%E$;z�+� �&�M�&j#�E��d�LE)E&Աjc����DKCGW:��.0a�@f �U�M�&k�HТb��(\ޞNO�ڷ*k�����N���T�� x��/?ݍ�p�����,�2�JQ
P�ww�������r�n�ܢ AQJd��YZ��?�5I83�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<IDAT����s���>��מ��*�v"�6iD ��@��"�DLb�5�D���h�2HDDIY$⥪ ����<��uUϼs��c�^� �@!E������������g�*������ǯ�9=F��@\�q��W�����?|���ϟ݃�Tm�����FE�5mY�����n��/�ʑ��מz�;>;��ހ�:�d�N�f0�`*�
�Ա����r��v�c�€P00�QeTUF�1����鞣9Q^}�N�fzf��y��T�5�2Ol3�t5�{ѽ����y,0CB0��(�4�[F��I j��F�A����֒����$` t���"DY����# !@�R*̃�� �0�ڬ!M�6A��iX�0C/щ�o�"��W*Ҁ�
�|�`�� ˲ZW�w��{�4�*��% �*�����qpk3,{�Kw�׍o����
-*5b�G/k/0�������t�_o���d �}g ;��Jo��w]�W��*�?�������!�����y���!��!�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT�mh�e���u?�9���|��b*�VI+R$he!������A�!A�e��SB?D�-!��}�r$�sJ�Z��f��6u;��<�}]�~��ǽoJu۝�X��)Au|����;3��Sy�r�ѝuN  �����c��L^�U�YR>�^�.���>i�|�ĉ��)DSB0�Y��x��3�S����<����{��Zp"��̒|��9���D@(�Jy�+�gms��K�#�@��N'��%¿�U�,̘�N�&�%�x3� ���Ѹ��1��\��0 i��a5Y��~� ����/�0`�6��︯~ �/mGM�Q��T*n�/\�i��fo�" ��`Y����
�&�%KM�WCd�J��g��0 03��\b��N��-���gN�{�)nMW G������X𪆙��a�Xw3P���ポl[���+9��'��9ȹO�W|T���AS�_��q�:���v����\�O�
����`��/��
� �#��!M ����|�4Yx�i-۷���ȟ�����!Db�U��;� ��{��K�6�-�X�:�E�"�W���+_�!���T-����������{�������! �,��B��W׵�݋7��dپִhfm�w�ܙ���+"h!��������E���}��ȓ��``��&19�k�y&��w�%ńev��qIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT�M�Ve����7��8���b�Dfai*QT�@�h妍�P;����]B�@hQTP��6Rd%XAT(T���0���s���x����M(a6�/�AV]��-_��c�������gN�ʞ���|� ��#�[�����/?�_8s|qmibG�m���)%de�Uץ�������O�l]��z���^�té������̦�m�� �"Pm��Yܻٶ�'׵s3�@I
J��D(J.][s���} ��÷h&���L��8)�m�e���4��Z��kR���6�DE�����'.X?�갳a��+k>+��4;u���ʚ/~�{���������=�o��v�:��_�� >�rI�q�ԎL*2�V#�nt����+���"��֜�LI)�IF��ء�jM�F�n Vn��a�G5�^�n(#e����?y�?��Wu\%2�dz�j�nl<f�܄n-��88{! Ɲ�L ����5eV]72v�nPkWk��K�����D�-���!
IF5�����EWWnjG���^����3Y�T��S�1�Z���/�8�U(�V�tp�[�)���6"�=}��#��� �K�o��ڶ��goxr�>�-��[�6ә��F��:���;�=2?9o���Ց�U�X�U�/��������F�/�ˮIEND�B`�
�PNG

IHDR��7�gAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT(�u�[� E���&}����O(��@_֖��9a.і�?v�9\ ���bB�WҴJ�/\Y���+DI��O�)n,T(pbe���F��8��D�`���ñ_9υ�N�8�s]蔊�d!���4����i���/&~��<EOK��E�K�.�:'� 1%�u;Š/2�[�y�OIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ��KQ��eV�J���q�ҕ`����Q�X>b%��BB �*t!�ЕB�iU| Q�d&�d��+3�D��� i���ν��s9U���0��O�ƨq�
�e�s��]>�G9�9|>��BI����uE��� �� À���T
�$q�(����� �&]05�w��Lӄ�iH�ӈ�b\��d��:����X`�6����߸�TUE</)���X��@�;mk���n��D"�3����}@�3G�H(�,˕��+��!::���? �C=!QE�8���/0�/a�� ���fyHB�ؒ�P/�H�����v�A�mn��������)+/� �8���Ŀ�B�����"nƆ��@Z[)�j~Uh��^���N��3Q��O�R6��]����n��^Sݑ����I1��Oc�
c����4e�sKx�C�A� fw5>��V�<c�h�[�$9���ȶIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<*IDAT8ˍ�͋RQƧ�� ��6������H*)ZS���E����$���ZD�Е�ĕ� .�Р 1�
�E���z����<��Ls�q���pϽ缿���9��)rٸf��C\��M��.cl8 0I|^���(d0C���@UUK�$���V� H�Z��� ���@ 4M�a�޼�����t�]��u���$~� 2�`#��v��U��/@�e4�=% O�������B�2�;��R�ͦ�I�R� �1���V��~Ƴ2���#��h�Z���hKW��.�x�kw��B��L&#�O�����d�����6ݐ��P�<ba*�B�\��;��>�D��{�; ����XL�" �
��u��S� ��2d�ƻ�07>�,�D<G6��i�B���F��Y����U�s0��u��O�c���R �d��B��8V���(�}�X� �u �Wm�Y$�H��n�1)� ���t|?��>�76'�@�XG"�r9-�y����8��]"��������L�?�y[��ӿ�ح�YQ�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8˕��K�P�[����8���V�"���Apj�������[�JS,�889U�`���(Z�R����ǜKSӷ��pr�/�w�k`PkR�Y�e��U�ѣ���+�J�^�7 ���>���,4�E(��R.�C&�A<�X,I�� ,#�P.�Q�V�J
d�Y$ (�J�K���th�D �|�d�k�f&�6�:Fk�9�6J*��Ȳ��)=��0�t:���q� A#�Z�&r!��.Bo8
ذw����ٛ��4_�q�`�ST»��ʼn-�<VL����p[�D��,Od��>�_�Z?^D(z }=~H@����� �a\a�0��m4�e5eE���0�����<�#�̕�"�&`��AGya{���4)l��}�O�/�����!&RIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ�KK�`���
���I]�t�^�����R�Y��U�8L�V7*�ځʠ0^t�JEQT*R��IS�&����~�S/���\�'��+PB����aT�A9㣓s <�lV���B/��C�n�[PE�d2�T*�H$�idY�I� ��#��H@d2X����i��u��pA:����������{���ksƷ,÷��V {�:P�0 �b�g-��]z�򍰦b�aE���(XK�o�UUy%�H�Q�,�� _���l�ܺ��ٿ� �HB��<���I�+��a⻻� k�tlK�� �A�/ ��(*j:^�|D.���% ��&�!/T6w�;s�� �9�*H@P5����w1��?C�qȄ��00}���+�<HP����[�5�.�Ω0Z�+��^baU~vS$��� ;�ZQ��)/
�Ż� � ���A� (E7�fϚ|��e$y�r���_vN��k)7FIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<"IDAT8ˍ�=�ZA�߹*��Ic��4)$A��,
k����f!��X����w���&���&**qר�\�?W��3���G����9��0�9�`�y(�)L���Qܑn'� ��j�Z�6����n�cA�<�J}���(�;���l����!��1����JH����t�1�LĂ�r����"��)�F���I�b��b�l6+!,�H|�7�FE"�"$�I��qP��d2�0�͗
Qo"�|>TUE�P���/���O�J%�b18�N8D�Q P5G��nG�XD ���B(��_-��W���|@�ل�jE�\��b��t<(����~|�}�ܝB�Xq�Vx�!��! �R����<e�ɡ��f÷��.0f�9�.��D�.�d,�]�]@r�4v��邛��S�=P��4 �z�O48�J� ܢZ�J�!'rrg���}鬪��;2QT�h4�Ղ��s^�WV# ��K@��NS�j�3����^f�������<H���5�����sƎ� *��'�麾�1�]P���sV��Y9�]<�����@�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<,IDAT8ˍ�_k�P�g?���d����G�J:��bE/d�u��@� ���.ZA7� �ԭ�е�f�]�6iҦi��=?�9ڬ�� <���9�y�w ��^)���p�
rC� �q4���^���D"sÒa�$ ��4:���6$I�z��h4H� ��$f6�V>�O+x�iB(���v�idY�˲�6��b�%�;v��#�����B6}T$�HeEZ��f�y�H�'4<�ֈn���I�@�&p�x}�Y��7�QEᕈ�x*��TEviPC�Ճf��#��:"��]�y?TU=,�+�|�BbGE����br���o5� ӱ�� ��0Q Xxߨ~����ٚ�W�Pu&����O3�<��r #̭�EG��"|g.6\l��-�x�2��� ��V��/�H���@�5����t�F�����G�s5^����[.��>�O/����@86�-*�:�/�E��@0  ~�+��g"�n-dqc�3�s�̝��GqF�n�C�9A?�\���l�<a�n�O�`�I�1����`�����IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ�=O�P�)C��0�[��!�k�_@� �@
��
&~@[%C
*UA���V�J�;dB� ,@l�_��ر�o}n�qHP����=�<>���.]����D\��c�n?/ �8������F��N�q$�ɷAIP0Hɦi²,�0�iDQdA�J�|������mT�U�&��2t]�$ILP�T@I��MIP�[5��AJ(�J�e��%6O�(��~�0�[d�ā���a�(��*�y�U�t�O�л�����M�̾��_
^�I��
�P%4UUo�VNcc_E{v_B|�NuX�ת��A��"��*k�fB"_0�-K?�6��љ��c.oal���7�.`Z�������:g�|)bb��ܬ�*��ā�G�
���å��2��D����a.��a<�g�ɏ^f$V �u�Z�A�m� {��T�o�Y�����7�A��A��{:;r���{ЁK_p-pdQ�>���2��A�$���t�C��ʘ��?�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ�OkA�k//9ւG/"�!GE �Ԇ4M[Ү�D���!�@?�?�=�'�%�����n6�I�9��7&�.<,̻�ggޙ�0G��dER�%�:�� 6�G�f!�h6�����@� ����}x��n��$�i��jiI�C� �"�q�ބ�1X���~��v�=�dC�p
(�9�m�SKR=I�� �������AuA�@��z)�㨙t:�I��Nj����S�����X�� �h@ ����fB�p]���y����K�o���$�*&�K��*h�/�����C=!��5_�=Fo�8���ܶo'�^��޼�W+a
%!����v�泈{p�M�W?�3�3��e��J��G�\:=8+�˝���
� U��$58�j�{�$QPxJ@��|~�z_�U_SEw��8�\�2%Hҿ��9���n�3�ւ?��lPH�ۄ�B�ތ`�$���)t��~���{F�f:IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ�_O�P��o�?��}�"Je&^�xO �h���� ?W���qdR�0�B����v�v�s��ԕn�M~iӞ�wz�� `�E �+�C�r!��eY��8���=G<��7 �P�ՠ�*J���
$�@������V�%ό���4 �rY
��&x�d2�K�n�(K�^�cI��n-#�׊j�UV`�x~ ������nO�+'.�+ �G�Z�Lf���?}Y�(y�,{0?�h�3��}�㹋b��^�_
�~�n�7�/���!0��� V�&���4�|.:�&�d���ɔ�[�#��B����?��X%N5[���å@��gTP���|{���±���F�L۶%��e�a���(�Y1*��x�F��U7� vqs4��hʳ�)�YG)��Z�����E�}�/�ܣ� ~p�0���� �Xr��܆���?V^֫��T�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<fIDAT8˅�MK�Q����̼3N�Nb��a`T�B�6�5�M����_��jS��֢����H�D~V̌��;�眧�69���9p��澹�������g�""a r8��r�$�9'��8�edd�� hiM��W�U��j��T*R*�d~~^�s2;;+��� ����gP�<(�ӛf�拉Š5@�ZM��k�n���)
���B`ll�����5��ޑ�:�_��Z�
$h��BCC(�MfXk��\>*t�v3�3G�͓�/����3�9v���� >!�2��eB8����\�(�$�Yaz�e��ӵ @&JQ��`��Z��c�eE�l������\&�-� 8�1h�QJ�6�����7f��7wn��  �u����[����^?1֓��5BPJ`�iVP+��~|&�V:�͙��k1sK]�>�#�J��Xm\_Me���Ks�f�\������O�?Ż:��|����5�K�*D�Mr�p��{��*KQk������Ή��x�z��ɗ����x�i�W�z��/�M0YYZZTٜb��N�:��� ���Τ#�6 /��ֵ�H�^�0�d�A#��~9�N��X��F��~{TB�|v9�IEND�B`�
�PNG

IHDR��7�gAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT(�u�Mn�0��E��9GBꂫt�P k�BH�$�4]8�&����瑟��J&ѨF%���@d�s3W$�q&гݨyFz�\<jU�RU��wN|qDk��G2��H�Ǽg���' �7�=�Bp�{��K��q�=���1�,=��Фon���Y�( U��<��B��*�D�2���u�M�x#��>���M��M��IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ��kQū��]w%R�.�Z�V� (HWJەJ���QqF�n�H�SBm��PA7� �EII������$��w��d�Fځü���o�wn��0��v�A��q\�
��j6�[�V ���!$$ ��Z���bٶ �4��*�Ȳ QcH��t��}�a��$�uaY4M�z��H6�� !����C���2s*2s
f���jq8�]�wX�59q}=5QP ��� �Rq���Z^��}GV ���T*�6�(峋�]z?��.h}������۩����Q�Vۀ�Y7Y��CƓ�� ��ʴ�3�\��7xM�R �x!c���op�Bp��c�rW�Ivp�TJ3@�ɼ��s�X^sx���C���"K1����ѫ�+8s��|)�0�S�7q�^˫6�Y��u��6^;���<�pV,c��:��Qy ��h�P �>��X�lv�:�lWW{��s�E[1��0+�G{ fg]>� @/A�0Αh�{�=��ҧ���IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<NIDAT8ˍ��kAƫ���@"�G_�,>�X,� 5��R���x M�چ4�i4!��R�Tkђ
�ň��msiv�l���S?g6&��3��f�9s��Q���HE4��%���)�Z�Vh6�ۭV �D�a�XLJ�0@͒$�\.wU,!2�� I��`� �wQ=P�VQ��噪T*�P(��8P�T@/�Z�m ����n���yL�9�r�e5���Qw�W�Q �,�[�99n��n=���79ؗ����1������琀����20�¸8�_#�m���6�c�,�j��|zo
ZgcO��MGqv2�3L��ȳ�r8xb�2������M�#�M�ϲ08���&0���j� ��p�������.[0"���C�La!���L��0V>���m��;�� �,J�OG#���:�dg��fq��н��98zcC3��Õ���5&A(�a����%�f��,f0����\�,'� �e<�j/LE�QW
W�m�m,�Hɼ� N�#�
U\&f�5�F�!�@�#�_/b�H
-e/�������~A�/\�;1��%�{�~
�A;wD[��'�V��~.m�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<IDAT8ˍ��kSQ��k� .�W�q���:��΍݋��\!X%Ym7A�.B"Đ�@��@�����9y!S�yϱyM�b|��ws�{�{7l�.�l����rݚ`k:�����r��E�yh4�w�u�6��cH�$3 ����h4XR�ՠ�je  ��j��M4E$A8F0d���4��" &� h�N�Gb2��|��l6�z���j�K�U*��q�\.������.��}�-_����?����o3��
>������,i6��V�g�ш�p����>���G�.��ç�O�m�5~}�B���yt:�3��f���9'L�\�ە��i��n�h4�e����I�R��Ár���Z.�C"��q*�b(Db�/�N���~
�/�J铠�n�l6�|6�q��@�R�ŽL&�
�ڥHB�$�z��=*>'�5�RyW���b1�h�Z, �Bp:��Z! NO��B�KX�V�g�d���� h >���=��Yp*�%�h�2��#��k�M�\�:�����{�F`k��IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ��j"A�MbV �2��2/�bP$j��lu!���q'F���kN��.�\�������� �qƺd]�G�SUg\�V��v���v;�L�NN��b\�x�X�r�T�N�4���� �����R��n�q�������T���$e2�u���!��s�L&���`����
����[��z�ш��5� )h4�H$�`6��`0�Iz�ŵ
o�jPi�&��(p'�N�����|�'��mj�ZT(� 
Є� ��
��k�a�l6e�R��0���l4!p��t���ipg�j�*�R�$����*�f���f<�Fc:f�s���yx�^� ���:߱Q��%�X�r�,��!�@(>�Oq��f tׇ|p���;*�J���i ��v����q�D"�s�N�h:x/x�O����_��O�W�7�On� �)�sy��9 �xΦ���_K��<����IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8˕�;KBa�գ���nBCM�MBh����("�Zڂ���38��PC.(8TK �4�u∷�=^����#��~������y�
���Q��a��$CCUM`�$)Y*�*�r�`��r��Z%��H�l6 Q�R)$ ��aY
���|�����!�ϣP(�O"�� �L"�Ȃ\.:��v˒6�H@�t:�h4��Rm&�&k���ީo��X,&W"BwA+�������/h�P;4 $ �Ţ<� ���['^�f���2~^��PH!�9Ǜ݄��)��^�׻l�V|f�N_���:� �iC������Ͼ�����4����fm�QP�6���qd/���*�2�[|V�G� sl�"���2}ݜ �9 ��GdO�� 5�6m�k���Iz]�˥a��� T��� _��#��>U��)ےIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<IDAT8ˍ��n�@EK��J�CQ�����o<%A  U%R0�u�T�!�DI��\�mdlǹ߯�f΀M�E��~�g�:��X!��6���t����k��=��.��9�[����Z�,�����1 \u:�Z-T�U1M>�υ8�[�|�T*!�N#�L"��B�u�z=��mض���T������r9O&�y�J��f�o$S�р$I���<E�V��� 3o�y4���*��.X;\� �\.sH�^� �� `f��)�£RD�d2�˲���<L��.@��
�z�[�B<:.*:�^�9�'@`j�@. �x_1ʻ�RO�3%����qnu�8=CJ3�>�t:婜�.��m�����$N��8��0,��3�|�!Db��(� �F��a�7�8�v�c�q5���jױ��_
%��D�?�(z�{/=�xq\�B.�Ç�!d-�@ 6#^�8rΏ�`�������6��� ,�4�8������݃kt�~AZ������ۻX%� ��#��?y"�CupX�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ��KSa�WEDBԅЍ�}a? ��P3B� ��]t� +$aA ��I���X^�ns�\[sK�p;;g�������ɦ�p���s���6qt �w�`��԰U]�|^)�J�r�L+�:N�sb��&��\.���u��,�L�d2iI�YBӗ������)��v��>)��iR(��D�4E!�J��߰�EYyZ���,�ǽ�M�!�a��*�?fH�>��>�ƧG�9�Q7���&�h�޳|�}+� ����n�� ���$�j������cM�?��}w����+���U;��}��92XͶ$����jx�w?Y�=“g�~���Z��\�-��32L>vE�d��i��/��� �e��{;���^D� ��t��T�߈�]v��5Jh�.�A���z�{��������<N
� ���̍%�S,��(��9���N\ϱ8s�l2ji#����A *2�8 '�ߧ˅��E�&�Q�!%{�r�;d�?!n�,��pIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<IDAT8˕��OA��W�5F"�������w ���xT#Ab��!jژ&������a�"I5Qh���]������v�?gF�H�'y2��ϼ��N@��c��� ')GX� �#B,��6�M� ��p�i�D�Yq�^�mۻT*���R��%�� �쑰��l���<�όZ�˲��*8�vH4�}V,`VP�V�iھH;wұG@c�n`k�[D�u�w"����V��\\���( m �a^�c�U����� g^�H�%���@�:��������� k� �A�y
�wȧ��7H{��h���v0 R��4BØ���0r�����#��i8����- �ʿG��5O�t����m�&Lzq��]��W���q�'(��a�v0�*�%ۙ9�)x����vv�F�㳓�G�Gr�\9}��x ��g�b��>��G߀WN�����_���}���$G�bBp�Iij�&{-�aI?�@>L�'��n� �����"��$>����Z� �?�zL�^IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<)IDAT8ˍ�OHTQ���;�D�:�L���&���DD��)-7A����Q�Z�����b�3�c�8o޻��6��T�|���;��)@)�H>�W���P� ��E�5�ȿ�����v��4�Q�R�$�r�Y^^���E1���‚����!jp�Wֲ9'�u8'8+X�p�a����q��$a�#�ˍ �ep�W6R��)
�d��\���/�-�$�4E�����%����Ȥ���q��"�9�1�R)�֎&����-�J��C��4�c�����y�����Z���Z��ʋ����~>|��4�¼�М��f�5W� ��Š��}��h���b�0��|����3����Y=�jK����<~� �����~TT���$՚F�021����LW'$���d�0�(��}���m��+g�Hli�ZÞ�>�Ͼ��珄���Q� "(�p�5���� ��}i��a�����p��!�i|g���V�S�M�Ƙ��bsrZ�^�P8kmp��֮V�V�]�:{�L`��/��G*�_>IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<6IDAT8ˍ��k�a�W�@�%t\#
�&j�Pɉ�lk�h�k���E�$�XZl��:�2X��#�0Z���/��v]=��zg�h/\/�s���x�$��d3I��]L�_ @\�V��Fc��l���9�^�VH+@J�b��R�$(��!�� �sH,��� ��pz�ZG5�e�~�`px C�K�T*(
�f�H$P.�AE��o3nq��Ϻf�@s�?A�Έ��sx4����y$��F�L���L[alb
�#ZL��Қ`w=��[�h�0J*��,//�$�CS:�枾��<���i��Y1���4n����B�P�tz ��g�Ύ@�7A�����@�PA�>q���t���!4?eB �2�.�q��KL�p���,�F�l�<��N���z�Z�CH`��U�}�m���Cx
�l���o?��&�����Hԍ0Xyu��8䪣_��� n����ö�;��: ��/@�RQ�5�������
�!�+�<��Dzr�B0�J���M����R�vZ�s�=h��
���Jt�3�[���d��G��_�ٝ]<W�=IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ��KQƵE
]7���4�m���Z��… Q� A|�E)�d�?F(Rh�tӢ��.D�j2�;�;��{�f���6s��;�|����$�.����z&����!˲j���h'q�t:���Ȭ�:c�EA�ZE�P��|>�L&�A��N��4a�6�o�a��m�P��P,%�0 P�l6{i��>8��vn* �r
���T*�If�
p��aμ_[�13 ����\.�Nr��=�am�'��H��������B�P�J�=��=�9�z��/�����bB�k�&Am��O��� �#a�͔7��82���6���Qe�� s��X@]Ȁ�����|���ė�����s���4���}"�U�DO���ށ�����~y-�BW�� {iJl�x�&�U@��?����o��q��Q���6�>��ǘ�]Mn��M�G�sS����v�����/�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<IDAT8ˍ��kSaƛ�8���bA�c�JE'�������:tp�!��KEp�i��C�6�iC�6چ��ބ4��77��9�Mz��� ����sx�����bM�����,���v�}`��a���Y�:<�;'� �s�لi���u�j5��e)�J�z�H���<h�Z�t:H7x�����J �4M,˂4��|!�1�u�Lo��I�X�r�:ߍ��2��~m=���on���>|'�T*5I�X<�l�7(���[X� �E�'y4x-ɣZ�h%>�r�_�s�
w���G]C���@d�0h�L�KW��1<H�1��E pW�t�]��@DÀx�5������Bs�<&����U �iNe��zf�|��5�����h)�����@$�!w%� �t�U6 ���{��X�%V�3��:D#_p$�{���7���������m5��N�P�B�}���`YGRx����� �<�u�� 28��.dJ���4�[C�^`\ ���?�7³ �WIEND�B`�
�PNG

IHDR��7�gAMA��7��tEXtSoftwareAdobe ImageReadyq�e<$IDAT(�m�=KB���[���#�. 54��PQC5h8��B��EI��1�aEZ=�s�n�#�ų^��p iDA} h!$��Uv�.��X�t�� �Y��Ĥ�'��<��!�O�K�:u�)S¥F�hD�����S㋷�+�u������I�wJ<yAwm�!�����,%N�rO���? �-���+���E.�a�eR��뻐�� 4����>�x@��Ӡ��D����9"N�49���p��d�<
���)���M�+�$E�Y�5��Y;�_!o�Ɛ������\�H��IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8˕�MKQ��M�!Z�� ��M� ��[�.�PladdF������qѢ@Â
�m��s����5?��0s��s���ak�a`�0�����%0��Xl4��f��# �%��H�j�
��۔J%
��iY�J�
�:$��$� �Z �$�O�R��X,"���A@�D"Y�#�� (P.���f{Zj�D�!`m�7�;�������J��dA7j UB���� �j�fB� �z�.υ$ĿT ��C��]� (�@��N�p>���]P8c6��� #��֍+ޥ/�>?>�/�'��n�qg�ջ�7lQ+LG�����Ղ�AsX���zߋk�f���껰Ȇij�}/��bg���<���7G!�Z�#ɠ�lrs`%Co����4�t��Q��Л1�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8˕��KQ�(R�J}�B��.FSkJ7-�"�RQ�U����P�FQH�P��4�UĂTJq���B�JB^�s�֯� ���h��1s�o��0��|���ܠ�TXPD"o<?J$�(�9�z��,��T !�I|><�v���l6 �S-�!#��WJ ������P(z��h�s�B��~8��s-%�����8�@��w���%��j���F��I�{�����H�j�-���8�Pb���\kD��=�"����#��X���r���ѿ�K:�-?�J�����Ǘ����s+�z���ڍ>�v��iQ�|����,;-����=�|���z;֚1��s[�x�
w߱DZ�����eo��q�o�q�5f���n�C����}��R�X
<�-A�.�ӷQ5��W ���@�Y�2�dU��,��O��i�I1v M�(5y���@(
�l���Y�P���R�49�T���}�vs��IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ�KK�Pǵ�����|�R7�B7nD�0�B�R�: � tD����G)��� �υ�}hT&1ɤyg���{n�%�H ��=�w�9p���id41���!�ȋ�J��U�V�k��`�$i(*�
���y|�ض �4��*�(��L&#$ar= (�X,�\.�7�.,˂�i\�l6�W
ZRRj����- ��/$��8t]���I(x�b$5�i1��Ë���x�a+�B�W"��m}�m����= s;&fs&L�,$T ��0�x���_��Y�� �/iZ+@Z�E%�̈́D����F_���������y�W*>�������S{'.�,��V�<H@P5BК�L��H>�H/�H/�<y�����+����d�������L��`�J���Ք���yt��蘖1�� A�<�;kh�:y�hn{�������W��E����U���;���]{õ�H�ـ|:�O2�u��F ��c�Ch�Y��S�M�nIEND�B`�
�PNG

IHDR��7�gAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT(�}��� `�9j�t�g[��G�ܲD��N��0-���C?�#DX�������l�2�B��Y|氍D�g�:J�+�8P؍D���RhP��7=N�3 �I D��x��%���gG��0���2�����c��� ��(�� �f���W.hlǠԝ}ewqCC=QYe�,N!V��N��P�L=TIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ��kA�S��Pς�HɭЊՃz�*X�A��=��!�E!EI�)��zi��Q��R�Jj ]kQR�d����5��&>�t�&5���.��}fް/ "���P��%��<�";���8��Z�Z��$�#�L>h��n2�� ˲��4 �J���B��T*���A�m���O�a`��T*��9h�t:�Cv��d�u�ryW��;�h��z��AUU�Ȳ�Ь0D�~f�zy���������x�2��q�쾑��_�s(e��'`k�P���x|�~q����Q���p�8��$X6��4��Z�联��07�?�a篃��u��b�?�����
��KХ!��S�7a����aw�\W�l�9��N�4�og��cXI��˽~����޽�͗�!��a�y�j <׏�}Ƚ��k0��V#O� G��g c�L��kp�����Xy��ݳ^��=t$\ݹ[���SG��'b�'��n�5U���Mu���+�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e</IDAT8ˍ��kQ�����;���tW��h���+A[���>�t�& 5��*�&BP�EiA��X-Z[��-i4ii��Lf&�yf�?zijZ������}�s.�@�|[���������U m�ΕJ��r��� ���%Ղ&6 �i:��
EQ ��<�`0�H*�u��;ڳ�Ӑ�����8�/�>��>B �X�Z$
�PA��� _\O�D'�d�� ��P�� ��(�O �BMKl&T��ɳ�q�6�c� �9?�i/��f(�>�I���d�qܒ@߿13��v��}h��0~v!�jr�^����Q��il�,/ �Q�+�q�hs~�w�M����0?�8q�� a���w��q��D����r3�L��> =�#�[P�^�ߜ@j��G�!N�"o(l�G��wu��������r��T� 7�4r�����|6�Z)
�Ҳ!�g����b�y��ǐx��h R��"��W��ڐ|q�T=���� WS#�_��1����eo]��K���u�)K�������#�+�Edҋ��ɿ:��*A=��a�+�կ� _Z��MHyBIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ�IK�@���C��7����/�= ŋ�Im������\� E*q�[A\j�U��6�4S�:_4�U1 d�g�2..1�����TR���!��g���i�� �n�{�\b )��:c��r9d2��qK�(
<�7 �
��0P(�'�i��,��%���E�^�%�!�� (��*���JgR�M j|N�w�mWI�R�NdY�[P�W ��#�N;�f�P ��5&��1��_�/�L�}~��`7
�]�c�V��i���3��$��Q�A4)°+�������E8�!��� ��_j�8�������C��=L=p��U��U��^���X}�L�wr }�u=�R��Y�8�yƂ8��]c�w��!�6i��Mwֶ�w�A�}L���L6�����xG)�>_o��$qp�-����7Z����7�����ZIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<TIDAT8˅��KTQ�?����8�O3��J�@�Z�[7�]HX B�~�m�F
�A�@��EB���E��.*��(�y��j��8E���{��|��� ���O (z��{"��z������7��u����8H�=�­fx ��q���G^(6���pΑ�)�B���-VVV���/� ��2~r���F���8�)t��^BJ��!a233�sssK�k*�1G�:HbMR7��uR���,J)��-�L&C.�cvvv�֘����Q9�x!ω�<Qy�Wo6�q�4RJ�Rd2*�
QQ*�Z��P�~s����U�YO9���Oq��]P]Xk�s�0 ��l�,�gF�&E��K�f�^�M��K���ɏ�C)Ռ!D35�ӵk��+ظ��]��Ⱦ v>>i�V�RA����҃�U�5���u�")��ym�������}���/����.�::�;�f��dit���8���[���uw�Z[)�R� T����3��@f"s��ÏOoɏ^�my�hY���0�X�E\w)]:�z �]���m�|�R� ΋�6N$I�Z)��>�t��Z6���.0ܨ�~��X���X��ҡ3IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ��KSQ�G�g$T�C�aYQ�hEHY�� ��eIŌ(� !)J��i��~1
��� _p]��~1u�v���{w�v�݋~;��^��.|~:�����r��Pr)y�`+eS�.M��i������8�=��d�J�lgK��y1W�u��Ħ,���!# BEx�^&�y���I�a2s;��O�*�����~� PU��@�$����B!���ߒoDz�r�\�>�~!�� ���^F�Z��D���#D7��2�gc�V~YB��� �B���|ܢ�e/.Y����f����@����;'&:��m���<���»��+�*�#��ƽ��x N�ȓbȽ-PF:����y_�p��CS�DIf�Ȳ�(�-��ㅙ��w�i!�Q���cBd��&��"|�ª�B�I
4�q�:� ��b�(�0Ua�-���y�
�OU�-� � �>RJ�4�ȟ�a�oKd��5 J;y2zo�{�� ��h��� ��W�����D�a.�u�6��FfP���`e����a7��W؝�.��@&w��<��:���O����j��nt��u�N��~��a(��=�+h
����� �D@�?�5&H[�}4��~�eJ/�w��i� ]��@_�_�
�8O �pIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<BIDAT8ˍ��OA��/�8&b���&('��ś1���$���41��PK�($�D�i�P��)�VmR�
i������~��l��62�s��=3�ym6�m�A�A�8`�����t]���V�TB5�}8�NG5 ]�4,�2E�E<�#�J����r�L���nop��o���n
�MӐ�硨E�$I�t���
z�þ��٫11�Y�A��pB�N�Xde���\.�L&c��� �`���>����{��(Q�c~S��0'[�B�nD��y� �i��F}���]���uL�Kx��C�S��Q �"肞}�ԗ xҾ���Pg5�,X�j�,�p�")��W�$��@�&K��� �:�����0���D�$ Oay���W.M;���'�� bD�p8��ES~�|��8���$���a��0/�*m���av_�C��_��Yx
��ӈ���=�)�H��cx��n=�\�[��L"Ů�P(��P�n?@k�.u>CK�(Z�����lf�Z�_��
[4S9 G�_�Ѝ턍��JA#�lc����o, ~���Nč3IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ��kQ��.�q�E�����Ǫu�Ɲ�+7Ս�.,؅�E[(XhUS�@P�/�D�H(}a�EJ����ؚF�8ɴ�$����{.�$���1����sf� �F��?�cT��Ք�db�|��P(�lv��VJB����d���h��h4
EQ�D�e8.����&Z���+Ёt:�l6˯D"�@,C8�T*z��.i��Ê�n
(l@
��qD"����Oъ�:����x�Wk3� � �S�F)��"t ��q٨�؁��:�tO]�)�b�*���02GsP��ī޳�;����OM�E`�!�;����E\�p�˝�(8TA�Z�����о�fMkD8� ���˞)x�>���*v���o�_����֗n,�@(�q�5f]����=�(�;��^Ĩg�&}�>���y(���r�������5<�Ρ7��@׃%��{�����}�S�x��ߧ��I��l��X�@����~�!�/\�b��fIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8�u�;hTQ���{�q�F�%�ш� ��]*k_��r]�!��IJ�+��!�A ��X)6�.I@Hv�����̙����#Ks��3��qf�����7ƣ��h�pB��n��rz�Gk�t۟������'���xl-7���1�u������4��W̌��`f,^�g������7o�c�K��i�~ *47�`m����85{!1H�s�
�94`"L̜E�`��hw������vZ=��ι`��40UT�=����V�{k�����!��h<[YY�;�vs���c����Dq��AD�ޓ�)�Je5�cj�Z}"T<&  �is�EQ� I���*0�cA1QT � EQ?ONN��t!���`��YUE%`jX#w�"2��}�D1 ��� �-���d�3����!�A�=�z�gPX��υ����-N��τ��Bɷ�o�zx�a{{��;�K'�B������]�89p��d0s�a,�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ�KKQ����� [զ}����mJ"��&����zl�4��E�i�E���$nfԔy���tϭw��s��O8�\�?��:F��jR��h5�M��P(d%���Ś�����,�(�P(�D�Ö�,�C&T�U0 ����� I�E*�T*�?�8�G��������l�� ��q�����R����e4�d��)�5!I� n�,@��<��&ѫ'��<�� v�3�����D��W���8���/P.�m;>�%X߸�� �w���������(6A�6&f2Ek*l�Ƴ� �
�0A� �|{���-�X��V0J��pl<p��|^� p��OF�g|~�VVOm�>$���|������=H���D7A��=�@��J&�ֱ��b������(��:���w~⭞)���IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<IDAT8ˍ��OSa��s���ZbMJPA�q�h$���?p1�ͅ�فф�EcT����ĄE �+h�����^n���8Pj��$���7�s�sDU���������PUz&��4mc��V�S�������U2�6Ƹv���N��V���FC�ժZku{{[����&2��ëR��x��NF�b�8���x�M����q��2Y��gee�����k^,���u����q� ˟�^�A��VB�P(ʏ�]>m<c��$3l��q��w�^@��f���k-�J�H�����5Fre<]|�A���ՓYKE��9��b�ʮ*�{IF#Mqڡm��$) ��B� �AD�~`p𕰗z6�.���MB�q�+c��� �#K �������<OZf��N�$�"Ȍ�7�aH T�￞b�a-���sd�1������""x�D���l����)�c8� �P� �$]}��m�yn
q1�q�,���c��M����/�p��Q���R�;���f�\88��9'L���_`FgS���IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ���SA�?����b.H��l��,m�^��B ZZha�P�H
�5�-�^c��؄$B�;�{;�c�葠va��|gvƨ*Ƙ-�,�o�U5��� W�,;缈�*ϲL���[�"`U�`�9�ө�i���d���H���z=�t: ���n)��^Q�Q��+O� O��h4(���nw��j�a����~<����p�$`'V){�)�����ݾ������h�H���xL��l`� �g��y���!=������;�8&I*�
�ju�%��L� �VC3���}:,�rGEc0�̛^BQ��ό�v "PA f��b�Y
��+/�� y��P84s��6�
YGQ��vp��#� �P ��m6�,8AU��%��l<�_9��>Dz�M��;7�,��!�a��03i�&"�a= q_���R x�a�`����_�|~��vM��,|��NIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8˕�KKa��E�"!hQAIe���1- ��J �\�
j�BA� Rh�-\H�hA��(��::��ۜ���30���9g822�P h�0,0@ YU��8.U*�*�r����v��%�@C�\.�ek��i$�ID"Q���x$t�I@
��Ţx'��,R��Ѩ(���0 #JZ� 2� b�XKKՙ�B��L}K���q��P(�Y�L��*�y$���j�fB�����\HB�-�*vױ}o�9� ӭ���BT�%h������� (L����<��ѧǨvd����x:�ٿ {Њ�7'\����;T�S����;�s��`�ۄ����#�\�0�?���vaV�2+:.�ŷ�w � - � Z��eR���:�ؕߓֱ���+(�\��ҴphIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<IDAT8ˍ�OOA����B��H�V�&&$$� ����H���m�r3 �"��'.� I����?�������v ���f~�̼�N��0����*#�b��V��B� � 6Y���%qA?7�Mضa��ժ�T*
�H�_���u]x�'F�eY�u�ZM��DQ��.��j�ɝ�(��} ��K�K/�ZX�;����S�w�O\IԄ�d�Q�����g�o_A?m�Vh�<�\��y0�:|�+�PU���D��kk@� vI`cf&�ߒ��j:��ss('S��݇�iA����9|�����a �:8}d{,�# ����_0M�#h���d�d���.��ghf*���E�9 ct�n�"rN .'׽B~F'!pXX���qw>k%����Q�"��4��2���&ۙ�}�����\Mvl�w�q�I����)��Yz�;�B �I���|�"a���7&�� <�6������vj��IEND�B`�
�PNG

IHDR��7�gAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT(�u�M
�0FG=�R�P��3��:E�#�q����C("�ڟ��9��i
���y�0��x4�!
T�B�A�}LkZ��������݉6�G�
7(L{P ��� �أo�X#�b��x���G� @�)���yxp0�—��X,�X� �<4i0H�ȧ<.m{��b�4O:�a"נ�JF@��zt�� 7uN�x���x��?,?X��.YwIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ��KQ��X�?Tpi��b$Kq�.J�E�MQ
���.�J7�d�Mq)n�}7""hq� � �E�|5���{of������Dt�0�y�7瞙;`�$�R �����| �97}߿
��$�#��|�!: If۶�8N�n��N��z�� �Z �l6���a����N�, �i��h(�뺠��r��w��� ������l���:���v��#���QZ��JR�Vo��n�.,�;O���{��7��4��ώA( ��n�u�rN�Z/�w��8�v������X�:!� ��8�O�vy�|����<\c �/�q<�S����<~��_BTR� �{����Xa�",���֏gϙ�
��X�e���������8�yklMn�_�?�_n��u �~_=���oۃ���!Ӳ ���,�Zj{5�8A�Ρh�ǯ#��f*�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e< IDAT8ˍ��j�A����G Q�D�+Q K K;�B�/@/@$waag#�5,�DPD�p�p��~gw��8'�D�80L1�/3�$��p��;��/�*�B.��~朽���2�����i�$�\�9��ښ���G����^��n��R�5;;;�4C�6�!�H�Z+��J��bP"� ��In޺� 6cv����&i p��2��w>�W��,�1�-�`�Nc&�6����Y�o4�*��D#�1�z�� N���#����h�!D@��B `�@'F6�~���'��z*B �D�F��2�5�bd�@%��|�<[�SY��u�(1�hp� ��4�M�6�.V3���u]��T�� \�
n�1���|� I�� �P3�5}�t�e}��(U\;�r̶�12��Qk�a�&���
}�\�������Ž^h]��c�Cr��k�ު�6��e�Ŧ�Těne����PB*z�*,�H����;s��=�v���7�m�|rx΁� �~P%S�!ӂIEND�B`�
�PNG

IHDR��7�gAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT�1nSA��Ǟ�4A����(�I�Sp.KPp"��Q�A�7%�����1Ӣ�;���+����Z######��DWk=�C�?��|��X��j�9昇���S�ekMs9���NNV��G@���kD)��4�hn�������.Q�@�nJ)1]:�;1@� �T��:�t���i��:���I�$fM��-�+g�]�����^LvIEND�B`�
�PNG

IHDR��7�gAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT(υ�M
�0�'Z��q�J�[A=��q/�� ܺtc+Z[�t|I[l�?�<x_��S����ӇW\J�,������涘&�6�J�Yc����is�c�E/< r,,���1�Y�X�� J��������E�a�Y���Ҷ
�#C�����I;w{\��_�� X��rM�9_�o �غ�ru�e�K��]��u��Y�� �IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<.IDAT8ˍ�O�RQƧV����
Z��r��EX�d��� rjmJ��F")hD�����E!��r
Ǭ!��� BS���'�����{<�|�Ź�w���;cƨH�$� ���]D��:`��j��n����0J$�P(4���\�����q�\.��~T*T�Uv
�����D-�D�Tƾ�6�8�iE&�A�^�,�(� �l6�h4�D~C�Q�w��n�91�t:�
j�J�҆��'z@Y�܇#(~r��)+��߳�Ea��h'�\n4 �\��`��,<|�����P?$I��8�l4E��lf�<�k:�����g�f��
�5��� ���`�n��jpl��Q�{� �H$`4�J�@���� Ο�>�pF�\� 5n�`˸���X�(C�»˻��z�oÛ��V�}�)&��vl'Ɖ@�X�z�{���{�`aJ�8ސ��w���xqˌ�l�4���3�-�yK��7w�0;�#v� ����Cx͏ڍ����O9I Rh�oˤ/&w�l{u���:���o�Ѥbu�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<IDAT8˅�OoQšF�.���ąw5�{�;w~�a��o ��1!�EB�Z W@i��պP�� Q �a@�0�Ϳz|wZȔ�:�ټ���{�\I|ׄV�V���BK3��b�ȶ�#�q�H��h4�B��U2O&����V���h@�e�����f���O��9�i�`��P(@�4��u(��h�I&�ǐy�骥R ��MlU��l6���ϴ�f2�, �J��w����-s�#�����7�$i1@d�`0��Ϟ#�!�ˑ�,Z�֚�-���@U k�r�a�e�S�Dod����������e0�=XzZ,�f_G|���Z��q��-�3,h���!�<dn�d�ه�T��D~Qx�¼��0f����=7`z!n�P���k�\.��d2���t�6���E S�T.�!Q . ��?j�������>�S��٫Y���O$W��Zlv-���`�s�^���5-�*�f⼙8�� p�-Bҩ����� �b��N��L�^�y������/]0�4����q�� �`IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<PIDAT8ˍ�oHqǗ��8 -���7FDh�B�ȔJ�0��ތeь\��zFQ�"�‘V
��^� �Lbc���s���M���vw����]�Om�����~����Щ(�I�Q��j*�"Ac:��$I�f2�C9���yT,)��p*�˲y��$H�D,�$A����%��U��<A��
�0�(
�x\p�!>��$'�ޖ� = �kneT�M,�n���ɒO�z�
㗏��D��\d� ��V���\o�|�gܣx��$���S�6Y�T?�@�� �s7��v"n�F�Z�c��h� a$��D� ��x�g��%���zEL�@�R��²D�6,�3����a�{�O���邠g̹z�� ��xxK�`/a2�0�A�UAx�G��f�5�@��.��y�}���4N� �A� c�V0m��
�+m�/�{��ʊ��<��Ď�!Wǝ>ؚ�0T ���� �f`J)�����.�]*Pか��?? ��^�~�V � ��Z!�Z03� ^`!��F� 7H��LgY��k�A�y��~e�X�`=a��Ѷ�H`V%�X���������yIEND�B`�
�PNG

IHDR��7�gAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT(υ�A�0E��֕n\x���qob♼� �R�w(���g�I�u2�U��5�S����6�VX���ʲJ6Yhl�Oe<�Ƥj�56�S&����5���n�2 ��,��be� %,r�[;�z�ֳ��
X`���<�Ɛ�dz�B����7|�!A��/�n2=V����Y��� �r�o� v��ZdIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<IDAT8ˍ��k�Q���}ɢ��7.Ĥ�Sc����R+SY��`+"���6�_���F����,���]�f�ǽ3Y7Q����[̜{��cTc�i`p���7UT��ȅ,˺eY���,�tii�50XU�C`�,˸����~�^���NG[�����l����H��{����B7��zuN�B� A�C����Z��(VVV�,..�����y�2ȡl�������n�� ����!q��o?��"���7L$��q�ڗ]b��iJ��ED!P����\I�И��� '��,�h�T���iJ�$����Vb��{��+�k]�B�h�|�^�p�6(�9��x�I�d_ {�,s����.���F����i$*�Z�s#����
�`s�����J�r��$S���1��ڃ� ™����O���n,�q� �[1����T��s�?>
�,���ܨ�����x)����} y6>ۘ�AT�5�#� 3�f�K!�U�p4����J�19Js�q��@��8�#:���/n�y�����IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<pIDAT8ˍ��ORaǭ�#���+/���ڢ��2�+u��6S�Q��H�e��UV"5�L����Ks�a� ž=�)�����>;��}��{+PB!�B���%���x���������V>��� �P��*��/(��kkk�d2�d�x+++�$C��p�B�'�W3N:� �Ӌɻ��z,,��H$�DXA6��V��)��Z���D+ �ި`�O`<��{+:��quL���I�����[鐨��n���W �)^}[�)���G�c��At[�1�مh4��$
 ���`���F�aг�Kv/jl�q�{��>����O�I�Rl=b�ض��d�F؀�$O?��9 q�
*� v��~�L#�:�fE|�w}@���og!q���ی�:>�Q��!1r�+�l��-���<��ǘPy͎C*;Ι�p�z��+T@������� ��M��?��a�_p� C/z��NWfƀ�� 6�wAE��ܠ� �c��|�y�5�F�Nԡ��2�Hw��'(�A�Fle��7>ųI\��H�"����^�LiEn�5ۙ�`t���;��'�%�G
��;-?�|�f��'(���X�t�K<�PU̗IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ�OkQ��~��R���t��@���"�Z� m�U�HC VS��L���8��F�"c2(������R���6�Y�w~���ޝ0Gb�<�"��t���3{�^}8^�F#�[���xc��Kdn�Zh����rE� �C�4QUN�Ӏ��w@��.j�|>��2��,B���*t:�!.��2 �������èT*p�ݐ$ �@�Xl�%��4���B��`0EQ��x`�ۑH$`�Xx%�'���#�N��S��'�IX�Vޞ��I��N[�CȲ�h4ʳ�*l6�5�M4���'�v�/�O!�c�{���+�d2�F�dʇB$M�,�m��ߟ�uD~�؊kXy�LF��D��0��3o�/] �]ǧ���_Unk0p�y�*�tw�<���~k��FU�T��,��m���@���_"g7J�%�������\_^��q9c�!�6 S�4B�s�Y@mZ����m��5r�q�F�
�OźX��IEND�B`�
�PNG

IHDR��7�gAMA��7��tEXtSoftwareAdobe ImageReadyq�e<IDAT(�]�MJ����+���"/$Bׂ�Q�BT)�"Vt�� D�*��ǦI��%�� �����$1���17� ����t�A�Ȏ&鰲�O�r���/���7�"o�l�ܐ_�jP�C�M�U����5<j�E!� ��+����5�����5Nc�钯<x�J�0!m���AY�O��]]�Vr�P�$ �5'Ι�Ȣ^6Є��9��slRJ��d@�ݽ,��
glq�F�(�I�uݻ����~Ü>(�M�_��Ǚ��r�
�L�[�n���IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT�M�Ue���ι��u��q���I�W�h�"(²l6�Ԧ(��E�h��]d�lآE�hS�Z��Q34%-gl�c�{�9������_�O�^��n�!��HDє���k�]���މ# C�����o�~ �4T���G��z�?+gO�[�Ñ�Ԑ���[W�g��rJ$��F�4�Ψ���n��,�k�l_~�ͯg�}�� CJi""�n�u2u��T�����ɮ�=s6m�����Ϡ���������E�3}����ܱ�������3Ӷ̮s�D�שmzxֱ��z/�f����L9~i��0<�k��š�~`� ג�ߟ_��TR�Ȋ_n���W���Ҳ��Z���W���6gM���Vƺ��nGȤ �hm�U�vᎏ��d���-��z����?:c�)Km9Du�ʸ`)e�ez5IS��Ң�{7�)�� AH�B[�C�h���:�ʃ�d8*n���I�"�sR�d���M���b�Jt���f\������ J���@ "ѩ�f؀:�i����z�&��Nvq��̾Y%�*S��(F��v~0]_�^[��n���;@�0Zm@�fPJSJ�u.M[�a���;ޭ�F��0կA�N��ҩҭ�)C )�GO�{��|�5�@ �j)�T�����' ��J�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<IDAT�Kh\U���9��;w�$�4�M[�Զ�Ɣ4�BK*TM�Tp�B�e-
�V\�ąB�Y!��A�]�$jbR��Zͳ���ә�&3��{�~�^����tS���B@�Q ��|�(��v铱��^�|b���}�h��<D��n��t���Z%7w�u��`�hO�
����&�V
��D�
�q�ŧ9�0�
u�N�>��(��4��W��PM,��4���z����M������ꇕ�p�׮����O^���J��~��'9W�8�}Z3�t7;�)�P�F��Ռ��l�0���ݫg.y�n����|���n���sTl��r�b1�x���ɵHw�g?�?��
��-���y�n�o�s�� ��Ha�>��ч��J&b�����]�% K��93�ԣ�tP,/�M�y���"`�����g��Gi�#cZR/me��� G�D�A�8H��ݝ�)®:��Һ��-,��f�.��޺Fe-)�(��>$Vй����*��8��
*��&Œ%�<��L��p���������W���y��7/��?Rh�Y�Ո�AW��>�V�;� ٞ����q�H�O\s��/���^シ����y�DC�M��� EV�y��g��D@�mZ� q�b����w����v�A���(�Y����9��s�:T��D+�S��M�5.n[�hh(�K��h�I;D �+����I��+����k6�!��A�@�ι;F��Qx�- �1IEND�B`�
body {
margin: 0;
padding: 80px 100px;
font: 13px "Helvetica Neue", "Lucida Grande", "Arial";
background: #ECE9E9 -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#ECE9E9));
background: #ECE9E9 -moz-linear-gradient(top, #fff, #ECE9E9);
background-repeat: no-repeat;
color: #555;
-webkit-font-smoothing: antialiased;
}
h1, h2, h3 {
margin: 0;
font-size: 22px;
color: #343434;
}
h1 em, h2 em {
padding: 0 5px;
font-weight: normal;
}
h1 {
font-size: 60px;
}
h2 {
margin-top: 10px;
}
h3 {
margin: 5px 0 10px 0;
padding-bottom: 5px;
border-bottom: 1px solid #eee;
font-size: 18px;
}
ul {
margin: 0;
padding: 0;
}
ul li {
margin: 5px 0;
padding: 3px 8px;
list-style: none;
}
ul li:hover {
cursor: pointer;
color: #2e2e2e;
}
ul li .path {
padding-left: 5px;
font-weight: bold;
}
ul li .line {
padding-right: 5px;
font-style: italic;
}
ul li:first-child .path {
padding-left: 0;
}
p {
line-height: 1.5;
}
a {
color: #555;
text-decoration: none;
}
a:hover {
color: #303030;
}
#stacktrace {
margin-top: 15px;
}
.directory h1 {
margin-bottom: 15px;
font-size: 18px;
}
ul#files {
width: 100%;
height: 500px;
}
ul#files li {
padding: 0;
}
ul#files li img {
position: absolute;
top: 5px;
left: 5px;
}
ul#files li a {
position: relative;
display: block;
margin: 1px;
width: 30%;
height: 25px;
line-height: 25px;
text-indent: 8px;
float: left;
border: 1px solid transparent;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
overflow: hidden;
text-overflow: ellipsis;
}
ul#files li a.icon {
text-indent: 25px;
}
ul#files li a:focus,
ul#files li a:hover {
outline: none;
background: rgba(255,255,255,0.65);
border: 1px solid #ececec;
}
ul#files li a.highlight {
-webkit-transition: background .4s ease-in-out;
background: #ffff4f;
border-color: #E9DC51;
}
#search {
display: block;
position: fixed;
top: 20px;
right: 20px;
width: 90px;
-webkit-transition: width ease 0.2s, opacity ease 0.4s;
-moz-transition: width ease 0.2s, opacity ease 0.4s;
-webkit-border-radius: 32px;
-moz-border-radius: 32px;
-webkit-box-shadow: inset 0px 0px 3px rgba(0, 0, 0, 0.25), inset 0px 1px 3px rgba(0, 0, 0, 0.7), 0px 1px 0px rgba(255, 255, 255, 0.03);
-moz-box-shadow: inset 0px 0px 3px rgba(0, 0, 0, 0.25), inset 0px 1px 3px rgba(0, 0, 0, 0.7), 0px 1px 0px rgba(255, 255, 255, 0.03);
-webkit-font-smoothing: antialiased;
text-align: left;
font: 13px "Helvetica Neue", Arial, sans-serif;
padding: 4px 10px;
border: none;
background: transparent;
margin-bottom: 0;
outline: none;
opacity: 0.7;
color: #888;
}
#search:focus {
width: 120px;
opacity: 1.0;
}
/* automatically generated by JSCoverage - do not edit */
if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
if (! _$jscoverage['utils.js']) {
_$jscoverage['utils.js'] = [];
_$jscoverage['utils.js'][13] = 0;
_$jscoverage['utils.js'][26] = 0;
_$jscoverage['utils.js'][27] = 0;
_$jscoverage['utils.js'][39] = 0;
_$jscoverage['utils.js'][40] = 0;
_$jscoverage['utils.js'][41] = 0;
_$jscoverage['utils.js'][54] = 0;
_$jscoverage['utils.js'][55] = 0;
_$jscoverage['utils.js'][56] = 0;
_$jscoverage['utils.js'][57] = 0;
_$jscoverage['utils.js'][73] = 0;
_$jscoverage['utils.js'][74] = 0;
_$jscoverage['utils.js'][95] = 0;
_$jscoverage['utils.js'][96] = 0;
_$jscoverage['utils.js'][97] = 0;
_$jscoverage['utils.js'][98] = 0;
_$jscoverage['utils.js'][101] = 0;
_$jscoverage['utils.js'][112] = 0;
_$jscoverage['utils.js'][113] = 0;
_$jscoverage['utils.js'][132] = 0;
_$jscoverage['utils.js'][133] = 0;
_$jscoverage['utils.js'][147] = 0;
_$jscoverage['utils.js'][148] = 0;
_$jscoverage['utils.js'][149] = 0;
_$jscoverage['utils.js'][166] = 0;
_$jscoverage['utils.js'][167] = 0;
_$jscoverage['utils.js'][168] = 0;
_$jscoverage['utils.js'][169] = 0;
_$jscoverage['utils.js'][184] = 0;
_$jscoverage['utils.js'][185] = 0;
_$jscoverage['utils.js'][186] = 0;
_$jscoverage['utils.js'][187] = 0;
_$jscoverage['utils.js'][188] = 0;
_$jscoverage['utils.js'][189] = 0;
_$jscoverage['utils.js'][190] = 0;
_$jscoverage['utils.js'][191] = 0;
_$jscoverage['utils.js'][192] = 0;
_$jscoverage['utils.js'][196] = 0;
_$jscoverage['utils.js'][208] = 0;
_$jscoverage['utils.js'][209] = 0;
_$jscoverage['utils.js'][222] = 0;
_$jscoverage['utils.js'][223] = 0;
_$jscoverage['utils.js'][224] = 0;
_$jscoverage['utils.js'][225] = 0;
_$jscoverage['utils.js'][226] = 0;
_$jscoverage['utils.js'][228] = 0;
_$jscoverage['utils.js'][239] = 0;
_$jscoverage['utils.js'][240] = 0;
_$jscoverage['utils.js'][241] = 0;
_$jscoverage['utils.js'][242] = 0;
_$jscoverage['utils.js'][267] = 0;
_$jscoverage['utils.js'][276] = 0;
_$jscoverage['utils.js'][277] = 0;
_$jscoverage['utils.js'][278] = 0;
_$jscoverage['utils.js'][279] = 0;
_$jscoverage['utils.js'][292] = 0;
_$jscoverage['utils.js'][293] = 0;
_$jscoverage['utils.js'][305] = 0;
_$jscoverage['utils.js'][306] = 0;
_$jscoverage['utils.js'][307] = 0;
_$jscoverage['utils.js'][308] = 0;
_$jscoverage['utils.js'][319] = 0;
_$jscoverage['utils.js'][320] = 0;
_$jscoverage['utils.js'][321] = 0;
_$jscoverage['utils.js'][322] = 0;
_$jscoverage['utils.js'][334] = 0;
_$jscoverage['utils.js'][335] = 0;
_$jscoverage['utils.js'][346] = 0;
_$jscoverage['utils.js'][347] = 0;
_$jscoverage['utils.js'][350] = 0;
_$jscoverage['utils.js'][351] = 0;
_$jscoverage['utils.js'][355] = 0;
_$jscoverage['utils.js'][358] = 0;
_$jscoverage['utils.js'][369] = 0;
_$jscoverage['utils.js'][370] = 0;
_$jscoverage['utils.js'][371] = 0;
_$jscoverage['utils.js'][372] = 0;
_$jscoverage['utils.js'][374] = 0;
_$jscoverage['utils.js'][386] = 0;
}
_$jscoverage['utils.js'][13]++;
var http = require("http"), crypto = require("crypto"), parse = require("url").parse, signature = require("cookie-signature");
_$jscoverage['utils.js'][26]++;
exports.hasBody = (function (req) {
_$jscoverage['utils.js'][27]++;
return "transfer-encoding" in req.headers || "content-length" in req.headers;
});
_$jscoverage['utils.js'][39]++;
exports.mime = (function (req) {
_$jscoverage['utils.js'][40]++;
var str = req.headers["content-type"] || "";
_$jscoverage['utils.js'][41]++;
return str.split(";")[0];
});
_$jscoverage['utils.js'][54]++;
exports.error = (function (code, msg) {
_$jscoverage['utils.js'][55]++;
var err = new Error(msg || http.STATUS_CODES[code]);
_$jscoverage['utils.js'][56]++;
err.status = code;
_$jscoverage['utils.js'][57]++;
return err;
});
_$jscoverage['utils.js'][73]++;
exports.md5 = (function (str, encoding) {
_$jscoverage['utils.js'][74]++;
return crypto.createHash("md5").update(str).digest(encoding || "hex");
});
_$jscoverage['utils.js'][95]++;
exports.merge = (function (a, b) {
_$jscoverage['utils.js'][96]++;
if (a && b) {
_$jscoverage['utils.js'][97]++;
for (var key in b) {
_$jscoverage['utils.js'][98]++;
a[key] = b[key];
}
}
_$jscoverage['utils.js'][101]++;
return a;
});
_$jscoverage['utils.js'][112]++;
exports.escape = (function (html) {
_$jscoverage['utils.js'][113]++;
return String(html).replace(/&(?!\w+;)/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
});
_$jscoverage['utils.js'][132]++;
exports.uid = (function (len) {
_$jscoverage['utils.js'][133]++;
return crypto.randomBytes(Math.ceil(len * 3 / 4)).toString("base64").slice(0, len);
});
_$jscoverage['utils.js'][147]++;
exports.sign = (function (val, secret) {
_$jscoverage['utils.js'][148]++;
console.warn("do not use utils.sign(), use https://github.com/visionmedia/node-cookie-signature");
_$jscoverage['utils.js'][149]++;
return val + "." + crypto.createHmac("sha256", secret).update(val).digest("base64").replace(/=+$/, "");
});
_$jscoverage['utils.js'][166]++;
exports.unsign = (function (val, secret) {
_$jscoverage['utils.js'][167]++;
console.warn("do not use utils.unsign(), use https://github.com/visionmedia/node-cookie-signature");
_$jscoverage['utils.js'][168]++;
var str = val.slice(0, val.lastIndexOf("."));
_$jscoverage['utils.js'][169]++;
return exports.sign(str, secret) == val? str: false;
});
_$jscoverage['utils.js'][184]++;
exports.parseSignedCookies = (function (obj, secret) {
_$jscoverage['utils.js'][185]++;
var ret = {};
_$jscoverage['utils.js'][186]++;
Object.keys(obj).forEach((function (key) {
_$jscoverage['utils.js'][187]++;
var val = obj[key];
_$jscoverage['utils.js'][188]++;
if (0 == val.indexOf("s:")) {
_$jscoverage['utils.js'][189]++;
val = signature.unsign(val.slice(2), secret);
_$jscoverage['utils.js'][190]++;
if (val) {
_$jscoverage['utils.js'][191]++;
ret[key] = val;
_$jscoverage['utils.js'][192]++;
delete obj[key];
}
}
}));
_$jscoverage['utils.js'][196]++;
return ret;
});
_$jscoverage['utils.js'][208]++;
exports.parseSignedCookie = (function (str, secret) {
_$jscoverage['utils.js'][209]++;
return 0 == str.indexOf("s:")? signature.unsign(str.slice(2), secret): str;
});
_$jscoverage['utils.js'][222]++;
exports.parseJSONCookies = (function (obj) {
_$jscoverage['utils.js'][223]++;
Object.keys(obj).forEach((function (key) {
_$jscoverage['utils.js'][224]++;
var val = obj[key];
_$jscoverage['utils.js'][225]++;
var res = exports.parseJSONCookie(val);
_$jscoverage['utils.js'][226]++;
if (res) {
_$jscoverage['utils.js'][226]++;
obj[key] = res;
}
}));
_$jscoverage['utils.js'][228]++;
return obj;
});
_$jscoverage['utils.js'][239]++;
exports.parseJSONCookie = (function (str) {
_$jscoverage['utils.js'][240]++;
if (0 == str.indexOf("j:")) {
_$jscoverage['utils.js'][241]++;
try {
_$jscoverage['utils.js'][242]++;
return JSON.parse(str.slice(2));
}
catch (err) {
}
}
});
_$jscoverage['utils.js'][267]++;
exports.pause = require("pause");
_$jscoverage['utils.js'][276]++;
exports.removeContentHeaders = (function (res) {
_$jscoverage['utils.js'][277]++;
Object.keys(res._headers).forEach((function (field) {
_$jscoverage['utils.js'][278]++;
if (0 == field.indexOf("content")) {
_$jscoverage['utils.js'][279]++;
res.removeHeader(field);
}
}));
});
_$jscoverage['utils.js'][292]++;
exports.conditionalGET = (function (req) {
_$jscoverage['utils.js'][293]++;
return req.headers["if-modified-since"] || req.headers["if-none-match"];
});
_$jscoverage['utils.js'][305]++;
exports.unauthorized = (function (res, realm) {
_$jscoverage['utils.js'][306]++;
res.statusCode = 401;
_$jscoverage['utils.js'][307]++;
res.setHeader("WWW-Authenticate", "Basic realm=\"" + realm + "\"");
_$jscoverage['utils.js'][308]++;
res.end("Unauthorized");
});
_$jscoverage['utils.js'][319]++;
exports.notModified = (function (res) {
_$jscoverage['utils.js'][320]++;
exports.removeContentHeaders(res);
_$jscoverage['utils.js'][321]++;
res.statusCode = 304;
_$jscoverage['utils.js'][322]++;
res.end();
});
_$jscoverage['utils.js'][334]++;
exports.etag = (function (stat) {
_$jscoverage['utils.js'][335]++;
return "\"" + stat.size + "-" + Number(stat.mtime) + "\"";
});
_$jscoverage['utils.js'][346]++;
exports.parseCacheControl = (function (str) {
_$jscoverage['utils.js'][347]++;
var directives = str.split(","), obj = {};
_$jscoverage['utils.js'][350]++;
for (var i = 0, len = directives.length; i < len; i++) {
_$jscoverage['utils.js'][351]++;
var parts = directives[i].split("="), key = parts.shift().trim(), val = parseInt(parts.shift(), 10);
_$jscoverage['utils.js'][355]++;
obj[key] = isNaN(val)? true: val;
}
_$jscoverage['utils.js'][358]++;
return obj;
});
_$jscoverage['utils.js'][369]++;
exports.parseUrl = (function (req) {
_$jscoverage['utils.js'][370]++;
var parsed = req._parsedUrl;
_$jscoverage['utils.js'][371]++;
if (parsed && parsed.href == req.url) {
_$jscoverage['utils.js'][372]++;
return parsed;
}
else {
_$jscoverage['utils.js'][374]++;
return req._parsedUrl = parse(req.url);
}
});
_$jscoverage['utils.js'][386]++;
exports.parseBytes = require("bytes");
_$jscoverage['utils.js'].source = ["","/*!"," * Connect - utils"," * Copyright(c) 2010 Sencha Inc."," * Copyright(c) 2011 TJ Holowaychuk"," * MIT Licensed"," */","","/**"," * Module dependencies."," */","","var http = require('http')"," , crypto = require('crypto')"," , parse = require('url').parse"," , signature = require('cookie-signature');","","/**"," * Return `true` if the request has a body, otherwise return `false`."," *"," * @param {IncomingMessage} req"," * @return {Boolean}"," * @api private"," */","","exports.hasBody = function(req) {"," return 'transfer-encoding' in req.headers || 'content-length' in req.headers;","};","","/**"," * Extract the mime type from the given request's"," * _Content-Type_ header."," *"," * @param {IncomingMessage} req"," * @return {String}"," * @api private"," */","","exports.mime = function(req) {"," var str = req.headers['content-type'] || '';"," return str.split(';')[0];","};","","/**"," * Generate an `Error` from the given status `code`"," * and optional `msg`."," *"," * @param {Number} code"," * @param {String} msg"," * @return {Error}"," * @api private"," */","","exports.error = function(code, msg){"," var err = new Error(msg || http.STATUS_CODES[code]);"," err.status = code;"," return err;","};","","/**"," * Return md5 hash of the given string and optional encoding,"," * defaulting to hex."," *"," * utils.md5('wahoo');"," * // =&gt; \"e493298061761236c96b02ea6aa8a2ad\""," *"," * @param {String} str"," * @param {String} encoding"," * @return {String}"," * @api private"," */","","exports.md5 = function(str, encoding){"," return crypto"," .createHash('md5')"," .update(str)"," .digest(encoding || 'hex');","};","","/**"," * Merge object b with object a."," *"," * var a = { foo: 'bar' }"," * , b = { bar: 'baz' };"," * "," * utils.merge(a, b);"," * // =&gt; { foo: 'bar', bar: 'baz' }"," *"," * @param {Object} a"," * @param {Object} b"," * @return {Object}"," * @api private"," */","","exports.merge = function(a, b){"," if (a &amp;&amp; b) {"," for (var key in b) {"," a[key] = b[key];"," }"," }"," return a;","};","","/**"," * Escape the given string of `html`."," *"," * @param {String} html"," * @return {String}"," * @api private"," */","","exports.escape = function(html){"," return String(html)"," .replace(/&amp;(?!\\w+;)/g, '&amp;amp;')"," .replace(/&lt;/g, '&amp;lt;')"," .replace(/&gt;/g, '&amp;gt;')"," .replace(/\"/g, '&amp;quot;');","};","","","/**"," * Return a unique identifier with the given `len`."," *"," * utils.uid(10);"," * // =&gt; \"FDaS435D2z\""," *"," * @param {Number} len"," * @return {String}"," * @api private"," */","","exports.uid = function(len) {"," return crypto.randomBytes(Math.ceil(len * 3 / 4))"," .toString('base64')"," .slice(0, len);","};","","/**"," * Sign the given `val` with `secret`."," *"," * @param {String} val"," * @param {String} secret"," * @return {String}"," * @api private"," */","","exports.sign = function(val, secret){"," console.warn('do not use utils.sign(), use https://github.com/visionmedia/node-cookie-signature')"," return val + '.' + crypto"," .createHmac('sha256', secret)"," .update(val)"," .digest('base64')"," .replace(/=+$/, '');","};","","/**"," * Unsign and decode the given `val` with `secret`,"," * returning `false` if the signature is invalid."," *"," * @param {String} val"," * @param {String} secret"," * @return {String|Boolean}"," * @api private"," */","","exports.unsign = function(val, secret){"," console.warn('do not use utils.unsign(), use https://github.com/visionmedia/node-cookie-signature')"," var str = val.slice(0, val.lastIndexOf('.'));"," return exports.sign(str, secret) == val"," ? str"," : false;","};","","/**"," * Parse signed cookies, returning an object"," * containing the decoded key/value pairs,"," * while removing the signed key from `obj`."," *"," * @param {Object} obj"," * @return {Object}"," * @api private"," */","","exports.parseSignedCookies = function(obj, secret){"," var ret = {};"," Object.keys(obj).forEach(function(key){"," var val = obj[key];"," if (0 == val.indexOf('s:')) {"," val = signature.unsign(val.slice(2), secret);"," if (val) {"," ret[key] = val;"," delete obj[key];"," }"," }"," });"," return ret;","};","","/**"," * Parse a signed cookie string, return the decoded value"," *"," * @param {String} str signed cookie string"," * @param {String} secret"," * @return {String} decoded value"," * @api private"," */","","exports.parseSignedCookie = function(str, secret){"," return 0 == str.indexOf('s:')"," ? signature.unsign(str.slice(2), secret)"," : str;","};","","/**"," * Parse JSON cookies."," *"," * @param {Object} obj"," * @return {Object}"," * @api private"," */","","exports.parseJSONCookies = function(obj){"," Object.keys(obj).forEach(function(key){"," var val = obj[key];"," var res = exports.parseJSONCookie(val);"," if (res) obj[key] = res;"," });"," return obj;","};","","/**"," * Parse JSON cookie string"," *"," * @param {String} str"," * @return {Object} Parsed object or null if not json cookie"," * @api private"," */","","exports.parseJSONCookie = function(str) {"," if (0 == str.indexOf('j:')) {"," try {"," return JSON.parse(str.slice(2));"," } catch (err) {"," // no op"," }"," }","};","","/**"," * Pause `data` and `end` events on the given `obj`."," * Middleware performing async tasks _should_ utilize"," * this utility (or similar), to re-emit data once"," * the async operation has completed, otherwise these"," * events may be lost."," *"," * var pause = utils.pause(req);"," * fs.readFile(path, function(){"," * next();"," * pause.resume();"," * });"," *"," * @param {Object} obj"," * @return {Object}"," * @api private"," */","","exports.pause = require('pause');","","/**"," * Strip `Content-*` headers from `res`."," *"," * @param {ServerResponse} res"," * @api private"," */","","exports.removeContentHeaders = function(res){"," Object.keys(res._headers).forEach(function(field){"," if (0 == field.indexOf('content')) {"," res.removeHeader(field);"," }"," });","};","","/**"," * Check if `req` is a conditional GET request."," *"," * @param {IncomingMessage} req"," * @return {Boolean}"," * @api private"," */","","exports.conditionalGET = function(req) {"," return req.headers['if-modified-since']"," || req.headers['if-none-match'];","};","","/**"," * Respond with 401 \"Unauthorized\"."," *"," * @param {ServerResponse} res"," * @param {String} realm"," * @api private"," */","","exports.unauthorized = function(res, realm) {"," res.statusCode = 401;"," res.setHeader('WWW-Authenticate', 'Basic realm=\"' + realm + '\"');"," res.end('Unauthorized');","};","","/**"," * Respond with 304 \"Not Modified\"."," *"," * @param {ServerResponse} res"," * @param {Object} headers"," * @api private"," */","","exports.notModified = function(res) {"," exports.removeContentHeaders(res);"," res.statusCode = 304;"," res.end();","};","","/**"," * Return an ETag in the form of `\"&lt;size&gt;-&lt;mtime&gt;\"`"," * from the given `stat`."," *"," * @param {Object} stat"," * @return {String}"," * @api private"," */","","exports.etag = function(stat) {"," return '\"' + stat.size + '-' + Number(stat.mtime) + '\"';","};","","/**"," * Parse the given Cache-Control `str`."," *"," * @param {String} str"," * @return {Object}"," * @api private"," */","","exports.parseCacheControl = function(str){"," var directives = str.split(',')"," , obj = {};",""," for(var i = 0, len = directives.length; i &lt; len; i++) {"," var parts = directives[i].split('=')"," , key = parts.shift().trim()"," , val = parseInt(parts.shift(), 10);",""," obj[key] = isNaN(val) ? true : val;"," }",""," return obj;","};","","/**"," * Parse the `req` url with memoization."," *"," * @param {ServerRequest} req"," * @return {Object}"," * @api private"," */","","exports.parseUrl = function(req){"," var parsed = req._parsedUrl;"," if (parsed &amp;&amp; parsed.href == req.url) {"," return parsed;"," } else {"," return req._parsedUrl = parse(req.url);"," }","};","","/**"," * Parse byte `size` string."," *"," * @param {String} size"," * @return {Number}"," * @api private"," */","","exports.parseBytes = require('bytes');"];
/*!
* Connect - Cache
* Copyright(c) 2011 Sencha Inc.
* MIT Licensed
*/
/**
* Expose `Cache`.
*/
module.exports = Cache;
/**
* LRU cache store.
*
* @param {Number} limit
* @api private
*/
function Cache(limit) {
this.store = {};
this.keys = [];
this.limit = limit;
}
/**
* Touch `key`, promoting the object.
*
* @param {String} key
* @param {Number} i
* @api private
*/
Cache.prototype.touch = function(key, i){
this.keys.splice(i,1);
this.keys.push(key);
};
/**
* Remove `key`.
*
* @param {String} key
* @api private
*/
Cache.prototype.remove = function(key){
delete this.store[key];
};
/**
* Get the object stored for `key`.
*
* @param {String} key
* @return {Array}
* @api private
*/
Cache.prototype.get = function(key){
return this.store[key];
};
/**
* Add a cache `key`.
*
* @param {String} key
* @return {Array}
* @api private
*/
Cache.prototype.add = function(key){
// initialize store
var len = this.keys.push(key);
// limit reached, invalidate LRU
if (len > this.limit) this.remove(this.keys.shift());
var arr = this.store[key] = [];
arr.createdAt = new Date;
return arr;
};
/*!
* Connect
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var EventEmitter = require('events').EventEmitter
, proto = require('./proto')
, utils = require('./utils')
, path = require('path')
, basename = path.basename
, fs = require('fs');
// node patches
require('./patch');
// expose createServer() as the module
exports = module.exports = createServer;
/**
* Framework version.
*/
exports.version = '2.7.2';
/**
* Expose mime module.
*/
exports.mime = require('./middleware/static').mime;
/**
* Expose the prototype.
*/
exports.proto = proto;
/**
* Auto-load middleware getters.
*/
exports.middleware = {};
/**
* Expose utilities.
*/
exports.utils = utils;
/**
* Create a new connect server.
*
* @return {Function}
* @api public
*/
function createServer() {
function app(req, res){ app.handle(req, res); }
utils.merge(app, proto);
utils.merge(app, EventEmitter.prototype);
app.route = '/';
app.stack = [];
for (var i = 0; i < arguments.length; ++i) {
app.use(arguments[i]);
}
return app;
};
/**
* Support old `.createServer()` method.
*/
createServer.createServer = createServer;
/**
* Auto-load bundled middleware with getters.
*/
fs.readdirSync(__dirname + '/middleware').forEach(function(filename){
if (!/\.js$/.test(filename)) return;
var name = basename(filename, '.js');
function load(){ return require('./middleware/' + name); }
exports.middleware.__defineGetter__(name, load);
exports.__defineGetter__(name, load);
});
/**
* Connect is a middleware framework for node,
* shipping with over 18 bundled middleware and a rich selection of
* 3rd-party middleware.
*
* var app = connect()
* .use(connect.logger('dev'))
* .use(connect.static('public'))
* .use(function(req, res){
* res.end('hello world\n');
* })
* .listen(3000);
*
* Installation:
*
* $ npm install connect
*
* Middleware:
*
* - [logger](logger.html) request logger with custom format support
* - [csrf](csrf.html) Cross-site request forgery protection
* - [compress](compress.html) Gzip compression middleware
* - [basicAuth](basicAuth.html) basic http authentication
* - [bodyParser](bodyParser.html) extensible request body parser
* - [json](json.html) application/json parser
* - [urlencoded](urlencoded.html) application/x-www-form-urlencoded parser
* - [multipart](multipart.html) multipart/form-data parser
* - [timeout](timeout.html) request timeouts
* - [cookieParser](cookieParser.html) cookie parser
* - [session](session.html) session management support with bundled MemoryStore
* - [cookieSession](cookieSession.html) cookie-based session support
* - [methodOverride](methodOverride.html) faux HTTP method support
* - [responseTime](responseTime.html) calculates response-time and exposes via X-Response-Time
* - [staticCache](staticCache.html) memory cache layer for the static() middleware
* - [static](static.html) streaming static file server supporting `Range` and more
* - [directory](directory.html) directory listing middleware
* - [vhost](vhost.html) virtual host sub-domain mapping middleware
* - [favicon](favicon.html) efficient favicon server (with default icon)
* - [limit](limit.html) limit the bytesize of request bodies
* - [query](query.html) automatic querystring parser, populating `req.query`
* - [errorHandler](errorHandler.html) flexible error handler
*
* Links:
*
* - list of [3rd-party](https://github.com/senchalabs/connect/wiki) middleware
* - GitHub [repository](http://github.com/senchalabs/connect)
* - [test documentation](https://github.com/senchalabs/connect/blob/gh-pages/tests.md)
*
*/
/*!
* Connect - basicAuth
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var utils = require('../utils')
, unauthorized = utils.unauthorized;
/**
* Basic Auth:
*
* Enfore basic authentication by providing a `callback(user, pass)`,
* which must return `true` in order to gain access. Alternatively an async
* method is provided as well, invoking `callback(user, pass, callback)`. Populates
* `req.user`. The final alternative is simply passing username / password
* strings.
*
* Simple username and password
*
* connect(connect.basicAuth('username', 'password'));
*
* Callback verification
*
* connect()
* .use(connect.basicAuth(function(user, pass){
* return 'tj' == user & 'wahoo' == pass;
* }))
*
* Async callback verification, accepting `fn(err, user)`.
*
* connect()
* .use(connect.basicAuth(function(user, pass, fn){
* User.authenticate({ user: user, pass: pass }, fn);
* }))
*
* @param {Function|String} callback or username
* @param {String} realm
* @api public
*/
module.exports = function basicAuth(callback, realm) {
var username, password;
// user / pass strings
if ('string' == typeof callback) {
username = callback;
password = realm;
if ('string' != typeof password) throw new Error('password argument required');
realm = arguments[2];
callback = function(user, pass){
return user == username && pass == password;
}
}
realm = realm || 'Authorization Required';
return function(req, res, next) {
var authorization = req.headers.authorization;
if (req.user) return next();
if (!authorization) return unauthorized(res, realm);
var parts = authorization.split(' ');
if (parts.length !== 2) return next(400);
var scheme = parts[0]
, credentials = new Buffer(parts[1], 'base64').toString()
, index = credentials.indexOf(':');
if ('Basic' != scheme || index < 0) return next(400);
var user = credentials.slice(0, index)
, pass = credentials.slice(index + 1);
// async
if (callback.length >= 3) {
var pause = utils.pause(req);
callback(user, pass, function(err, user){
if (err || !user) return unauthorized(res, realm);
req.user = req.remoteUser = user;
next();
pause.resume();
});
// sync
} else {
if (callback(user, pass)) {
req.user = req.remoteUser = user;
next();
} else {
unauthorized(res, realm);
}
}
}
};
/*!
* Connect - bodyParser
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var multipart = require('./multipart')
, urlencoded = require('./urlencoded')
, json = require('./json');
/**
* Body parser:
*
* Parse request bodies, supports _application/json_,
* _application/x-www-form-urlencoded_, and _multipart/form-data_.
*
* This is equivalent to:
*
* app.use(connect.json());
* app.use(connect.urlencoded());
* app.use(connect.multipart());
*
* Examples:
*
* connect()
* .use(connect.bodyParser())
* .use(function(req, res) {
* res.end('viewing user ' + req.body.user.name);
* });
*
* $ curl -d 'user[name]=tj' http://local/
* $ curl -d '{"user":{"name":"tj"}}' -H "Content-Type: application/json" http://local/
*
* View [json](json.html), [urlencoded](urlencoded.html), and [multipart](multipart.html) for more info.
*
* @param {Object} options
* @return {Function}
* @api public
*/
exports = module.exports = function bodyParser(options){
var _urlencoded = urlencoded(options)
, _multipart = multipart(options)
, _json = json(options);
return function bodyParser(req, res, next) {
_json(req, res, function(err){
if (err) return next(err);
_urlencoded(req, res, function(err){
if (err) return next(err);
_multipart(req, res, next);
});
});
}
};
/*!
* Connect - compress
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var zlib = require('zlib');
/**
* Supported content-encoding methods.
*/
exports.methods = {
gzip: zlib.createGzip
, deflate: zlib.createDeflate
};
/**
* Default filter function.
*/
exports.filter = function(req, res){
return /json|text|javascript/.test(res.getHeader('Content-Type'));
};
/**
* Compress:
*
* Compress response data with gzip/deflate.
*
* Filter:
*
* A `filter` callback function may be passed to
* replace the default logic of:
*
* exports.filter = function(req, res){
* return /json|text|javascript/.test(res.getHeader('Content-Type'));
* };
*
* Options:
*
* All remaining options are passed to the gzip/deflate
* creation functions. Consult node's docs for additional details.
*
* - `chunkSize` (default: 16*1024)
* - `windowBits`
* - `level`: 0-9 where 0 is no compression, and 9 is slow but best compression
* - `memLevel`: 1-9 low is slower but uses less memory, high is fast but uses more
* - `strategy`: compression strategy
*
* @param {Object} options
* @return {Function}
* @api public
*/
module.exports = function compress(options) {
options = options || {};
var names = Object.keys(exports.methods)
, filter = options.filter || exports.filter;
return function(req, res, next){
var accept = req.headers['accept-encoding']
, write = res.write
, end = res.end
, stream
, method;
// vary
res.setHeader('Vary', 'Accept-Encoding');
// proxy
res.write = function(chunk, encoding){
if (!this.headerSent) this._implicitHeader();
return stream
? stream.write(new Buffer(chunk, encoding))
: write.call(res, chunk, encoding);
};
res.end = function(chunk, encoding){
if (chunk) this.write(chunk, encoding);
return stream
? stream.end()
: end.call(res);
};
res.on('header', function(){
var encoding = res.getHeader('Content-Encoding') || 'identity';
// already encoded
if ('identity' != encoding) return;
// default request filter
if (!filter(req, res)) return;
// SHOULD use identity
if (!accept) return;
// head
if ('HEAD' == req.method) return;
// default to gzip
if ('*' == accept.trim()) method = 'gzip';
// compression method
if (!method) {
for (var i = 0, len = names.length; i < len; ++i) {
if (~accept.indexOf(names[i])) {
method = names[i];
break;
}
}
}
// compression method
if (!method) return;
// compression stream
stream = exports.methods[method](options);
// header fields
res.setHeader('Content-Encoding', method);
res.removeHeader('Content-Length');
// compression
stream.on('data', function(chunk){
write.call(res, chunk);
});
stream.on('end', function(){
end.call(res);
});
stream.on('drain', function() {
res.emit('drain');
});
});
next();
};
};
/*!
* Connect - cookieParser
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var utils = require('./../utils')
, cookie = require('cookie');
/**
* Cookie parser:
*
* Parse _Cookie_ header and populate `req.cookies`
* with an object keyed by the cookie names. Optionally
* you may enabled signed cookie support by passing
* a `secret` string, which assigns `req.secret` so
* it may be used by other middleware.
*
* Examples:
*
* connect()
* .use(connect.cookieParser('optional secret string'))
* .use(function(req, res, next){
* res.end(JSON.stringify(req.cookies));
* })
*
* @param {String} secret
* @return {Function}
* @api public
*/
module.exports = function cookieParser(secret){
return function cookieParser(req, res, next) {
if (req.cookies) return next();
var cookies = req.headers.cookie;
req.secret = secret;
req.cookies = {};
req.signedCookies = {};
if (cookies) {
try {
req.cookies = cookie.parse(cookies);
if (secret) {
req.signedCookies = utils.parseSignedCookies(req.cookies, secret);
req.signedCookies = utils.parseJSONCookies(req.signedCookies);
}
req.cookies = utils.parseJSONCookies(req.cookies);
} catch (err) {
err.status = 400;
return next(err);
}
}
next();
};
};
/*!
* Connect - cookieSession
* Copyright(c) 2011 Sencha Inc.
* MIT Licensed
*/
/**
* Module dependencies.
*/
var utils = require('./../utils')
, Cookie = require('./session/cookie')
, debug = require('debug')('connect:cookieSession')
, signature = require('cookie-signature')
, crc32 = require('buffer-crc32');
/**
* Cookie Session:
*
* Cookie session middleware.
*
* var app = connect();
* app.use(connect.cookieParser());
* app.use(connect.cookieSession({ secret: 'tobo!', cookie: { maxAge: 60 * 60 * 1000 }}));
*
* Options:
*
* - `key` cookie name defaulting to `connect.sess`
* - `secret` prevents cookie tampering
* - `cookie` session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: null }`
* - `proxy` trust the reverse proxy when setting secure cookies (via "x-forwarded-proto")
*
* Clearing sessions:
*
* To clear the session simply set its value to `null`,
* `cookieSession()` will then respond with a 1970 Set-Cookie.
*
* req.session = null;
*
* @param {Object} options
* @return {Function}
* @api public
*/
module.exports = function cookieSession(options){
// TODO: utilize Session/Cookie to unify API
options = options || {};
var key = options.key || 'connect.sess'
, trustProxy = options.proxy;
return function cookieSession(req, res, next) {
// req.secret is for backwards compatibility
var secret = options.secret || req.secret;
if (!secret) throw new Error('`secret` option required for cookie sessions');
// default session
req.session = {};
var cookie = req.session.cookie = new Cookie(options.cookie);
// pathname mismatch
if (0 != req.originalUrl.indexOf(cookie.path)) return next();
// cookieParser secret
if (!options.secret && req.secret) {
req.session = req.signedCookies[key] || {};
} else {
// TODO: refactor
var rawCookie = req.cookies[key];
if (rawCookie) {
var unsigned = utils.parseSignedCookie(rawCookie, secret);
if (unsigned) {
var originalHash = crc32.signed(unsigned);
req.session = utils.parseJSONCookie(unsigned) || {};
}
}
}
res.on('header', function(){
// removed
if (!req.session) {
debug('clear session');
cookie.expires = new Date(0);
res.setHeader('Set-Cookie', cookie.serialize(key, ''));
return;
}
delete req.session.cookie;
// check security
var proto = (req.headers['x-forwarded-proto'] || '').toLowerCase()
, tls = req.connection.encrypted || (trustProxy && 'https' == proto)
, secured = cookie.secure && tls;
// only send secure cookies via https
if (cookie.secure && !secured) return debug('not secured');
// serialize
debug('serializing %j', req.session);
var val = 'j:' + JSON.stringify(req.session);
// compare hashes, no need to set-cookie if unchanged
if (originalHash == crc32.signed(val)) return debug('unmodified session');
// set-cookie
val = 's:' + signature.sign(val, secret);
val = cookie.serialize(key, val);
debug('set-cookie %j', cookie);
res.setHeader('Set-Cookie', val);
});
next();
};
};
/*!
* Connect - csrf
* Copyright(c) 2011 Sencha Inc.
* MIT Licensed
*/
/**
* Module dependencies.
*/
var utils = require('../utils');
/**
* Anti CSRF:
*
* CRSF protection middleware.
*
* By default this middleware generates a token named "_csrf"
* which should be added to requests which mutate
* state, within a hidden form field, query-string etc. This
* token is validated against the visitor's `req.session._csrf`
* property.
*
* The default `value` function checks `req.body` generated
* by the `bodyParser()` middleware, `req.query` generated
* by `query()`, and the "X-CSRF-Token" header field.
*
* This middleware requires session support, thus should be added
* somewhere _below_ `session()` and `cookieParser()`.
*
* Options:
*
* - `value` a function accepting the request, returning the token
*
* @param {Object} options
* @api public
*/
module.exports = function csrf(options) {
options = options || {};
var value = options.value || defaultValue;
return function(req, res, next){
// generate CSRF token
var token = req.session._csrf || (req.session._csrf = utils.uid(24));
// ignore these methods
if ('GET' == req.method || 'HEAD' == req.method || 'OPTIONS' == req.method) return next();
// determine value
var val = value(req);
// check
if (val != token) return next(403);
next();
}
};
/**
* Default value function, checking the `req.body`
* and `req.query` for the CSRF token.
*
* @param {IncomingMessage} req
* @return {String}
* @api private
*/
function defaultValue(req) {
return (req.body && req.body._csrf)
|| (req.query && req.query._csrf)
|| (req.headers['x-csrf-token']);
}
/*!
* Connect - directory
* Copyright(c) 2011 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
// TODO: icon / style for directories
// TODO: arrow key navigation
// TODO: make icons extensible
/**
* Module dependencies.
*/
var fs = require('fs')
, parse = require('url').parse
, path = require('path')
, normalize = path.normalize
, extname = path.extname
, join = path.join;
/*!
* Icon cache.
*/
var cache = {};
/**
* Directory:
*
* Serve directory listings with the given `root` path.
*
* Options:
*
* - `hidden` display hidden (dot) files. Defaults to false.
* - `icons` display icons. Defaults to false.
* - `filter` Apply this filter function to files. Defaults to false.
*
* @param {String} root
* @param {Object} options
* @return {Function}
* @api public
*/
exports = module.exports = function directory(root, options){
options = options || {};
// root required
if (!root) throw new Error('directory() root path required');
var hidden = options.hidden
, icons = options.icons
, filter = options.filter
, root = normalize(root);
return function directory(req, res, next) {
if ('GET' != req.method && 'HEAD' != req.method) return next();
var accept = req.headers.accept || 'text/plain'
, url = parse(req.url)
, dir = decodeURIComponent(url.pathname)
, path = normalize(join(root, dir))
, originalUrl = parse(req.originalUrl)
, originalDir = decodeURIComponent(originalUrl.pathname)
, showUp = path != root && path != root + '/';
// null byte(s), bad request
if (~path.indexOf('\0')) return next(400);
// malicious path, forbidden
if (0 != path.indexOf(root)) return next(403);
// check if we have a directory
fs.stat(path, function(err, stat){
if (err) return 'ENOENT' == err.code
? next()
: next(err);
if (!stat.isDirectory()) return next();
// fetch files
fs.readdir(path, function(err, files){
if (err) return next(err);
if (!hidden) files = removeHidden(files);
if (filter) files = files.filter(filter);
files.sort();
// content-negotiation
for (var key in exports) {
if (~accept.indexOf(key) || ~accept.indexOf('*/*')) {
exports[key](req, res, files, next, originalDir, showUp, icons);
return;
}
}
// not acceptable
next(406);
});
});
};
};
/**
* Respond with text/html.
*/
exports.html = function(req, res, files, next, dir, showUp, icons){
fs.readFile(__dirname + '/../public/directory.html', 'utf8', function(err, str){
if (err) return next(err);
fs.readFile(__dirname + '/../public/style.css', 'utf8', function(err, style){
if (err) return next(err);
if (showUp) files.unshift('..');
str = str
.replace('{style}', style)
.replace('{files}', html(files, dir, icons))
.replace('{directory}', dir)
.replace('{linked-path}', htmlPath(dir));
res.setHeader('Content-Type', 'text/html');
res.setHeader('Content-Length', str.length);
res.end(str);
});
});
};
/**
* Respond with application/json.
*/
exports.json = function(req, res, files){
files = JSON.stringify(files);
res.setHeader('Content-Type', 'application/json');
res.setHeader('Content-Length', files.length);
res.end(files);
};
/**
* Respond with text/plain.
*/
exports.plain = function(req, res, files){
files = files.join('\n') + '\n';
res.setHeader('Content-Type', 'text/plain');
res.setHeader('Content-Length', files.length);
res.end(files);
};
/**
* Map html `dir`, returning a linked path.
*/
function htmlPath(dir) {
var curr = [];
return dir.split('/').map(function(part){
curr.push(part);
return '<a href="' + curr.join('/') + '">' + part + '</a>';
}).join(' / ');
}
/**
* Map html `files`, returning an html unordered list.
*/
function html(files, dir, useIcons) {
return '<ul id="files">' + files.map(function(file){
var icon = ''
, classes = [];
if (useIcons && '..' != file) {
icon = icons[extname(file)] || icons.default;
icon = '<img src="data:image/png;base64,' + load(icon) + '" />';
classes.push('icon');
}
return '<li><a href="'
+ join(dir, file)
+ '" class="'
+ classes.join(' ') + '"'
+ ' title="' + file + '">'
+ icon + file + '</a></li>';
}).join('\n') + '</ul>';
}
/**
* Load and cache the given `icon`.
*
* @param {String} icon
* @return {String}
* @api private
*/
function load(icon) {
if (cache[icon]) return cache[icon];
return cache[icon] = fs.readFileSync(__dirname + '/../public/icons/' + icon, 'base64');
}
/**
* Filter "hidden" `files`, aka files
* beginning with a `.`.
*
* @param {Array} files
* @return {Array}
* @api private
*/
function removeHidden(files) {
return files.filter(function(file){
return '.' != file[0];
});
}
/**
* Icon map.
*/
var icons = {
'.js': 'page_white_code_red.png'
, '.c': 'page_white_c.png'
, '.h': 'page_white_h.png'
, '.cc': 'page_white_cplusplus.png'
, '.php': 'page_white_php.png'
, '.rb': 'page_white_ruby.png'
, '.cpp': 'page_white_cplusplus.png'
, '.swf': 'page_white_flash.png'
, '.pdf': 'page_white_acrobat.png'
, 'default': 'page_white.png'
};
/*!
* Connect - errorHandler
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var utils = require('../utils')
, fs = require('fs');
// environment
var env = process.env.NODE_ENV || 'development';
/**
* Error handler:
*
* Development error handler, providing stack traces
* and error message responses for requests accepting text, html,
* or json.
*
* Text:
*
* By default, and when _text/plain_ is accepted a simple stack trace
* or error message will be returned.
*
* JSON:
*
* When _application/json_ is accepted, connect will respond with
* an object in the form of `{ "error": error }`.
*
* HTML:
*
* When accepted connect will output a nice html stack trace.
*
* @return {Function}
* @api public
*/
exports = module.exports = function errorHandler(){
return function errorHandler(err, req, res, next){
if (err.status) res.statusCode = err.status;
if (res.statusCode < 400) res.statusCode = 500;
if ('test' != env) console.error(err.stack);
var accept = req.headers.accept || '';
// html
if (~accept.indexOf('html')) {
fs.readFile(__dirname + '/../public/style.css', 'utf8', function(e, style){
fs.readFile(__dirname + '/../public/error.html', 'utf8', function(e, html){
var stack = (err.stack || '')
.split('\n').slice(1)
.map(function(v){ return '<li>' + v + '</li>'; }).join('');
html = html
.replace('{style}', style)
.replace('{stack}', stack)
.replace('{title}', exports.title)
.replace('{statusCode}', res.statusCode)
.replace(/\{error\}/g, utils.escape(err.toString()));
res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.end(html);
});
});
// json
} else if (~accept.indexOf('json')) {
var error = { message: err.message, stack: err.stack };
for (var prop in err) error[prop] = err[prop];
var json = JSON.stringify({ error: error });
res.setHeader('Content-Type', 'application/json');
res.end(json);
// plain text
} else {
res.writeHead(res.statusCode, { 'Content-Type': 'text/plain' });
res.end(err.stack);
}
};
};
/**
* Template title, framework authors may override this value.
*/
exports.title = 'Connect';
/*!
* Connect - favicon
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var fs = require('fs')
, utils = require('../utils');
/**
* Favicon:
*
* By default serves the connect favicon, or the favicon
* located by the given `path`.
*
* Options:
*
* - `maxAge` cache-control max-age directive, defaulting to 1 day
*
* Examples:
*
* Serve default favicon:
*
* connect()
* .use(connect.favicon())
*
* Serve favicon before logging for brevity:
*
* connect()
* .use(connect.favicon())
* .use(connect.logger('dev'))
*
* Serve custom favicon:
*
* connect()
* .use(connect.favicon('public/favicon.ico))
*
* @param {String} path
* @param {Object} options
* @return {Function}
* @api public
*/
module.exports = function favicon(path, options){
var options = options || {}
, path = path || __dirname + '/../public/favicon.ico'
, maxAge = options.maxAge || 86400000
, icon; // favicon cache
return function favicon(req, res, next){
if ('/favicon.ico' == req.url) {
if (icon) {
res.writeHead(200, icon.headers);
res.end(icon.body);
} else {
fs.readFile(path, function(err, buf){
if (err) return next(err);
icon = {
headers: {
'Content-Type': 'image/x-icon'
, 'Content-Length': buf.length
, 'ETag': '"' + utils.md5(buf) + '"'
, 'Cache-Control': 'public, max-age=' + (maxAge / 1000)
},
body: buf
};
res.writeHead(200, icon.headers);
res.end(icon.body);
});
}
} else {
next();
}
};
};
/*!
* Connect - json
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var utils = require('../utils')
, _limit = require('./limit');
/**
* noop middleware.
*/
function noop(req, res, next) {
next();
}
/**
* JSON:
*
* Parse JSON request bodies, providing the
* parsed object as `req.body`.
*
* Options:
*
* - `strict` when `false` anything `JSON.parse()` accepts will be parsed
* - `reviver` used as the second "reviver" argument for JSON.parse
* - `limit` byte limit disabled by default
*
* @param {Object} options
* @return {Function}
* @api public
*/
exports = module.exports = function(options){
var options = options || {}
, strict = options.strict !== false;
var limit = options.limit
? _limit(options.limit)
: noop;
return function json(req, res, next) {
if (req._body) return next();
req.body = req.body || {};
if (!utils.hasBody(req)) return next();
// check Content-Type
if ('application/json' != utils.mime(req)) return next();
// flag as parsed
req._body = true;
// parse
limit(req, res, function(err){
if (err) return next(err);
var buf = '';
req.setEncoding('utf8');
req.on('data', function(chunk){ buf += chunk });
req.on('end', function(){
var first = buf.trim()[0];
if (0 == buf.length) {
return next(400, 'invalid json, empty body');
}
if (strict && '{' != first && '[' != first) return next(400, 'invalid json');
try {
req.body = JSON.parse(buf, options.reviver);
next();
} catch (err){
err.body = buf;
err.status = 400;
next(err);
}
});
});
}
};
/*!
* Connect - limit
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var utils = require('../utils');
/**
* Limit:
*
* Limit request bodies to the given size in `bytes`.
*
* A string representation of the bytesize may also be passed,
* for example "5mb", "200kb", "1gb", etc.
*
* connect()
* .use(connect.limit('5.5mb'))
* .use(handleImageUpload)
*
* @param {Number|String} bytes
* @return {Function}
* @api public
*/
module.exports = function limit(bytes){
if ('string' == typeof bytes) bytes = utils.parseBytes(bytes);
if ('number' != typeof bytes) throw new Error('limit() bytes required');
return function limit(req, res, next){
var received = 0
, len = req.headers['content-length']
? parseInt(req.headers['content-length'], 10)
: null;
// self-awareness
if (req._limit) return next();
req._limit = true;
// limit by content-length
if (len && len > bytes) return next(413);
// limit
req.on('data', function(chunk){
received += chunk.length;
if (received > bytes) req.destroy();
});
next();
};
};
/*!
* Connect - logger
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var bytes = require('bytes');
/*!
* Log buffer.
*/
var buf = [];
/*!
* Default log buffer duration.
*/
var defaultBufferDuration = 1000;
/**
* Logger:
*
* Log requests with the given `options` or a `format` string.
*
* Options:
*
* - `format` Format string, see below for tokens
* - `stream` Output stream, defaults to _stdout_
* - `buffer` Buffer duration, defaults to 1000ms when _true_
* - `immediate` Write log line on request instead of response (for response times)
*
* Tokens:
*
* - `:req[header]` ex: `:req[Accept]`
* - `:res[header]` ex: `:res[Content-Length]`
* - `:http-version`
* - `:response-time`
* - `:remote-addr`
* - `:date`
* - `:method`
* - `:url`
* - `:referrer`
* - `:user-agent`
* - `:status`
*
* Formats:
*
* Pre-defined formats that ship with connect:
*
* - `default` ':remote-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"'
* - `short` ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms'
* - `tiny` ':method :url :status :res[content-length] - :response-time ms'
* - `dev` concise output colored by response status for development use
*
* Examples:
*
* connect.logger() // default
* connect.logger('short')
* connect.logger('tiny')
* connect.logger({ immediate: true, format: 'dev' })
* connect.logger(':method :url - :referrer')
* connect.logger(':req[content-type] -> :res[content-type]')
* connect.logger(function(tokens, req, res){ return 'some format string' })
*
* Defining Tokens:
*
* To define a token, simply invoke `connect.logger.token()` with the
* name and a callback function. The value returned is then available
* as ":type" in this case.
*
* connect.logger.token('type', function(req, res){ return req.headers['content-type']; })
*
* Defining Formats:
*
* All default formats are defined this way, however it's public API as well:
*
* connect.logger.format('name', 'string or function')
*
* @param {String|Function|Object} format or options
* @return {Function}
* @api public
*/
exports = module.exports = function logger(options) {
if ('object' == typeof options) {
options = options || {};
} else if (options) {
options = { format: options };
} else {
options = {};
}
// output on request instead of response
var immediate = options.immediate;
// format name
var fmt = exports[options.format] || options.format || exports.default;
// compile format
if ('function' != typeof fmt) fmt = compile(fmt);
// options
var stream = options.stream || process.stdout
, buffer = options.buffer;
// buffering support
if (buffer) {
var realStream = stream
, interval = 'number' == typeof buffer
? buffer
: defaultBufferDuration;
// flush interval
setInterval(function(){
if (buf.length) {
realStream.write(buf.join(''));
buf.length = 0;
}
}, interval);
// swap the stream
stream = {
write: function(str){
buf.push(str);
}
};
}
return function logger(req, res, next) {
req._startTime = new Date;
// immediate
if (immediate) {
var line = fmt(exports, req, res);
if (null == line) return;
stream.write(line + '\n');
// proxy end to output logging
} else {
var end = res.end;
res.end = function(chunk, encoding){
res.end = end;
res.end(chunk, encoding);
var line = fmt(exports, req, res);
if (null == line) return;
stream.write(line + '\n');
};
}
next();
};
};
/**
* Compile `fmt` into a function.
*
* @param {String} fmt
* @return {Function}
* @api private
*/
function compile(fmt) {
fmt = fmt.replace(/"/g, '\\"');
var js = ' return "' + fmt.replace(/:([-\w]{2,})(?:\[([^\]]+)\])?/g, function(_, name, arg){
return '"\n + (tokens["' + name + '"](req, res, "' + arg + '") || "-") + "';
}) + '";'
return new Function('tokens, req, res', js);
};
/**
* Define a token function with the given `name`,
* and callback `fn(req, res)`.
*
* @param {String} name
* @param {Function} fn
* @return {Object} exports for chaining
* @api public
*/
exports.token = function(name, fn) {
exports[name] = fn;
return this;
};
/**
* Define a `fmt` with the given `name`.
*
* @param {String} name
* @param {String|Function} fmt
* @return {Object} exports for chaining
* @api public
*/
exports.format = function(name, str){
exports[name] = str;
return this;
};
/**
* Default format.
*/
exports.format('default', ':remote-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"');
/**
* Short format.
*/
exports.format('short', ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms');
/**
* Tiny format.
*/
exports.format('tiny', ':method :url :status :res[content-length] - :response-time ms');
/**
* dev (colored)
*/
exports.format('dev', function(tokens, req, res){
var status = res.statusCode
, len = parseInt(res.getHeader('Content-Length'), 10)
, color = 32;
if (status >= 500) color = 31
else if (status >= 400) color = 33
else if (status >= 300) color = 36;
len = isNaN(len)
? ''
: len = ' - ' + bytes(len);
return '\033[90m' + req.method
+ ' ' + req.originalUrl + ' '
+ '\033[' + color + 'm' + res.statusCode
+ ' \033[90m'
+ (new Date - req._startTime)
+ 'ms' + len
+ '\033[0m';
});
/**
* request url
*/
exports.token('url', function(req){
return req.originalUrl || req.url;
});
/**
* request method
*/
exports.token('method', function(req){
return req.method;
});
/**
* response time in milliseconds
*/
exports.token('response-time', function(req){
return new Date - req._startTime;
});
/**
* UTC date
*/
exports.token('date', function(){
return new Date().toUTCString();
});
/**
* response status code
*/
exports.token('status', function(req, res){
return res.statusCode;
});
/**
* normalized referrer
*/
exports.token('referrer', function(req){
return req.headers['referer'] || req.headers['referrer'];
});
/**
* remote address
*/
exports.token('remote-addr', function(req){
if (req.ip) return req.ip;
var sock = req.socket;
if (sock.socket) return sock.socket.remoteAddress;
return sock.remoteAddress;
});
/**
* HTTP version
*/
exports.token('http-version', function(req){
return req.httpVersionMajor + '.' + req.httpVersionMinor;
});
/**
* UA string
*/
exports.token('user-agent', function(req){
return req.headers['user-agent'];
});
/**
* request header
*/
exports.token('req', function(req, res, field){
return req.headers[field.toLowerCase()];
});
/**
* response header
*/
exports.token('res', function(req, res, field){
return (res._headers || {})[field.toLowerCase()];
});
/*!
* Connect - methodOverride
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Method Override:
*
* Provides faux HTTP method support.
*
* Pass an optional `key` to use when checking for
* a method override, othewise defaults to _\_method_.
* The original method is available via `req.originalMethod`.
*
* @param {String} key
* @return {Function}
* @api public
*/
module.exports = function methodOverride(key){
key = key || "_method";
return function methodOverride(req, res, next) {
req.originalMethod = req.originalMethod || req.method;
// req.body
if (req.body && key in req.body) {
req.method = req.body[key].toUpperCase();
delete req.body[key];
// check X-HTTP-Method-Override
} else if (req.headers['x-http-method-override']) {
req.method = req.headers['x-http-method-override'].toUpperCase();
}
next();
};
};
/*!
* Connect - multipart
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var formidable = require('formidable')
, _limit = require('./limit')
, utils = require('../utils')
, qs = require('qs');
/**
* noop middleware.
*/
function noop(req, res, next) {
next();
}
/**
* Multipart:
*
* Parse multipart/form-data request bodies,
* providing the parsed object as `req.body`
* and `req.files`.
*
* Configuration:
*
* The options passed are merged with [formidable](https://github.com/felixge/node-formidable)'s
* `IncomingForm` object, allowing you to configure the upload directory,
* size limits, etc. For example if you wish to change the upload dir do the following.
*
* app.use(connect.multipart({ uploadDir: path }));
*
* Options:
*
* - `limit` byte limit defaulting to none
* - `defer` defers processing and exposes the Formidable form object as `req.form`.
* `next()` is called without waiting for the form's "end" event.
* This option is useful if you need to bind to the "progress" event, for example.
*
* @param {Object} options
* @return {Function}
* @api public
*/
exports = module.exports = function(options){
options = options || {};
var limit = options.limit
? _limit(options.limit)
: noop;
return function multipart(req, res, next) {
if (req._body) return next();
req.body = req.body || {};
req.files = req.files || {};
if (!utils.hasBody(req)) return next();
// ignore GET
if ('GET' == req.method || 'HEAD' == req.method) return next();
// check Content-Type
if ('multipart/form-data' != utils.mime(req)) return next();
// flag as parsed
req._body = true;
// parse
limit(req, res, function(err){
if (err) return next(err);
var form = new formidable.IncomingForm
, data = {}
, files = {}
, done;
Object.keys(options).forEach(function(key){
form[key] = options[key];
});
function ondata(name, val, data){
if (Array.isArray(data[name])) {
data[name].push(val);
} else if (data[name]) {
data[name] = [data[name], val];
} else {
data[name] = val;
}
}
form.on('field', function(name, val){
ondata(name, val, data);
});
form.on('file', function(name, val){
ondata(name, val, files);
});
form.on('error', function(err){
if (!options.defer) {
err.status = 400;
next(err);
}
done = true;
});
form.on('end', function(){
if (done) return;
try {
req.body = qs.parse(data);
req.files = qs.parse(files);
if (!options.defer) next();
} catch (err) {
form.emit('error', err);
}
});
form.parse(req);
if (options.defer) {
req.form = form;
next();
}
});
}
};
/*!
* Connect - query
* Copyright(c) 2011 TJ Holowaychuk
* Copyright(c) 2011 Sencha Inc.
* MIT Licensed
*/
/**
* Module dependencies.
*/
var qs = require('qs')
, parse = require('../utils').parseUrl;
/**
* Query:
*
* Automatically parse the query-string when available,
* populating the `req.query` object.
*
* Examples:
*
* connect()
* .use(connect.query())
* .use(function(req, res){
* res.end(JSON.stringify(req.query));
* });
*
* The `options` passed are provided to qs.parse function.
*
* @param {Object} options
* @return {Function}
* @api public
*/
module.exports = function query(options){
return function query(req, res, next){
if (!req.query) {
req.query = ~req.url.indexOf('?')
? qs.parse(parse(req).query, options)
: {};
}
next();
};
};
/*!
* Connect - responseTime
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Reponse time:
*
* Adds the `X-Response-Time` header displaying the response
* duration in milliseconds.
*
* @return {Function}
* @api public
*/
module.exports = function responseTime(){
return function(req, res, next){
var start = new Date;
if (res._responseTime) return next();
res._responseTime = true;
res.on('header', function(){
var duration = new Date - start;
res.setHeader('X-Response-Time', duration + 'ms');
});
next();
};
};
/*!
* Connect - session
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Session = require('./session/session')
, debug = require('debug')('connect:session')
, MemoryStore = require('./session/memory')
, signature = require('cookie-signature')
, Cookie = require('./session/cookie')
, Store = require('./session/store')
, utils = require('./../utils')
, parse = utils.parseUrl
, crc32 = require('buffer-crc32');
// environment
var env = process.env.NODE_ENV;
/**
* Expose the middleware.
*/
exports = module.exports = session;
/**
* Expose constructors.
*/
exports.Store = Store;
exports.Cookie = Cookie;
exports.Session = Session;
exports.MemoryStore = MemoryStore;
/**
* Warning message for `MemoryStore` usage in production.
*/
var warning = 'Warning: connection.session() MemoryStore is not\n'
+ 'designed for a production environment, as it will leak\n'
+ 'memory, and will not scale past a single process.';
/**
* Session:
*
* Setup session store with the given `options`.
*
* Session data is _not_ saved in the cookie itself, however
* cookies are used, so we must use the [cookieParser()](cookieParser.html)
* middleware _before_ `session()`.
*
* Examples:
*
* connect()
* .use(connect.cookieParser())
* .use(connect.session({ secret: 'keyboard cat', key: 'sid', cookie: { secure: true }}))
*
* Options:
*
* - `key` cookie name defaulting to `connect.sid`
* - `store` session store instance
* - `secret` session cookie is signed with this secret to prevent tampering
* - `cookie` session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: null }`
* - `proxy` trust the reverse proxy when setting secure cookies (via "x-forwarded-proto")
*
* Cookie option:
*
* By default `cookie.maxAge` is `null`, meaning no "expires" parameter is set
* so the cookie becomes a browser-session cookie. When the user closes the
* browser the cookie (and session) will be removed.
*
* ## req.session
*
* To store or access session data, simply use the request property `req.session`,
* which is (generally) serialized as JSON by the store, so nested objects
* are typically fine. For example below is a user-specific view counter:
*
* connect()
* .use(connect.favicon())
* .use(connect.cookieParser())
* .use(connect.session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }}))
* .use(function(req, res, next){
* var sess = req.session;
* if (sess.views) {
* res.setHeader('Content-Type', 'text/html');
* res.write('<p>views: ' + sess.views + '</p>');
* res.write('<p>expires in: ' + (sess.cookie.maxAge / 1000) + 's</p>');
* res.end();
* sess.views++;
* } else {
* sess.views = 1;
* res.end('welcome to the session demo. refresh!');
* }
* }
* )).listen(3000);
*
* ## Session#regenerate()
*
* To regenerate the session simply invoke the method, once complete
* a new SID and `Session` instance will be initialized at `req.session`.
*
* req.session.regenerate(function(err){
* // will have a new session here
* });
*
* ## Session#destroy()
*
* Destroys the session, removing `req.session`, will be re-generated next request.
*
* req.session.destroy(function(err){
* // cannot access session here
* });
*
* ## Session#reload()
*
* Reloads the session data.
*
* req.session.reload(function(err){
* // session updated
* });
*
* ## Session#save()
*
* Save the session.
*
* req.session.save(function(err){
* // session saved
* });
*
* ## Session#touch()
*
* Updates the `.maxAge` property. Typically this is
* not necessary to call, as the session middleware does this for you.
*
* ## Session#cookie
*
* Each session has a unique cookie object accompany it. This allows
* you to alter the session cookie per visitor. For example we can
* set `req.session.cookie.expires` to `false` to enable the cookie
* to remain for only the duration of the user-agent.
*
* ## Session#maxAge
*
* Alternatively `req.session.cookie.maxAge` will return the time
* remaining in milliseconds, which we may also re-assign a new value
* to adjust the `.expires` property appropriately. The following
* are essentially equivalent
*
* var hour = 3600000;
* req.session.cookie.expires = new Date(Date.now() + hour);
* req.session.cookie.maxAge = hour;
*
* For example when `maxAge` is set to `60000` (one minute), and 30 seconds
* has elapsed it will return `30000` until the current request has completed,
* at which time `req.session.touch()` is called to reset `req.session.maxAge`
* to its original value.
*
* req.session.cookie.maxAge;
* // => 30000
*
* Session Store Implementation:
*
* Every session store _must_ implement the following methods
*
* - `.get(sid, callback)`
* - `.set(sid, session, callback)`
* - `.destroy(sid, callback)`
*
* Recommended methods include, but are not limited to:
*
* - `.length(callback)`
* - `.clear(callback)`
*
* For an example implementation view the [connect-redis](http://github.com/visionmedia/connect-redis) repo.
*
* @param {Object} options
* @return {Function}
* @api public
*/
function session(options){
var options = options || {}
, key = options.key || 'connect.sid'
, store = options.store || new MemoryStore
, cookie = options.cookie || {}
, trustProxy = options.proxy
, storeReady = true;
// notify user that this store is not
// meant for a production environment
if ('production' == env && store instanceof MemoryStore) {
console.warn(warning);
}
// generates the new session
store.generate = function(req){
req.sessionID = utils.uid(24);
req.session = new Session(req);
req.session.cookie = new Cookie(cookie);
};
store.on('disconnect', function(){ storeReady = false; });
store.on('connect', function(){ storeReady = true; });
return function session(req, res, next) {
// self-awareness
if (req.session) return next();
// Handle connection as if there is no session if
// the store has temporarily disconnected etc
if (!storeReady) return debug('store is disconnected'), next();
// pathname mismatch
if (0 != req.originalUrl.indexOf(cookie.path || '/')) return next();
// backwards compatibility for signed cookies
// req.secret is passed from the cookie parser middleware
var secret = options.secret || req.secret;
// ensure secret is available or bail
if (!secret) throw new Error('`secret` option required for sessions');
// parse url
var originalHash
, originalId;
// expose store
req.sessionStore = store;
// grab the session cookie value and check the signature
var rawCookie = req.cookies[key];
// get signedCookies for backwards compat with signed cookies
var unsignedCookie = req.signedCookies[key];
if (!unsignedCookie && rawCookie) {
unsignedCookie = utils.parseSignedCookie(rawCookie, secret);
}
// set-cookie
res.on('header', function(){
if (!req.session) return;
var cookie = req.session.cookie
, proto = (req.headers['x-forwarded-proto'] || '').toLowerCase()
, tls = req.connection.encrypted || (trustProxy && 'https' == proto)
, secured = cookie.secure && tls
, isNew = unsignedCookie != req.sessionID;
// only send secure cookies via https
if (cookie.secure && !secured) return debug('not secured');
// browser-session length cookie
if (null == cookie.expires) {
if (!isNew) return debug('already set browser-session cookie');
// compare hashes and ids
} else if (originalHash == hash(req.session) && originalId == req.session.id) {
return debug('unmodified session');
}
var val = 's:' + signature.sign(req.sessionID, secret);
val = cookie.serialize(key, val);
debug('set-cookie %s', val);
res.setHeader('Set-Cookie', val);
});
// proxy end() to commit the session
var end = res.end;
res.end = function(data, encoding){
res.end = end;
if (!req.session) return res.end(data, encoding);
debug('saving');
req.session.resetMaxAge();
req.session.save(function(){
debug('saved');
res.end(data, encoding);
});
};
// generate the session
function generate() {
store.generate(req);
}
// get the sessionID from the cookie
req.sessionID = unsignedCookie;
// generate a session if the browser doesn't send a sessionID
if (!req.sessionID) {
debug('no SID sent, generating session');
generate();
next();
return;
}
// generate the session object
var pause = utils.pause(req);
debug('fetching %s', req.sessionID);
store.get(req.sessionID, function(err, sess){
// proxy to resume() events
var _next = next;
next = function(err){
_next(err);
pause.resume();
};
// error handling
if (err) {
debug('error');
if ('ENOENT' == err.code) {
generate();
next();
} else {
next(err);
}
// no session
} else if (!sess) {
debug('no session found');
generate();
next();
// populate req.session
} else {
debug('session found');
store.createSession(req, sess);
originalId = req.sessionID;
originalHash = hash(sess);
next();
}
});
};
};
/**
* Hash the given `sess` object omitting changes
* to `.cookie`.
*
* @param {Object} sess
* @return {String}
* @api private
*/
function hash(sess) {
return crc32.signed(JSON.stringify(sess, function(key, val){
if ('cookie' != key) return val;
}));
}
/*!
* Connect - session - MemoryStore
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Store = require('./store');
/**
* Initialize a new `MemoryStore`.
*
* @api public
*/
var MemoryStore = module.exports = function MemoryStore() {
this.sessions = {};
};
/**
* Inherit from `Store.prototype`.
*/
MemoryStore.prototype.__proto__ = Store.prototype;
/**
* Attempt to fetch session by the given `sid`.
*
* @param {String} sid
* @param {Function} fn
* @api public
*/
MemoryStore.prototype.get = function(sid, fn){
var self = this;
process.nextTick(function(){
var expires
, sess = self.sessions[sid];
if (sess) {
sess = JSON.parse(sess);
expires = 'string' == typeof sess.cookie.expires
? new Date(sess.cookie.expires)
: sess.cookie.expires;
if (!expires || new Date < expires) {
fn(null, sess);
} else {
self.destroy(sid, fn);
}
} else {
fn();
}
});
};
/**
* Commit the given `sess` object associated with the given `sid`.
*
* @param {String} sid
* @param {Session} sess
* @param {Function} fn
* @api public
*/
MemoryStore.prototype.set = function(sid, sess, fn){
var self = this;
process.nextTick(function(){
self.sessions[sid] = JSON.stringify(sess);
fn && fn();
});
};
/**
* Destroy the session associated with the given `sid`.
*
* @param {String} sid
* @api public
*/
MemoryStore.prototype.destroy = function(sid, fn){
var self = this;
process.nextTick(function(){
delete self.sessions[sid];
fn && fn();
});
};
/**
* Invoke the given callback `fn` with all active sessions.
*
* @param {Function} fn
* @api public
*/
MemoryStore.prototype.all = function(fn){
var arr = []
, keys = Object.keys(this.sessions);
for (var i = 0, len = keys.length; i < len; ++i) {
arr.push(this.sessions[keys[i]]);
}
fn(null, arr);
};
/**
* Clear all sessions.
*
* @param {Function} fn
* @api public
*/
MemoryStore.prototype.clear = function(fn){
this.sessions = {};
fn && fn();
};
/**
* Fetch number of sessions.
*
* @param {Function} fn
* @api public
*/
MemoryStore.prototype.length = function(fn){
fn(null, Object.keys(this.sessions).length);
};
/*!
* Connect - session - Session
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var utils = require('../../utils');
/**
* Create a new `Session` with the given request and `data`.
*
* @param {IncomingRequest} req
* @param {Object} data
* @api private
*/
var Session = module.exports = function Session(req, data) {
Object.defineProperty(this, 'req', { value: req });
Object.defineProperty(this, 'id', { value: req.sessionID });
if ('object' == typeof data) utils.merge(this, data);
};
/**
* Update reset `.cookie.maxAge` to prevent
* the cookie from expiring when the
* session is still active.
*
* @return {Session} for chaining
* @api public
*/
Session.prototype.touch = function(){
return this.resetMaxAge();
};
/**
* Reset `.maxAge` to `.originalMaxAge`.
*
* @return {Session} for chaining
* @api public
*/
Session.prototype.resetMaxAge = function(){
this.cookie.maxAge = this.cookie.originalMaxAge;
return this;
};
/**
* Save the session data with optional callback `fn(err)`.
*
* @param {Function} fn
* @return {Session} for chaining
* @api public
*/
Session.prototype.save = function(fn){
this.req.sessionStore.set(this.id, this, fn || function(){});
return this;
};
/**
* Re-loads the session data _without_ altering
* the maxAge properties. Invokes the callback `fn(err)`,
* after which time if no exception has occurred the
* `req.session` property will be a new `Session` object,
* although representing the same session.
*
* @param {Function} fn
* @return {Session} for chaining
* @api public
*/
Session.prototype.reload = function(fn){
var req = this.req
, store = this.req.sessionStore;
store.get(this.id, function(err, sess){
if (err) return fn(err);
if (!sess) return fn(new Error('failed to load session'));
store.createSession(req, sess);
fn();
});
return this;
};
/**
* Destroy `this` session.
*
* @param {Function} fn
* @return {Session} for chaining
* @api public
*/
Session.prototype.destroy = function(fn){
delete this.req.session;
this.req.sessionStore.destroy(this.id, fn);
return this;
};
/**
* Regenerate this request's session.
*
* @param {Function} fn
* @return {Session} for chaining
* @api public
*/
Session.prototype.regenerate = function(fn){
this.req.sessionStore.regenerate(this.req, fn);
return this;
};
/*!
* Connect - session - Store
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var EventEmitter = require('events').EventEmitter
, Session = require('./session')
, Cookie = require('./cookie');
/**
* Initialize abstract `Store`.
*
* @api private
*/
var Store = module.exports = function Store(options){};
/**
* Inherit from `EventEmitter.prototype`.
*/
Store.prototype.__proto__ = EventEmitter.prototype;
/**
* Re-generate the given requests's session.
*
* @param {IncomingRequest} req
* @return {Function} fn
* @api public
*/
Store.prototype.regenerate = function(req, fn){
var self = this;
this.destroy(req.sessionID, function(err){
self.generate(req);
fn(err);
});
};
/**
* Load a `Session` instance via the given `sid`
* and invoke the callback `fn(err, sess)`.
*
* @param {String} sid
* @param {Function} fn
* @api public
*/
Store.prototype.load = function(sid, fn){
var self = this;
this.get(sid, function(err, sess){
if (err) return fn(err);
if (!sess) return fn();
var req = { sessionID: sid, sessionStore: self };
sess = self.createSession(req, sess);
fn(null, sess);
});
};
/**
* Create session from JSON `sess` data.
*
* @param {IncomingRequest} req
* @param {Object} sess
* @return {Session}
* @api private
*/
Store.prototype.createSession = function(req, sess){
var expires = sess.cookie.expires
, orig = sess.cookie.originalMaxAge;
sess.cookie = new Cookie(sess.cookie);
if ('string' == typeof expires) sess.cookie.expires = new Date(expires);
sess.cookie.originalMaxAge = orig;
req.session = new Session(req, sess);
return req.session;
};
/*!
* Connect - static
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var send = require('send')
, utils = require('../utils')
, parse = utils.parseUrl
, url = require('url');
/**
* Static:
*
* Static file server with the given `root` path.
*
* Examples:
*
* var oneDay = 86400000;
*
* connect()
* .use(connect.static(__dirname + '/public'))
*
* connect()
* .use(connect.static(__dirname + '/public', { maxAge: oneDay }))
*
* Options:
*
* - `maxAge` Browser cache maxAge in milliseconds. defaults to 0
* - `hidden` Allow transfer of hidden files. defaults to false
* - `redirect` Redirect to trailing "/" when the pathname is a dir. defaults to true
*
* @param {String} root
* @param {Object} options
* @return {Function}
* @api public
*/
exports = module.exports = function static(root, options){
options = options || {};
// root required
if (!root) throw new Error('static() root path required');
// default redirect
var redirect = false !== options.redirect;
return function static(req, res, next) {
if ('GET' != req.method && 'HEAD' != req.method) return next();
var path = parse(req).pathname;
var pause = utils.pause(req);
function resume() {
next();
pause.resume();
}
function directory() {
if (!redirect) return resume();
var pathname = url.parse(req.originalUrl).pathname;
res.statusCode = 301;
res.setHeader('Location', pathname + '/');
res.end('Redirecting to ' + utils.escape(pathname) + '/');
}
function error(err) {
if (404 == err.status) return resume();
next(err);
}
send(req, path)
.maxage(options.maxAge || 0)
.root(root)
.hidden(options.hidden)
.on('error', error)
.on('directory', directory)
.pipe(res);
};
};
/**
* Expose mime module.
*
* If you wish to extend the mime table use this
* reference to the "mime" module in the npm registry.
*/
exports.mime = send.mime;
/*!
* Connect - staticCache
* Copyright(c) 2011 Sencha Inc.
* MIT Licensed
*/
/**
* Module dependencies.
*/
var utils = require('../utils')
, Cache = require('../cache')
, fresh = require('fresh');
/**
* Static cache:
*
* Enables a memory cache layer on top of
* the `static()` middleware, serving popular
* static files.
*
* By default a maximum of 128 objects are
* held in cache, with a max of 256k each,
* totalling ~32mb.
*
* A Least-Recently-Used (LRU) cache algo
* is implemented through the `Cache` object,
* simply rotating cache objects as they are
* hit. This means that increasingly popular
* objects maintain their positions while
* others get shoved out of the stack and
* garbage collected.
*
* Benchmarks:
*
* static(): 2700 rps
* node-static: 5300 rps
* static() + staticCache(): 7500 rps
*
* Options:
*
* - `maxObjects` max cache objects [128]
* - `maxLength` max cache object length 256kb
*
* @param {Object} options
* @return {Function}
* @api public
*/
module.exports = function staticCache(options){
var options = options || {}
, cache = new Cache(options.maxObjects || 128)
, maxlen = options.maxLength || 1024 * 256;
console.warn('connect.staticCache() is deprecated and will be removed in 3.0');
console.warn('use varnish or similar reverse proxy caches.');
return function staticCache(req, res, next){
var key = cacheKey(req)
, ranges = req.headers.range
, hasCookies = req.headers.cookie
, hit = cache.get(key);
// cache static
// TODO: change from staticCache() -> cache()
// and make this work for any request
req.on('static', function(stream){
var headers = res._headers
, cc = utils.parseCacheControl(headers['cache-control'] || '')
, contentLength = headers['content-length']
, hit;
// dont cache set-cookie responses
if (headers['set-cookie']) return hasCookies = true;
// dont cache when cookies are present
if (hasCookies) return;
// ignore larger files
if (!contentLength || contentLength > maxlen) return;
// don't cache partial files
if (headers['content-range']) return;
// dont cache items we shouldn't be
// TODO: real support for must-revalidate / no-cache
if ( cc['no-cache']
|| cc['no-store']
|| cc['private']
|| cc['must-revalidate']) return;
// if already in cache then validate
if (hit = cache.get(key)){
if (headers.etag == hit[0].etag) {
hit[0].date = new Date;
return;
} else {
cache.remove(key);
}
}
// validation notifiactions don't contain a steam
if (null == stream) return;
// add the cache object
var arr = [];
// store the chunks
stream.on('data', function(chunk){
arr.push(chunk);
});
// flag it as complete
stream.on('end', function(){
var cacheEntry = cache.add(key);
delete headers['x-cache']; // Clean up (TODO: others)
cacheEntry.push(200);
cacheEntry.push(headers);
cacheEntry.push.apply(cacheEntry, arr);
});
});
if (req.method == 'GET' || req.method == 'HEAD') {
if (ranges) {
next();
} else if (!hasCookies && hit && !mustRevalidate(req, hit)) {
res.setHeader('X-Cache', 'HIT');
respondFromCache(req, res, hit);
} else {
res.setHeader('X-Cache', 'MISS');
next();
}
} else {
next();
}
}
};
/**
* Respond with the provided cached value.
* TODO: Assume 200 code, that's iffy.
*
* @param {Object} req
* @param {Object} res
* @param {Object} cacheEntry
* @return {String}
* @api private
*/
function respondFromCache(req, res, cacheEntry) {
var status = cacheEntry[0]
, headers = utils.merge({}, cacheEntry[1])
, content = cacheEntry.slice(2);
headers.age = (new Date - new Date(headers.date)) / 1000 || 0;
switch (req.method) {
case 'HEAD':
res.writeHead(status, headers);
res.end();
break;
case 'GET':
if (utils.conditionalGET(req) && fresh(req.headers, headers)) {
headers['content-length'] = 0;
res.writeHead(304, headers);
res.end();
} else {
res.writeHead(status, headers);
function write() {
while (content.length) {
if (false === res.write(content.shift())) {
res.once('drain', write);
return;
}
}
res.end();
}
write();
}
break;
default:
// This should never happen.
res.writeHead(500, '');
res.end();
}
}
/**
* Determine whether or not a cached value must be revalidated.
*
* @param {Object} req
* @param {Object} cacheEntry
* @return {String}
* @api private
*/
function mustRevalidate(req, cacheEntry) {
var cacheHeaders = cacheEntry[1]
, reqCC = utils.parseCacheControl(req.headers['cache-control'] || '')
, cacheCC = utils.parseCacheControl(cacheHeaders['cache-control'] || '')
, cacheAge = (new Date - new Date(cacheHeaders.date)) / 1000 || 0;
if ( cacheCC['no-cache']
|| cacheCC['must-revalidate']
|| cacheCC['proxy-revalidate']) return true;
if (reqCC['no-cache']) return true;
if (null != reqCC['max-age']) return reqCC['max-age'] < cacheAge;
if (null != cacheCC['max-age']) return cacheCC['max-age'] < cacheAge;
return false;
}
/**
* The key to use in the cache. For now, this is the URL path and query.
*
* 'http://example.com?key=value' -> '/?key=value'
*
* @param {Object} req
* @return {String}
* @api private
*/
function cacheKey(req) {
return utils.parseUrl(req).path;
}
/*!
* Connect - timeout
* Ported from https://github.com/LearnBoost/connect-timeout
* MIT Licensed
*/
/**
* Module dependencies.
*/
var debug = require('debug')('connect:timeout');
/**
* Timeout:
*
* Times out the request in `ms`, defaulting to `5000`. The
* method `req.clearTimeout()` is added to revert this behaviour
* programmatically within your application's middleware, routes, etc.
*
* The timeout error is passed to `next()` so that you may customize
* the response behaviour. This error has the `.timeout` property as
* well as `.status == 408`.
*
* @param {Number} ms
* @return {Function}
* @api public
*/
module.exports = function timeout(ms) {
ms = ms || 5000;
return function(req, res, next) {
var id = setTimeout(function(){
req.emit('timeout', ms);
}, ms);
req.on('timeout', function(){
if (req.headerSent) return debug('response started, cannot timeout');
var err = new Error('Response timeout');
err.timeout = ms;
err.status = 503;
next(err);
});
req.clearTimeout = function(){
clearTimeout(id);
};
res.on('header', function(){
clearTimeout(id);
});
next();
};
};
/*!
* Connect - urlencoded
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var utils = require('../utils')
, _limit = require('./limit')
, qs = require('qs');
/**
* noop middleware.
*/
function noop(req, res, next) {
next();
}
/**
* Urlencoded:
*
* Parse x-ww-form-urlencoded request bodies,
* providing the parsed object as `req.body`.
*
* Options:
*
* - `limit` byte limit disabled by default
*
* @param {Object} options
* @return {Function}
* @api public
*/
exports = module.exports = function(options){
options = options || {};
var limit = options.limit
? _limit(options.limit)
: noop;
return function urlencoded(req, res, next) {
if (req._body) return next();
req.body = req.body || {};
if (!utils.hasBody(req)) return next();
// check Content-Type
if ('application/x-www-form-urlencoded' != utils.mime(req)) return next();
// flag as parsed
req._body = true;
// parse
limit(req, res, function(err){
if (err) return next(err);
var buf = '';
req.setEncoding('utf8');
req.on('data', function(chunk){ buf += chunk });
req.on('end', function(){
try {
req.body = buf.length
? qs.parse(buf, options)
: {};
next();
} catch (err){
err.body = buf;
next(err);
}
});
});
}
};
/*!
* Connect - vhost
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Vhost:
*
* Setup vhost for the given `hostname` and `server`.
*
* connect()
* .use(connect.vhost('foo.com', fooApp))
* .use(connect.vhost('bar.com', barApp))
* .use(connect.vhost('*.com', mainApp))
*
* The `server` may be a Connect server or
* a regular Node `http.Server`.
*
* @param {String} hostname
* @param {Server} server
* @return {Function}
* @api public
*/
module.exports = function vhost(hostname, server){
if (!hostname) throw new Error('vhost hostname required');
if (!server) throw new Error('vhost server required');
var regexp = new RegExp('^' + hostname.replace(/[*]/g, '(.*?)') + '$', 'i');
if (server.onvhost) server.onvhost(hostname);
return function vhost(req, res, next){
if (!req.headers.host) return next();
var host = req.headers.host.split(':')[0];
if (!regexp.test(host)) return next();
if ('function' == typeof server) return server(req, res, next);
server.emit('request', req, res);
};
};
/*!
* Connect
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var http = require('http')
, res = http.ServerResponse.prototype
, setHeader = res.setHeader
, _renderHeaders = res._renderHeaders
, writeHead = res.writeHead;
// apply only once
if (!res._hasConnectPatch) {
/**
* Provide a public "header sent" flag
* until node does.
*
* @return {Boolean}
* @api public
*/
res.__defineGetter__('headerSent', function(){
return this._header;
});
/**
* Set header `field` to `val`, special-casing
* the `Set-Cookie` field for multiple support.
*
* @param {String} field
* @param {String} val
* @api public
*/
res.setHeader = function(field, val){
var key = field.toLowerCase()
, prev;
// special-case Set-Cookie
if (this._headers && 'set-cookie' == key) {
if (prev = this.getHeader(field)) {
val = Array.isArray(prev)
? prev.concat(val)
: [prev, val];
}
// charset
} else if ('content-type' == key && this.charset) {
val += '; charset=' + this.charset;
}
return setHeader.call(this, field, val);
};
/**
* Proxy to emit "header" event.
*/
res._renderHeaders = function(){
if (!this._emittedHeader) this.emit('header');
this._emittedHeader = true;
return _renderHeaders.call(this);
};
res.writeHead = function(){
if (!this._emittedHeader) this.emit('header');
this._emittedHeader = true;
return writeHead.apply(this, arguments);
};
res._hasConnectPatch = true;
}
/*!
* Connect - HTTPServer
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var http = require('http')
, utils = require('./utils')
, debug = require('debug')('connect:dispatcher');
// prototype
var app = module.exports = {};
// environment
var env = process.env.NODE_ENV || 'development';
/**
* Utilize the given middleware `handle` to the given `route`,
* defaulting to _/_. This "route" is the mount-point for the
* middleware, when given a value other than _/_ the middleware
* is only effective when that segment is present in the request's
* pathname.
*
* For example if we were to mount a function at _/admin_, it would
* be invoked on _/admin_, and _/admin/settings_, however it would
* not be invoked for _/_, or _/posts_.
*
* Examples:
*
* var app = connect();
* app.use(connect.favicon());
* app.use(connect.logger());
* app.use(connect.static(__dirname + '/public'));
*
* If we wanted to prefix static files with _/public_, we could
* "mount" the `static()` middleware:
*
* app.use('/public', connect.static(__dirname + '/public'));
*
* This api is chainable, so the following is valid:
*
* connect()
* .use(connect.favicon())
* .use(connect.logger())
* .use(connect.static(__dirname + '/public'))
* .listen(3000);
*
* @param {String|Function|Server} route, callback or server
* @param {Function|Server} callback or server
* @return {Server} for chaining
* @api public
*/
app.use = function(route, fn){
// default route to '/'
if ('string' != typeof route) {
fn = route;
route = '/';
}
// wrap sub-apps
if ('function' == typeof fn.handle) {
var server = fn;
fn.route = route;
fn = function(req, res, next){
server.handle(req, res, next);
};
}
// wrap vanilla http.Servers
if (fn instanceof http.Server) {
fn = fn.listeners('request')[0];
}
// strip trailing slash
if ('/' == route[route.length - 1]) {
route = route.slice(0, -1);
}
// add the middleware
debug('use %s %s', route || '/', fn.name || 'anonymous');
this.stack.push({ route: route, handle: fn });
return this;
};
/**
* Handle server requests, punting them down
* the middleware stack.
*
* @api private
*/
app.handle = function(req, res, out) {
var stack = this.stack
, fqdn = ~req.url.indexOf('://')
, removed = ''
, slashAdded = false
, index = 0;
function next(err, msg) {
var layer, path, status, c;
if (slashAdded) {
req.url = req.url.substr(1);
slashAdded = false;
}
req.url = removed + req.url;
req.originalUrl = req.originalUrl || req.url;
removed = '';
// next(status, msg) support
if (typeof err === 'number') {
var status = err;
var name = http.STATUS_CODES[status];
err = new Error(msg || name);
err.name = name;
err.status = status;
}
// next callback
layer = stack[index++];
// all done
if (!layer || res.headerSent) {
// delegate to parent
if (out) return out(err);
// unhandled error
if (err) {
// default to 500
if (res.statusCode < 400) res.statusCode = 500;
debug('default %s', res.statusCode);
// respect err.status
if (err.status) res.statusCode = err.status;
// production gets a basic error message
var msg = 'production' == env
? http.STATUS_CODES[res.statusCode]
: err.stack || err.toString();
// log to stderr in a non-test env
if ('test' != env) console.error(err.stack || err.toString());
if (res.headerSent) return req.socket.destroy();
res.setHeader('Content-Type', 'text/plain');
res.setHeader('Content-Length', Buffer.byteLength(msg));
if ('HEAD' == req.method) return res.end();
res.end(msg);
} else {
debug('default 404');
res.statusCode = 404;
res.setHeader('Content-Type', 'text/plain');
if ('HEAD' == req.method) return res.end();
res.end('Cannot ' + req.method + ' ' + utils.escape(req.originalUrl));
}
return;
}
try {
path = utils.parseUrl(req).pathname;
if (undefined == path) path = '/';
// skip this layer if the route doesn't match.
if (0 != path.toLowerCase().indexOf(layer.route.toLowerCase())) return next(err);
c = path[layer.route.length];
if (c && '/' != c && '.' != c) return next(err);
// Call the layer handler
// Trim off the part of the url that matches the route
removed = layer.route;
req.url = req.url.substr(removed.length);
// Ensure leading slash
if (!fqdn && '/' != req.url[0]) {
req.url = '/' + req.url;
slashAdded = true;
}
debug('%s', layer.handle.name || 'anonymous');
var arity = layer.handle.length;
if (err) {
if (arity === 4) {
layer.handle(err, req, res, next);
} else {
next(err);
}
} else if (arity < 4) {
layer.handle(req, res, next);
} else {
next();
}
} catch (e) {
next(e);
}
}
next();
};
/**
* Listen for connections.
*
* This method takes the same arguments
* as node's `http.Server#listen()`.
*
* HTTP and HTTPS:
*
* If you run your application both as HTTP
* and HTTPS you may wrap them individually,
* since your Connect "server" is really just
* a JavaScript `Function`.
*
* var connect = require('connect')
* , http = require('http')
* , https = require('https');
*
* var app = connect();
*
* http.createServer(app).listen(80);
* https.createServer(options, app).listen(443);
*
* @return {http.Server}
* @api public
*/
app.listen = function(){
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>listing directory {directory}</title>
<style>{style}</style>
<script>
function $(id){
var el = 'string' == typeof id
? document.getElementById(id)
: id;
el.on = function(event, fn){
if ('content loaded' == event) {
event = window.attachEvent ? "load" : "DOMContentLoaded";
}
el.addEventListener
? el.addEventListener(event, fn, false)
: el.attachEvent("on" + event, fn);
};
el.all = function(selector){
return $(el.querySelectorAll(selector));
};
el.each = function(fn){
for (var i = 0, len = el.length; i < len; ++i) {
fn($(el[i]), i);
}
};
el.getClasses = function(){
return this.getAttribute('class').split(/\s+/);
};
el.addClass = function(name){
var classes = this.getAttribute('class');
el.setAttribute('class', classes
? classes + ' ' + name
: name);
};
el.removeClass = function(name){
var classes = this.getClasses().filter(function(curr){
return curr != name;
});
this.setAttribute('class', classes);
};
return el;
}
function search() {
var str = $('search').value
, links = $('files').all('a');
links.each(function(link){
var text = link.textContent;
if ('..' == text) return;
if (str.length && ~text.indexOf(str)) {
link.addClass('highlight');
} else {
link.removeClass('highlight');
}
});
}
$(window).on('content loaded', function(){
$('search').on('keyup', search);
});
</script>
</head>
<body class="directory">
<input id="search" type="text" placeholder="Search" autocomplete="off" />
<div id="wrapper">
<h1>{linked-path}</h1>
{files}
</div>
</body>
</html>
<html>
<head>
<meta charset='utf-8'>
<title>{error}</title>
<style>{style}</style>
</head>
<body>
<div id="wrapper">
<h1>{title}</h1>
<h2><em>{statusCode}</em> {error}</h2>
<ul id="stacktrace">{stack}</ul>
</div>
</body>
</html>
h( ��}@�_�U�C˩��~�6�G�����c�c�<�e�p›l�u4�ơu 
 
     
 
��������������������
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e< IDAT����s���>�{��SG��3�;1Ј���.��bc#61�l��I��AKD"$�X$ �TD�y����UI��ޥ�w�O�6�9�D�B����כ��Y�}���o*��>���'o�{t�:& ���ﱋ����oG�����g��p�fS=�3Og~�jUiִe�[ǫ����;�k�ҏ�x��O���T��$��4ls1 ������w���}�؝��>��``�ʨ2��*c*��u˽��=v���̝���*� �D)��ke���������{���O�y,0CB0��(�4�;�.ݓ�3�*J �4� PC�%# 0C/$4
I��2O!E��6k3tGB��T����%`��YC��am�)6Ӱl0C/щ���*�ER4���\�g��� ˲ZW�7��{谆��$$|u����̰u/�ٮ�+���Jt�(��<W/k/0�������t׻�o�� ���� awS��f�֥�� U��ŷ/�RUODNA8��o��"�D8V5�jIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<uIDAT�M��U��=ߙ;�c�YA!Y؟H*FE�n�Z�)�����U��-K���T�r��Ybj?��D�V�N)��{���<��������f&�*a=� �A6��~[<�_�^:�g� 2Ӷ׏�����ʤ�dB:{i���������:�g�T(]�>��ʅt%� }6�q�2�=����V}��.�vDžw}z�᷶/���� �b�P����fvf`džY��:���L�I@A J��D(JΜ���#w�
�o�^7�=  ��BFh}RB�dq�\��ֆX=)jC�L5��QB ��Z�BP!�A�D6&:@ч,�!���d��LP
Z�]�A�B��P����$)H ��~b�Ԝ��/�G���&�F�d�HВ��:}�so��UkZ����q��7+�qj�^�a(�d��4��'�?�/��g�:x�#�m���;+�ǽ�gvf�}7-�>h�gߞ1+<��Y��#�;��*��Z���^|�g�EJZr�ҿN��G��u�7<c����FW�� /�Ngf�4��˪}��9��6ߵ�܉�Q��0��i�΃;ǣ|<"�M�@�Hi����P�*}k�����'!1f����IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT�K��e���7�{'�P�eD�IF��a&F Q�D�jE���t1�27� !#($o�ٽ ��0�2-%Ǚ��Ή�t�{�O�=T�LB�@Yu�;{:?��<�w˪q��L+7���� �ӓF� ����:��_.����G.۷e�Eh�4q�`�L��M� �J?��K&�^7ͭsZ���)Y�Y��{�~���"b(3���(�ASh��@5cxЪ�3̾�7���H
JP"�%B�P�p�� f M����m�k���d�6��j?)�m���i�vj��hK-d�h�H)%��Ma�RC��T�ZHTDB"���E�C�T� �P;2�d&(5�M������� ���̜���n��{
Ԛ2�$3H �SǏڻs���{��M�]�a����B��O�R$�ɯ?��7͛��������1�=y��` �K5�s�� ��A��_���vݬEvM_��uk<��j�G�ߺnv ]���3cx��+�����ߏ�j�V?M���8��
���'�#�X;��+O�.��՚�}FN����w��m�⯟=�l�[V���w��yk�ȶ�&��6W<s����,������Ο;���=v���׷�ɽ�s�"��O�7"nN9 l4s��^��;�w�[�侱Z����I�? ��NIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT=�Kh�e��������%��!5������ Jt!�dcA�������.7�t�BJp�Ľ A7�Q�X���`�X i�ƙI����s����w���wN��fU8
��Kp#������d�~j��L�]��t=����7�N�ʐC��;���[�\������K#ߟ�iEz4Ƚy C�Tܠp#%g�S����ND~��������_+="���!J��BEc| g��8��+ǁ�J��l�T@EPTA����6w�w�oDx��;Yx1�c(-4iΩ�F��\��`v�F B��� �m �6O��C�&e�C^�<f��@E A� g�6i��,(}y��Jy�� �>�����UW&��k�Q��##�'�d�QP)��?�Y�m�,*y�E�w���}�PZ�wx�H��Zā�r|��Z31^���B��B JaP����.��vF���b��Fwg�V�_� E叵6O�W�T�*J�P$G/}2���R}��u+��Ͼ�Fa0�p�jI������OL ��98�%���tM�����;��n��rx���lބ���h.t��q��sϼ���1K�7���/�S��]��98���������IDzR�,�y�@~\)0q���\5!F�TX��tv��jF�~�]uw���m��r�r&�`Y��E�qw�����d�� "�����������1��
���r;�Q\�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<)IDAT8�u�=hTA������l�nv��B0I%VA�Q��JA0�(Z�������`!��N'Q �e�i��$�Ƹ�w�������L3�c�332v����|t���& �* ���j�y�Tz6?5^�C��G��^��m�� �'gaza��ō7��7n�=�Pm`�HO��veK��#����y=fO�cd���H������N'0
b�2V�X!�1ln�� ' ���\��D ��
j��3�.�>����qk�KE��Nݯ���_4K�'�S�5�� XcZ*JJ#��~�0[�@j��Ӳ�^�~���1<zc�S��v"�@��D�YUV�c��vj�3�݌ �e�ř���NU�0b
V@I׬Kg��&����s]7 jH�o�-'�Z6�%��j�_5%r'jm×��͝l貈��(��f��|���Q#�H���FT AT��D�]��x��)�� ��,���1�@�U��L�k7���Kq�k=�]�CL�O�֥6���H0�:m�������!Қ^��jۀ�w޿�F��V�ڴX%hR.��?��)�zIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<vIDAT�K��e����o��l��4x��FA����EA����hF�R��h.�u�PW��h�`�j"� ATDJQ �6���xΜ�{{��L��~����gJ؆)d�͸�3W.�B\�����{F��v�����l���X�t�LH��-{��+Ο^?��/k�<�gJw j���?�A��>��8--���&;�T߶řlw^~p������=,+2�t�D�]� "(�������6�69]�f߅I@A J��D(J��wɆ��^�߹V7�=  ��BFh}RB�d��4jc��<�yR�2�
�$j)%��@6�+ (-��I�(�B�!��lLt�(�YRC&P��ɤ!����P�$�$���7�Bk)3IR�@��G�Y>��S���1�Xe�
}�O��$hɍ�#�N}ྦྷ�3��K?}b��B����8�L ��A##=}�-���`���x���U6o���_��
�q���u]ђ>郖���[6���༮��
�ak��rԋo��Z��%�Wλ��1�G_4\:�:�]����*,��/���_�w4��E�+�����;}����V� �����I��L��}�o���G��)g$���[?��/������`��/}���� -%nQP`IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT�Oh�u���y�w��9�ge��&"2�&A�:u�Vt�.AA]<L�:����:dE��<Ě�jH3�ܜ��M�������Ia��_�^���"م�H !�U9O.����֍W� ���p��g>9�롢H낆 ��Ҋ?/���}�_'֏ jC E#m�*�Ưi)��LYU��ھ�}��ظx��q`�u��#Rk��RJ���j4$!� d�D!iOn��9�C/��i��m&N{�� A�� DJ�D��)u\�~���'ו:��nһaK A� I"%���wyĖU���־zRWO��؄�wR�D(S�HI�F��^<mK|����Z�}(5oh�����^?����g�
d�D��"%�+_Z���՚V4Wtn�o��y�{�2Ud( WD��}�k=�?���3:��4�B��}fFF���6lWg���CDL��Խ𓕼�ՋGd-���6sn��ޣR��ͤ�Pg� 2�?�𞗭�gĥ/��f��wc�{GճY��(T�
����#��K�����Ww<���ɱI?����+��*pbS�J;���V� �m���?�{���;,=yܣ}�� � �*��J�%T휫��SK�^���&%��HK�D�9)˔�:WP�J��Y�ո뵡Κ�(��]���IJr���*OA )�{O�r���=�@ @+�<ZN���X��WyIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT�K��e���?�� �yi 1+��Z�IH7 "(!*
�Em���m#\D� iэ�p�A��V&�!RV�V�86�s����L����Ʌ#��K؄� ���_.N侘�|���ms���{������tC)1�4�LH�.�{�ۋ�>5{��/�r�Y�Aib�`�=vVS"��eնiz��u�[�{�s��^?y׳�-���g D���l�b�� �BDP���A�6��������[P ((A�P"�%Bi�_��^<o���Ԗ+4�#�Ȥ�BF�]RB�a0��'�\m�:�k�WZ(�I�E�PД0Є^��#V]x�Psق��HTDP"�%Bd�C�?�|�MF�ݣ�+*2��%��Df"����=���hdl���{�gO�*]
Ԛ2�$3��?9���Q�ԧ������7��MP��tIV�JW�jUO�o���qx�;�N�3͞9��kAj�j����R ��?���I�KV�~%���7�l}��_���?zж��cld��+����v�p�z��6=�N�;c�� �������=�U�����5�:�>ݙ:�����Z4|^�D㻏N��3',_���f���Gf��}'��r���s(3��Ǐ�����l'�(����s��w|�i������|0"6�\�ښ�)k���ZeMYk�5K�mdw�+RO�����IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT�M�UU��{���� ���S#
�r�� �-�M��RT�ڄ�K
�E�aBD!�Ѣ�H!j�M �dI�� e�c�yw�9}_�9[�������,G?ȁ��)�v�|8\�|�؞��!��w&�}���%1�Y�B g�.^��w⊿�M�����w{�OA ����b��19�䤮�N���™V�Q:�.�x��W��v���!�9碯��H("E ��d�p����36�(��>��Ԏ�gS�5�B��e㏻|�o~�+�U�Фںe����KZU�ݝ�齓���WU%N����[;�?�~�S'��S۲���nj�vG2j|�ӎ���4m�m-��5Dl���� y��аEw�S�A��^�nw��\[ּoxhD_����EB���M��'{_L�d`����ݢ���� kw�Z�2�+
�2J���n.����]���M�q璻M�&��㐲�*�2e5�&��7nz�Z��j��r����G<k�%��n�Չ<�kL�A�"�U��Dl#�8}�/gЙn|r�#O�=gd�l�7/��֕2R&�*�z��w���͉ξ���/^����/�rb���I!D#�7�"U �7�@ u�hF��ڲv7���^�꩔�2@Y�T7��z���P_1G� 圣L� � g�(�*�M��C !�k��BX��A��,tSJ��h�Y+X�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<IDAT�Kh�U���;��g&�d�&Mh�K��&h�Z��� ��Huݍ�.�U�� ^6"�(���؂��!B���" �bjB�m�$3��d�&M:�̜s>�GT�W?��VK&y��� �p!�m��o��~r��`@T�ß_����C�����*�R��d� �������u�uzp;0V�'"�cfkD@@x 8�Ԛ��{�y�шˡܪ�o�wFw����_w./�,�7���_�t��?=���S� ϋ�)fʊ���E~����j�ή�O:����:5I��������`.;þ�X<J�Mz�ʞ6��=I�O��}���NO[-��W�s��$��� �?�G�l�Y!a 7ׄˋ� 7�$c�Dƙ��g�ת��������(߹K&�ή�ݴ�����"bkH&,��%��Q ��<���v�=�/#CTV�t�%(�����7��s�� [!6B֒� P��=��2��n-�X��2��a
�y^<�r����"��
����s.�';;��j��R�1��7�QX�@D!2�T �)����b~�z�F>�������;\�fY])�V.T�
����(�x����g�8��`O���­ ���U��|v� �*`hwLs; �
���k�'�M}9��CP�
^ ((�
�0��8� �w���\����OE���5� BIp>��Y��t����@#���t�D�BK,�b+[ޅ��*Ϝ���k�"򤢭((�((�”����4���LIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT�Mh�e����~��|���ϗ������HF�!E�^�
"�<��:tAt)�."#���{��@�"�R+�T��mn�9����=�>���`���E�^��t!��HD�.���XN7o�wt��Y�^���_��am�iqP " \�5��qCoO�u�L�O�߆r�謫���rJ$��D�n���3�-���_˵�(�����K�|��v��҂��:��#S'�L�H�,�X�������=0��^4�+�$�ȉ��������\%W�O�k��u}ɛO.UuT/C A]�$���9�+:#�g,̖�Rfm�g�T�6�A�NY����(D�M]s���
��A ���H�@�ы&G.X��Q]�:��Z���ȡ�6-�J�
�0q��ի�4}��V�eŊ�ç ܫ���՞={zj(%DA=}����588���ۺu�LMMͫ�Ov�:��)4A�BS8��eR��r��Y�v�o�+����˖-�����޽{���%‡��JBI옘PU���~�V�G��)�Z���I�.]r��y5�ۍ�a��[Y ��/�|����!k֬��o�K�f�Jccc����Ҫ�}��v)1�H�\n�B��+��]khh���133�… z{{��U�an���Yݱ������Ɨ:p���o�r�� ���6=�9����4�,���7�6)"l�uhW{.v��� �����FFF��z}��r"s���/���0Wjk;vUIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT�K�Ve���ΙGm�$�d7�fe�"��EIѢUPm�M�v�"ڹ+�6��.�v����]�2»6�8�f����ޞ'2Ӷw�>>1�J 1d�����+y �M�}xώ@d��>8z��77�-%'� �䍡�'��tf������Ȟs�Bi�ѶY�ۿ�A��>��K3���n�����:9?��SϾ����?|~�@D,��f�)F
m�� �"P���㩕�l��X�
$%(J��D(M��ߌ{=�4�|�v�H�2��� !d��'%� �Y����S����c�-��I��"�D��J6�QJ �6R!
(����D(J��0҄��8�ώn6��@�ڑIE"3�J�Dh溡U������J_�jM�I���v+��Π�\����\����}���A }�O�R]���k��ګ҅�֭���`�O���{��h�v�fz�灐j���:}�/����а�6w��1���?Gf[�^߳rbĆ�EM\����;&���^����3�.\��٣��y:g����Z�ZsЋc�{5ҭn��c� ��l7�f�ZO�����G���d|r��S??��p���`�Y�κ���,���/`�x ^�{�(�&�O�r��v<-D���oz)"�H9@�H���sS����_]}r���m��
aS��/IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT�?��s����~~����TI�!!�b�F� ,H8���b�1a5�l� �N�QB� b`�^8M�A��~����y*��޿������\�)(��0���k��������J�������i�ΆIH ���q�����~�����{�СM�кOg��Ԫ(2X2�s��,�}�O>�};���x��3o}~�W�tܠ��$��S�j�bjLEMa8�����y�޿��ww>�����J�Ҫ�*m*��u�=g6=W�|�v�jz :@B�(%U�Z��4�\��1����m��f��j"�j��A�ƚ6��hT��*J � V��ZJZ $@�1�0PHZ�(}
)B�e� ���� @)zc�Ԋe� ���0�2FH����d�#�����W?�9��</���;���C�9�A��x�y���轍y3t�-�;��w^�t'I����WM����eС*>��W����i!�Gc��{s���ގl6�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT�_��s������w��Ι���2-�!���I(vaŅ\p��"nȕ;q��j��f�����$�!�q���眝�����<���zeϣ ��=\��G�@Y�j�����ϼ�w��@d�{_�f���l���X�4�LH'����Y�������K�޾uZ(M��͒��5%� +]V�Q�8�l�j�[ֶ�� ��?��靗|��}s"b,3�~S�
m�� �"P���z�
W\9oA;��=(���D(J��4���V� ]�4<��RM�yZ�Lچ2B�چ~��J�:R���5�D[F�B&�6��QB +�z����6�v�n!V���J��D� �&�J;��K��f�#���Z?(PGdR��L�R(���U�&��d�]z Vzj��]Ϯy��ZSf�� �޹�M�z�n���V����z˵����-t�.�J��&��J�3*�IQ���O2;㿣sM u�j�W���a��!z�Ģ�:�U�Y�b9�q�_9�D �Q��X1�s�eEM������ݸQ>�>N�Y�oN=0��|i���\��ZsЉo�:5�c�>�~�'�k� ?~���������K=�ܷs��p�;���,{����,���F4S�y��bFoݓ^��~��~�Ѝ�������mqCʅ�my���}���#��sth����n����o��?N#=�ƙ?IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT�Kh�U���9ߙ[&��IzPR�5 �Ġ.�Z+�f��ƅ�Fp!"� Bw��ݹ�Ѕ�p!�`m�l��%hSm &�:��|3��}' �'����Z�r�;&�*�p�Ȉf � }붷޺xf��$���.~63y��nH�!��ڝ�ٟ[�,v����tf�|���!�}��;d�d�(�"q����bk}����^�zW84���-��Ɗ���d(%,D��8r��l���jr��R��\�4l��&�L�J}/}�ݨ����^N�5����Xe7˛9c��R`�##\���<�����赬T�v��|K�N��/�~�r��Ḳ���6�R� >���G�J����8�a�
�.[������<O(�2e��0��'XJG���AsȚP�\{��_Q*r
h�}Wn"/ � (�'ՑG�y,�`����������̡��]�p$�d�-��w�.���F������ݡ������C|�<������ȼ�Zr�(�$�x��|vf�ھp�j�~n�V)��@w�����dB7=�߽� E>�&��0�7�|Y?K�6�F����+Qt�p}Χ�[|U{���� ��@�_W#2Qt"`�Π��k��!���9!&p�;�9Bp�����\�}�ѫK� �$���a���Nі�$�N�? =�;"��@����]�0�?c�|�5$�#IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT�K��e��������Z��Y���L ����( Z�)�.�$��"ZDTAD���(�Tav��ݴ2�15o3�x�9�?���ĝ���>�d�%l�Bd�UW��S�q��ڱ��m}��O���G��/%�%� ҉����v�����~�w�g/o�hKkG�fٯ�5%� +ì�.] ݾ�b�^��X�u�ԛ/޼v�X�2{rr���2�i�^� �BDP��%#��<n��ѫ����u�=�5s��mPA
�JP�p��W_�(�V��1�z��?y��ɳ���I�BF�ä��a$��N���+Ͽm���>��~���� v��$�(RJD ��dS��]y�6�>���?<Y�͕��=s�_�%B�zMh�'��y�����{ϯ��A���}���R;2�Hd&���I3?���'Ml�0�C����w�`:���5e&IJ0��~3�{�n���3~�f�SƮ�d�}� +�$+����C�ػO{�U6�t��k�����Z���5w�5E����K5�?�-�36�˖_��y����"u��Ε+����|�v��p���O�ɞSG�8w��7:fb�+V����㝬i0�h��Z�Z�?��A5R
P��ҡ��,��жQ�a������#��7�gf�T���d2� j���aW�h#���ވ�1�"I"%�`���}[��R�Y^��13IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<QIDAT�1��e����}���AW��`^� E�h 6�\C�� N��m-
E) ��RX�AD�V�Y������������_~�����.��(�^z�Q���]�w{፳�����:�ó��޺�ҩ �`��g^9�o�{����2S�m��t��>KGO�̵�ο�,.���W���1޶��;d"]�����w�W�����Eu��Ve���i-Cp�-���^}��1[������|nm{�h���g��?�6�7�[�1 �ila������}�>���:���2�΍�鏍�ui���v��C;?��Ҥ[�6�OD��:�ƹ�M������/&}�8�\��v�N^|b�:�b��q.k����-�RX��$�bq�\�7M��y|� Cg��sQ���A��T}�%E$;z�+� �&�M�&j#�E��d�LE)E&Աjc����DKCGW:��.0a�@f �U�M�&k�HТb��(\ޞNO�ڷ*k�����N���T�� x��/?ݍ�p�����,�2�JQ
P�ww�������r�n�ܢ AQJd��YZ��?�5I83�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<IDAT����s���>��מ��*�v"�6iD ��@��"�DLb�5�D���h�2HDDIY$⥪ ����<��uUϼs��c�^� �@!E������������g�*������ǯ�9=F��@\�q��W�����?|���ϟ݃�Tm�����FE�5mY�����n��/�ʑ��מz�;>;��ހ�:�d�N�f0�`*�
�Ա����r��v�c�€P00�QeTUF�1����鞣9Q^}�N�fzf��y��T�5�2Ol3�t5�{ѽ����y,0CB0��(�4�[F��I j��F�A����֒����$` t���"DY����# !@�R*̃�� �0�ڬ!M�6A��iX�0C/щ�o�"��W*Ҁ�
�|�`�� ˲ZW�w��{�4�*��% �*�����qpk3,{�Kw�׍o����
-*5b�G/k/0�������t�_o���d �}g ;��Jo��w]�W��*�?�������!�����y���!��!�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT�mh�e���u?�9���|��b*�VI+R$he!������A�!A�e��SB?D�-!��}�r$�sJ�Z��f��6u;��<�}]�~��ǽoJu۝�X��)Au|����;3��Sy�r�ѝuN  �����c��L^�U�YR>�^�.���>i�|�ĉ��)DSB0�Y��x��3�S����<����{��Zp"��̒|��9���D@(�Jy�+�gms��K�#�@��N'��%¿�U�,̘�N�&�%�x3� ���Ѹ��1��\��0 i��a5Y��~� ����/�0`�6��︯~ �/mGM�Q��T*n�/\�i��fo�" ��`Y����
�&�%KM�WCd�J��g��0 03��\b��N��-���gN�{�)nMW G������X𪆙��a�Xw3P���ポl[���+9��'��9ȹO�W|T���AS�_��q�:���v����\�O�
����`��/��
� �#��!M ����|�4Yx�i-۷���ȟ�����!Db�U��;� ��{��K�6�-�X�:�E�"�W���+_�!���T-����������{�������! �,��B��W׵�݋7��dپִhfm�w�ܙ���+"h!��������E���}��ȓ��``��&19�k�y&��w�%ńev��qIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT�M�Ve����7��8���b�Dfai*QT�@�h妍�P;����]B�@hQTP��6Rd%XAT(T���0���s���x����M(a6�/�AV]��-_��c�������gN�ʞ���|� ��#�[�����/?�_8s|qmibG�m���)%de�Uץ�������O�l]��z���^�té������̦�m�� �"Pm��Yܻٶ�'׵s3�@I
J��D(J.][s���} ��÷h&���L��8)�m�e���4��Z��kR���6�DE�����'.X?�갳a��+k>+��4;u���ʚ/~�{���������=�o��v�:��_�� >�rI�q�ԎL*2�V#�nt����+���"��֜�LI)�IF��ء�jM�F�n Vn��a�G5�^�n(#e����?y�?��Wu\%2�dz�j�nl<f�܄n-��88{! Ɲ�L ����5eV]72v�nPkWk��K�����D�-���!
IF5�����EWWnjG���^����3Y�T��S�1�Z���/�8�U(�V�tp�[�)���6"�=}��#��� �K�o��ڶ��goxr�>�-��[�6ә��F��:���;�=2?9o���Ց�U�X�U�/��������F�/�ˮIEND�B`�
�PNG

IHDR��7�gAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT(�u�[� E���&}����O(��@_֖��9a.і�?v�9\ ���bB�WҴJ�/\Y���+DI��O�)n,T(pbe���F��8��D�`���ñ_9υ�N�8�s]蔊�d!���4����i���/&~��<EOK��E�K�.�:'� 1%�u;Š/2�[�y�OIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ��KQ��eV�J���q�ҕ`����Q�X>b%��BB �*t!�ЕB�iU| Q�d&�d��+3�D��� i���ν��s9U���0��O�ƨq�
�e�s��]>�G9�9|>��BI����uE��� �� À���T
�$q�(����� �&]05�w��Lӄ�iH�ӈ�b\��d��:����X`�6����߸�TUE</)���X��@�;mk���n��D"�3����}@�3G�H(�,˕��+��!::���? �C=!QE�8���/0�/a�� ���fyHB�ؒ�P/�H�����v�A�mn��������)+/� �8���Ŀ�B�����"nƆ��@Z[)�j~Uh��^���N��3Q��O�R6��]����n��^Sݑ����I1��Oc�
c����4e�sKx�C�A� fw5>��V�<c�h�[�$9���ȶIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<*IDAT8ˍ�͋RQƧ�� ��6������H*)ZS���E����$���ZD�Е�ĕ� .�Р 1�
�E���z����<��Ls�q���pϽ缿���9��)rٸf��C\��M��.cl8 0I|^���(d0C���@UUK�$���V� H�Z��� ���@ 4M�a�޼�����t�]��u���$~� 2�`#��v��U��/@�e4�=% O�������B�2�;��R�ͦ�I�R� �1���V��~Ƴ2���#��h�Z���hKW��.�x�kw��B��L&#�O�����d�����6ݐ��P�<ba*�B�\��;��>�D��{�; ����XL�" �
��u��S� ��2d�ƻ�07>�,�D<G6��i�B���F��Y����U�s0��u��O�c���R �d��B��8V���(�}�X� �u �Wm�Y$�H��n�1)� ���t|?��>�76'�@�XG"�r9-�y����8��]"��������L�?�y[��ӿ�ح�YQ�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8˕��K�P�[����8���V�"���Apj�������[�JS,�889U�`���(Z�R����ǜKSӷ��pr�/�w�k`PkR�Y�e��U�ѣ���+�J�^�7 ���>���,4�E(��R.�C&�A<�X,I�� ,#�P.�Q�V�J
d�Y$ (�J�K���th�D �|�d�k�f&�6�:Fk�9�6J*��Ȳ��)=��0�t:���q� A#�Z�&r!��.Bo8
ذw����ٛ��4_�q�`�ST»��ʼn-�<VL����p[�D��,Od��>�_�Z?^D(z }=~H@����� �a\a�0��m4�e5eE���0�����<�#�̕�"�&`��AGya{���4)l��}�O�/�����!&RIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ�KK�`���
���I]�t�^�����R�Y��U�8L�V7*�ځʠ0^t�JEQT*R��IS�&����~�S/���\�'��+PB����aT�A9㣓s <�lV���B/��C�n�[PE�d2�T*�H$�idY�I� ��#��H@d2X����i��u��pA:����������{���ksƷ,÷��V {�:P�0 �b�g-��]z�򍰦b�aE���(XK�o�UUy%�H�Q�,�� _���l�ܺ��ٿ� �HB��<���I�+��a⻻� k�tlK�� �A�/ ��(*j:^�|D.���% ��&�!/T6w�;s�� �9�*H@P5����w1��?C�qȄ��00}���+�<HP����[�5�.�Ω0Z�+��^baU~vS$��� ;�ZQ��)/
�Ż� � ���A� (E7�fϚ|��e$y�r���_vN��k)7FIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<"IDAT8ˍ�=�ZA�߹*��Ic��4)$A��,
k����f!��X����w���&���&**qר�\�?W��3���G����9��0�9�`�y(�)L���Qܑn'� ��j�Z�6����n�cA�<�J}���(�;���l����!��1����JH����t�1�LĂ�r����"��)�F���I�b��b�l6+!,�H|�7�FE"�"$�I��qP��d2�0�͗
Qo"�|>TUE�P���/���O�J%�b18�N8D�Q P5G��nG�XD ���B(��_-��W���|@�ل�jE�\��b��t<(����~|�}�ܝB�Xq�Vx�!��! �R����<e�ɡ��f÷��.0f�9�.��D�.�d,�]�]@r�4v��邛��S�=P��4 �z�O48�J� ܢZ�J�!'rrg���}鬪��;2QT�h4�Ղ��s^�WV# ��K@��NS�j�3����^f�������<H���5�����sƎ� *��'�麾�1�]P���sV��Y9�]<�����@�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<,IDAT8ˍ�_k�P�g?���d����G�J:��bE/d�u��@� ���.ZA7� �ԭ�е�f�]�6iҦi��=?�9ڬ�� <���9�y�w ��^)���p�
rC� �q4���^���D"sÒa�$ ��4:���6$I�z��h4H� ��$f6�V>�O+x�iB(���v�idY�˲�6��b�%�;v��#�����B6}T$�HeEZ��f�y�H�'4<�ֈn���I�@�&p�x}�Y��7�QEᕈ�x*��TEviPC�Ճf��#��:"��]�y?TU=,�+�|�BbGE����br���o5� ӱ�� ��0Q Xxߨ~����ٚ�W�Pu&����O3�<��r #̭�EG��"|g.6\l��-�x�2��� ��V��/�H���@�5����t�F�����G�s5^����[.��>�O/����@86�-*�:�/�E��@0  ~�+��g"�n-dqc�3�s�̝��GqF�n�C�9A?�\���l�<a�n�O�`�I�1����`�����IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ�=O�P�)C��0�[��!�k�_@� �@
��
&~@[%C
*UA���V�J�;dB� ,@l�_��ر�o}n�qHP����=�<>���.]����D\��c�n?/ �8������F��N�q$�ɷAIP0Hɦi²,�0�iDQdA�J�|������mT�U�&��2t]�$ILP�T@I��MIP�[5��AJ(�J�e��%6O�(��~�0�[d�ā���a�(��*�y�U�t�O�л�����M�̾��_
^�I��
�P%4UUo�VNcc_E{v_B|�NuX�ת��A��"��*k�fB"_0�-K?�6��љ��c.oal���7�.`Z�������:g�|)bb��ܬ�*��ā�G�
���å��2��D����a.��a<�g�ɏ^f$V �u�Z�A�m� {��T�o�Y�����7�A��A��{:;r���{ЁK_p-pdQ�>���2��A�$���t�C��ʘ��?�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ�OkA�k//9ւG/"�!GE �Ԇ4M[Ү�D���!�@?�?�=�'�%�����n6�I�9��7&�.<,̻�ggޙ�0G��dER�%�:�� 6�G�f!�h6�����@� ����}x��n��$�i��jiI�C� �"�q�ބ�1X���~��v�=�dC�p
(�9�m�SKR=I�� �������AuA�@��z)�㨙t:�I��Nj����S�����X�� �h@ ����fB�p]���y����K�o���$�*&�K��*h�/�����C=!��5_�=Fo�8���ܶo'�^��޼�W+a
%!����v�泈{p�M�W?�3�3��e��J��G�\:=8+�˝���
� U��$58�j�{�$QPxJ@��|~�z_�U_SEw��8�\�2%Hҿ��9���n�3�ւ?��lPH�ۄ�B�ތ`�$���)t��~���{F�f:IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ�_O�P��o�?��}�"Je&^�xO �h���� ?W���qdR�0�B����v�v�s��ԕn�M~iӞ�wz�� `�E �+�C�r!��eY��8���=G<��7 �P�ՠ�*J���
$�@������V�%ό���4 �rY
��&x�d2�K�n�(K�^�cI��n-#�׊j�UV`�x~ ������nO�+'.�+ �G�Z�Lf���?}Y�(y�,{0?�h�3��}�㹋b��^�_
�~�n�7�/���!0��� V�&���4�|.:�&�d���ɔ�[�#��B����?��X%N5[���å@��gTP���|{���±���F�L۶%��e�a���(�Y1*��x�F��U7� vqs4��hʳ�)�YG)��Z�����E�}�/�ܣ� ~p�0���� �Xr��܆���?V^֫��T�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<fIDAT8˅�MK�Q����̼3N�Nb��a`T�B�6�5�M����_��jS��֢����H�D~V̌��;�眧�69���9p��澹�������g�""a r8��r�$�9'��8�edd�� hiM��W�U��j��T*R*�d~~^�s2;;+��� ����gP�<(�ӛf�拉Š5@�ZM��k�n���)
���B`ll�����5��ޑ�:�_��Z�
$h��BCC(�MfXk��\>*t�v3�3G�͓�/����3�9v���� >!�2��eB8����\�(�$�Yaz�e��ӵ @&JQ��`��Z��c�eE�l������\&�-� 8�1h�QJ�6�����7f��7wn��  �u����[����^?1֓��5BPJ`�iVP+��~|&�V:�͙��k1sK]�>�#�J��Xm\_Me���Ks�f�\������O�?Ż:��|����5�K�*D�Mr�p��{��*KQk������Ή��x�z��ɗ����x�i�W�z��/�M0YYZZTٜb��N�:��� ���Τ#�6 /��ֵ�H�^�0�d�A#��~9�N��X��F��~{TB�|v9�IEND�B`�
�PNG

IHDR��7�gAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT(�u�Mn�0��E��9GBꂫt�P k�BH�$�4]8�&����瑟��J&ѨF%���@d�s3W$�q&гݨyFz�\<jU�RU��wN|qDk��G2��H�Ǽg���' �7�=�Bp�{��K��q�=���1�,=��Фon���Y�( U��<��B��*�D�2���u�M�x#��>���M��M��IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ��kQū��]w%R�.�Z�V� (HWJەJ���QqF�n�H�SBm��PA7� �EII������$��w��d�Fځü���o�wn��0��v�A��q\�
��j6�[�V ���!$$ ��Z���bٶ �4��*�Ȳ QcH��t��}�a��$�uaY4M�z��H6�� !����C���2s*2s
f���jq8�]�wX�59q}=5QP ��� �Rq���Z^��}GV ���T*�6�(峋�]z?��.h}������۩����Q�Vۀ�Y7Y��CƓ�� ��ʴ�3�\��7xM�R �x!c���op�Bp��c�rW�Ivp�TJ3@�ɼ��s�X^sx���C���"K1����ѫ�+8s��|)�0�S�7q�^˫6�Y��u��6^;���<�pV,c��:��Qy ��h�P �>��X�lv�:�lWW{��s�E[1��0+�G{ fg]>� @/A�0Αh�{�=��ҧ���IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<NIDAT8ˍ��kAƫ���@"�G_�,>�X,� 5��R���x M�چ4�i4!��R�Tkђ
�ň��msiv�l���S?g6&��3��f�9s��Q���HE4��%���)�Z�Vh6�ۭV �D�a�XLJ�0@͒$�\.wU,!2�� I��`� �wQ=P�VQ��噪T*�P(��8P�T@/�Z�m ����n���yL�9�r�e5���Qw�W�Q �,�[�99n��n=���79ؗ����1������琀����20�¸8�_#�m���6�c�,�j��|zo
ZgcO��MGqv2�3L��ȳ�r8xb�2������M�#�M�ϲ08���&0���j� ��p�������.[0"���C�La!���L��0V>���m��;�� �,J�OG#���:�dg��fq��н��98zcC3��Õ���5&A(�a����%�f��,f0����\�,'� �e<�j/LE�QW
W�m�m,�Hɼ� N�#�
U\&f�5�F�!�@�#�_/b�H
-e/�������~A�/\�;1��%�{�~
�A;wD[��'�V��~.m�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<IDAT8ˍ��kSQ��k� .�W�q���:��΍݋��\!X%Ym7A�.B"Đ�@��@�����9y!S�yϱyM�b|��ws�{�{7l�.�l����rݚ`k:�����r��E�yh4�w�u�6��cH�$3 ����h4XR�ՠ�je  ��j��M4E$A8F0d���4��" &� h�N�Gb2��|��l6�z���j�K�U*��q�\.������.��}�-_����?����o3��
>������,i6��V�g�ш�p����>���G�.��ç�O�m�5~}�B���yt:�3��f���9'L�\�ە��i��n�h4�e����I�R��Ár���Z.�C"��q*�b(Db�/�N���~
�/�J铠�n�l6�|6�q��@�R�ŽL&�
�ڥHB�$�z��=*>'�5�RyW���b1�h�Z, �Bp:��Z! NO��B�KX�V�g�d���� h >���=��Yp*�%�h�2��#��k�M�\�:�����{�F`k��IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ��j"A�MbV �2��2/�bP$j��lu!���q'F���kN��.�\�������� �qƺd]�G�SUg\�V��v���v;�L�NN��b\�x�X�r�T�N�4���� �����R��n�q�������T���$e2�u���!��s�L&���`����
����[��z�ш��5� )h4�H$�`6��`0�Iz�ŵ
o�jPi�&��(p'�N�����|�'��mj�ZT(� 
Є� ��
��k�a�l6e�R��0���l4!p��t���ipg�j�*�R�$����*�f���f<�Fc:f�s���yx�^� ���:߱Q��%�X�r�,��!�@(>�Oq��f tׇ|p���;*�J���i ��v����q�D"�s�N�h:x/x�O����_��O�W�7�On� �)�sy��9 �xΦ���_K��<����IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8˕�;KBa�գ���nBCM�MBh����("�Zڂ���38��PC.(8TK �4�u∷�=^����#��~������y�
���Q��a��$CCUM`�$)Y*�*�r�`��r��Z%��H�l6 Q�R)$ ��aY
���|�����!�ϣP(�O"�� �L"�Ȃ\.:��v˒6�H@�t:�h4��Rm&�&k���ީo��X,&W"BwA+�������/h�P;4 $ �Ţ<� ���['^�f���2~^��PH!�9Ǜ݄��)��^�׻l�V|f�N_���:� �iC������Ͼ�����4����fm�QP�6���qd/���*�2�[|V�G� sl�"���2}ݜ �9 ��GdO�� 5�6m�k���Iz]�˥a��� T��� _��#��>U��)ےIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<IDAT8ˍ��n�@EK��J�CQ�����o<%A  U%R0�u�T�!�DI��\�mdlǹ߯�f΀M�E��~�g�:��X!��6���t����k��=��.��9�[����Z�,�����1 \u:�Z-T�U1M>�υ8�[�|�T*!�N#�L"��B�u�z=��mض���T������r9O&�y�J��f�o$S�р$I���<E�V��� 3o�y4���*��.X;\� �\.sH�^� �� `f��)�£RD�d2�˲���<L��.@��
�z�[�B<:.*:�^�9�'@`j�@. �x_1ʻ�RO�3%����qnu�8=CJ3�>�t:婜�.��m�����$N��8��0,��3�|�!Db��(� �F��a�7�8�v�c�q5���jױ��_
%��D�?�(z�{/=�xq\�B.�Ç�!d-�@ 6#^�8rΏ�`�������6��� ,�4�8������݃kt�~AZ������ۻX%� ��#��?y"�CupX�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ��KSa�WEDBԅЍ�}a? ��P3B� ��]t� +$aA ��I���X^�ns�\[sK�p;;g�������ɦ�p���s���6qt �w�`��԰U]�|^)�J�r�L+�:N�sb��&��\.���u��,�L�d2iI�YBӗ������)��v��>)��iR(��D�4E!�J��߰�EYyZ���,�ǽ�M�!�a��*�?fH�>��>�ƧG�9�Q7���&�h�޳|�}+� ����n�� ���$�j������cM�?��}w����+���U;��}��92XͶ$����jx�w?Y�=“g�~���Z��\�-��32L>vE�d��i��/��� �e��{;���^D� ��t��T�߈�]v��5Jh�.�A���z�{��������<N
� ���̍%�S,��(��9���N\ϱ8s�l2ji#����A *2�8 '�ߧ˅��E�&�Q�!%{�r�;d�?!n�,��pIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<IDAT8˕��OA��W�5F"�������w ���xT#Ab��!jژ&������a�"I5Qh���]������v�?gF�H�'y2��ϼ��N@��c��� ')GX� �#B,��6�M� ��p�i�D�Yq�^�mۻT*���R��%�� �쑰��l���<�όZ�˲��*8�vH4�}V,`VP�V�iھH;wұG@c�n`k�[D�u�w"����V��\\���( m �a^�c�U����� g^�H�%���@�:��������� k� �A�y
�wȧ��7H{��h���v0 R��4BØ���0r�����#��i8����- �ʿG��5O�t����m�&Lzq��]��W���q�'(��a�v0�*�%ۙ9�)x����vv�F�㳓�G�Gr�\9}��x ��g�b��>��G߀WN�����_���}���$G�bBp�Iij�&{-�aI?�@>L�'��n� �����"��$>����Z� �?�zL�^IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<)IDAT8ˍ�OHTQ���;�D�:�L���&���DD��)-7A����Q�Z�����b�3�c�8o޻��6��T�|���;��)@)�H>�W���P� ��E�5�ȿ�����v��4�Q�R�$�r�Y^^���E1���‚����!jp�Wֲ9'�u8'8+X�p�a����q��$a�#�ˍ �ep�W6R��)
�d��\���/�-�$�4E�����%����Ȥ���q��"�9�1�R)�֎&����-�J��C��4�c�����y�����Z���Z��ʋ����~>|��4�¼�М��f�5W� ��Š��}��h���b�0��|����3����Y=�jK����<~� �����~TT���$՚F�021����LW'$���d�0�(��}���m��+g�Hli�ZÞ�>�Ͼ��珄���Q� "(�p�5���� ��}i��a�����p��!�i|g���V�S�M�Ƙ��bsrZ�^�P8kmp��֮V�V�]�:{�L`��/��G*�_>IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<6IDAT8ˍ��k�a�W�@�%t\#
�&j�Pɉ�lk�h�k���E�$�XZl��:�2X��#�0Z���/��v]=��zg�h/\/�s���x�$��d3I��]L�_ @\�V��Fc��l���9�^�VH+@J�b��R�$(��!�� �sH,��� ��pz�ZG5�e�~�`px C�K�T*(
�f�H$P.�AE��o3nq��Ϻf�@s�?A�Έ��sx4����y$��F�L���L[alb
�#ZL��Қ`w=��[�h�0J*��,//�$�CS:�枾��<���i��Y1���4n����B�P�tz ��g�Ύ@�7A�����@�PA�>q���t���!4?eB �2�.�q��KL�p���,�F�l�<��N���z�Z�CH`��U�}�m���Cx
�l���o?��&�����Hԍ0Xyu��8䪣_��� n����ö�;��: ��/@�RQ�5�������
�!�+�<��Dzr�B0�J���M����R�vZ�s�=h��
���Jt�3�[���d��G��_�ٝ]<W�=IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ��KQƵE
]7���4�m���Z��… Q� A|�E)�d�?F(Rh�tӢ��.D�j2�;�;��{�f���6s��;�|����$�.����z&����!˲j���h'q�t:���Ȭ�:c�EA�ZE�P��|>�L&�A��N��4a�6�o�a��m�P��P,%�0 P�l6{i��>8��vn* �r
���T*�If�
p��aμ_[�13 ����\.�Nr��=�am�'��H��������B�P�J�=��=�9�z��/�����bB�k�&Am��O��� �#a�͔7��82���6���Qe�� s��X@]Ȁ�����|���ė�����s���4���}"�U�DO���ށ�����~y-�BW�� {iJl�x�&�U@��?����o��q��Q���6�>��ǘ�]Mn��M�G�sS����v�����/�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<IDAT8ˍ��kSaƛ�8���bA�c�JE'�������:tp�!��KEp�i��C�6�iC�6چ��ބ4��77��9�Mz��� ����sx�����bM�����,���v�}`��a���Y�:<�;'� �s�لi���u�j5��e)�J�z�H���<h�Z�t:H7x�����J �4M,˂4��|!�1�u�Lo��I�X�r�:ߍ��2��~m=���on���>|'�T*5I�X<�l�7(���[X� �E�'y4x-ɣZ�h%>�r�_�s�
w���G]C���@d�0h�L�KW��1<H�1��E pW�t�]��@DÀx�5������Bs�<&����U �iNe��zf�|��5�����h)�����@$�!w%� �t�U6 ���{��X�%V�3��:D#_p$�{���7���������m5��N�P�B�}���`YGRx����� �<�u�� 28��.dJ���4�[C�^`\ ���?�7³ �WIEND�B`�
�PNG

IHDR��7�gAMA��7��tEXtSoftwareAdobe ImageReadyq�e<$IDAT(�m�=KB���[���#�. 54��PQC5h8��B��EI��1�aEZ=�s�n�#�ų^��p iDA} h!$��Uv�.��X�t�� �Y��Ĥ�'��<��!�O�K�:u�)S¥F�hD�����S㋷�+�u������I�wJ<yAwm�!�����,%N�rO���? �-���+���E.�a�eR��뻐�� 4����>�x@��Ӡ��D����9"N�49���p��d�<
���)���M�+�$E�Y�5��Y;�_!o�Ɛ������\�H��IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8˕�MKQ��M�!Z�� ��M� ��[�.�PladdF������qѢ@Â
�m��s����5?��0s��s���ak�a`�0�����%0��Xl4��f��# �%��H�j�
��۔J%
��iY�J�
�:$��$� �Z �$�O�R��X,"���A@�D"Y�#�� (P.���f{Zj�D�!`m�7�;�������J��dA7j UB���� �j�fB� �z�.υ$ĿT ��C��]� (�@��N�p>���]P8c6��� #��֍+ޥ/�>?>�/�'��n�qg�ջ�7lQ+LG�����Ղ�AsX���zߋk�f���껰Ȇij�}/��bg���<���7G!�Z�#ɠ�lrs`%Co����4�t��Q��Л1�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8˕��KQ�(R�J}�B��.FSkJ7-�"�RQ�U����P�FQH�P��4�UĂTJq���B�JB^�s�֯� ���h��1s�o��0��|���ܠ�TXPD"o<?J$�(�9�z��,��T !�I|><�v���l6 �S-�!#��WJ ������P(z��h�s�B��~8��s-%�����8�@��w���%��j���F��I�{�����H�j�-���8�Pb���\kD��=�"����#��X���r���ѿ�K:�-?�J�����Ǘ����s+�z���ڍ>�v��iQ�|����,;-����=�|���z;֚1��s[�x�
w߱DZ�����eo��q�o�q�5f���n�C����}��R�X
<�-A�.�ӷQ5��W ���@�Y�2�dU��,��O��i�I1v M�(5y���@(
�l���Y�P���R�49�T���}�vs��IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ�KK�Pǵ�����|�R7�B7nD�0�B�R�: � tD����G)��� �υ�}hT&1ɤyg���{n�%�H ��=�w�9p���id41���!�ȋ�J��U�V�k��`�$i(*�
���y|�ض �4��*�(��L&#$ar= (�X,�\.�7�.,˂�i\�l6�W
ZRRj����- ��/$��8t]���I(x�b$5�i1��Ë���x�a+�B�W"��m}�m����= s;&fs&L�,$T ��0�x���_��Y�� �/iZ+@Z�E%�̈́D����F_���������y�W*>�������S{'.�,��V�<H@P5BК�L��H>�H/�H/�<y�����+����d�������L��`�J���Ք���yt��蘖1�� A�<�;kh�:y�hn{�������W��E����U���;���]{õ�H�ـ|:�O2�u��F ��c�Ch�Y��S�M�nIEND�B`�
�PNG

IHDR��7�gAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT(�}��� `�9j�t�g[��G�ܲD��N��0-���C?�#DX�������l�2�B��Y|氍D�g�:J�+�8P؍D���RhP��7=N�3 �I D��x��%���gG��0���2�����c��� ��(�� �f���W.hlǠԝ}ewqCC=QYe�,N!V��N��P�L=TIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ��kA�S��Pς�HɭЊՃz�*X�A��=��!�E!EI�)��zi��Q��R�Jj ]kQR�d����5��&>�t�&5���.��}fް/ "���P��%��<�";���8��Z�Z��$�#�L>h��n2�� ˲��4 �J���B��T*���A�m���O�a`��T*��9h�t:�Cv��d�u�ryW��;�h��z��AUU�Ȳ�Ь0D�~f�zy���������x�2��q�쾑��_�s(e��'`k�P���x|�~q����Q���p�8��$X6��4��Z�联��07�?�a篃��u��b�?�����
��KХ!��S�7a����aw�\W�l�9��N�4�og��cXI��˽~����޽�͗�!��a�y�j <׏�}Ƚ��k0��V#O� G��g c�L��kp�����Xy��ݳ^��=t$\ݹ[���SG��'b�'��n�5U���Mu���+�IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e</IDAT8ˍ��kQ�����;���tW��h���+A[���>�t�& 5��*�&BP�EiA��X-Z[��-i4ii��Lf&�yf�?zijZ������}�s.�@�|[���������U m�ΕJ��r��� ���%Ղ&6 �i:��
EQ ��<�`0�H*�u��;ڳ�Ӑ�����8�/�>��>B �X�Z$
�PA��� _\O�D'�d�� ��P�� ��(�O �BMKl&T��ɳ�q�6�c� �9?�i/��f(�>�I���d�qܒ@߿13��v��}h��0~v!�jr�^����Q��il�,/ �Q�+�q�hs~�w�M����0?�8q�� a���w��q��D����r3�L��> =�#�[P�^�ߜ@j��G�!N�"o(l�G��wu��������r��T� 7�4r�����|6�Z)
�Ҳ!�g����b�y��ǐx��h R��"��W��ڐ|q�T=���� WS#�_��1����eo]��K���u�)K�������#�+�Edҋ��ɿ:��*A=��a�+�կ� _Z��MHyBIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ�IK�@���C��7����/�= ŋ�Im������\� E*q�[A\j�U��6�4S�:_4�U1 d�g�2..1�����TR���!��g���i�� �n�{�\b )��:c��r9d2��qK�(
<�7 �
��0P(�'�i��,��%���E�^�%�!�� (��*���JgR�M j|N�w�mWI�R�NdY�[P�W ��#�N;�f�P ��5&��1��_�/�L�}~��`7
�]�c�V��i���3��$��Q�A4)°+�������E8�!��� ��_j�8�������C��=L=p��U��U��^���X}�L�wr }�u=�R��Y�8�yƂ8��]c�w��!�6i��Mwֶ�w�A�}L���L6�����xG)�>_o��$qp�-����7Z����7�����ZIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<TIDAT8˅��KTQ�?����8�O3��J�@�Z�[7�]HX B�~�m�F
�A�@��EB���E��.*��(�y��j��8E���{��|��� ���O (z��{"��z������7��u����8H�=�­fx ��q���G^(6���pΑ�)�B���-VVV���/� ��2~r���F���8�)t��^BJ��!a233�sssK�k*�1G�:HbMR7��uR���,J)��-�L&C.�cvvv�֘����Q9�x!ω�<Qy�Wo6�q�4RJ�Rd2*�
QQ*�Z��P�~s����U�YO9���Oq��]P]Xk�s�0 ��l�,�gF�&E��K�f�^�M��K���ɏ�C)Ռ!D35�ӵk��+ظ��]��Ⱦ v>>i�V�RA����҃�U�5���u�")��ym�������}���/����.�::�;�f��dit���8���[���uw�Z[)�R� T����3��@f"s��ÏOoɏ^�my�hY���0�X�E\w)]:�z �]���m�|�R� ΋�6N$I�Z)��>�t��Z6���.0ܨ�~��X���X��ҡ3IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ��KSQ�G�g$T�C�aYQ�hEHY�� ��eIŌ(� !)J��i��~1
��� _p]��~1u�v���{w�v�݋~;��^��.|~:�����r��Pr)y�`+eS�.M��i������8�=��d�J�lgK��y1W�u��Ħ,���!# BEx�^&�y���I�a2s;��O�*�����~� PU��@�$����B!���ߒoDz�r�\�>�~!�� ���^F�Z��D���#D7��2�gc�V~YB��� �B���|ܢ�e/.Y����f����@����;'&:��m���<���»��+�*�#��ƽ��x N�ȓbȽ-PF:����y_�p��CS�DIf�Ȳ�(�-��ㅙ��w�i!�Q���cBd��&��"|�ª�B�I
4�q�:� ��b�(�0Ua�-���y�
�OU�-� � �>RJ�4�ȟ�a�oKd��5 J;y2zo�{�� ��h��� ��W�����D�a.�u�6��FfP���`e����a7��W؝�.��@&w��<��:���O����j��nt��u�N��~��a(��=�+h
����� �D@�?�5&H[�}4��~�eJ/�w��i� ]��@_�_�
�8O �pIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<BIDAT8ˍ��OA��/�8&b���&('��ś1���$���41��PK�($�D�i�P��)�VmR�
i������~��l��62�s��=3�ym6�m�A�A�8`�����t]���V�TB5�}8�NG5 ]�4,�2E�E<�#�J����r�L���nop��o���n
�MӐ�硨E�$I�t���
z�þ��٫11�Y�A��pB�N�Xde���\.�L&c��� �`���>����{��(Q�c~S��0'[�B�nD��y� �i��F}���]���uL�Kx��C�S��Q �"肞}�ԗ xҾ���Pg5�,X�j�,�p�")��W�$��@�&K��� �:�����0���D�$ Oay���W.M;���'�� bD�p8��ES~�|��8���$���a��0/�*m���av_�C��_��Yx
��ӈ���=�)�H��cx��n=�\�[��L"Ů�P(��P�n?@k�.u>CK�(Z�����lf�Z�_��
[4S9 G�_�Ѝ턍��JA#�lc����o, ~���Nč3IEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8ˍ��kQ��.�q�E�����Ǫu�Ɲ�+7Ս�.,؅�E[(XhUS�@P�/�D�H(}a�EJ����ؚF�8ɴ�$����{.�$���1����sf� �F��?�cT��Ք�db�|��P(�lv��VJB����d���h��h4
EQ�D�e8.����&Z���+Ёt:�l6˯D"�@,C8�T*z��.i��Ê�n
(l@
��qD"����Oъ�:����x�Wk3� � �S�F)��"t ��q٨�؁��:�tO]�)�b�*���02GsP��ī޳�;����OM�E`�!�;����E\�p�˝�(8TA�Z�����о�fMkD8� ���˞)x�>���*v���o�_����֗n,�@(�q�5f]����=�(�;��^Ĩg�&}�>���y(���r�������5<�Ρ7��@׃%��{�����}�S�x��ߧ��I��l��X�@����~�!�/\�b��fIEND�B`�
�PNG

IHDR��agAMA��7��tEXtSoftwareAdobe ImageReadyq�e<�IDAT8�u�;hTQ���{�q�F�%�ш� ��]*k_��r]�!��IJ�+��!�A ��X)6�.I@Hv�����̙����#Ks��3��qf�����7ƣ��h�pB��n��rz�Gk�t۟������'���xl-7���1�u������4��W̌��`f,^�g������7o�c�K��i�~ *47�`m����85{!1H�s�
�94`"L̜E�`��hw������vZ=��ι`��40UT�=����V�{k�����!��h<[YY�;�vs���c����Dq��AD�ޓ�)�Je5�cj�Z}"T<&  �is�EQ� I���*0�cA1QT � EQ?ONN��t!���`��YUE%`jX#w�"2��}�D1 ��� �-���d�3����!�A�=�z�gPX��υ����-N��τ��Bɷ�o�zx�a{{��;�K'�B������]�89p��d0s�a,�IEND�B`�
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment