summaryrefslogtreecommitdiff
path: root/node_modules/express/lib
diff options
context:
space:
mode:
authorJules Laplace <jules@okfoc.us>2012-09-24 16:22:07 -0400
committerJules Laplace <jules@okfoc.us>2012-09-24 16:22:07 -0400
commit686106d544ecc3b6ffd4db2b665d3bc879a58d8c (patch)
treea5b5e50237cef70e12f0745371896e96f5f6d578 /node_modules/express/lib
ok
Diffstat (limited to 'node_modules/express/lib')
-rw-r--r--node_modules/express/lib/express.js79
-rw-r--r--node_modules/express/lib/http.js582
-rw-r--r--node_modules/express/lib/https.js52
-rw-r--r--node_modules/express/lib/request.js323
-rw-r--r--node_modules/express/lib/response.js460
-rw-r--r--node_modules/express/lib/router/collection.js53
-rw-r--r--node_modules/express/lib/router/index.js398
-rw-r--r--node_modules/express/lib/router/methods.js70
-rw-r--r--node_modules/express/lib/router/route.js88
-rw-r--r--node_modules/express/lib/utils.js152
-rw-r--r--node_modules/express/lib/view.js460
-rw-r--r--node_modules/express/lib/view/partial.js40
-rw-r--r--node_modules/express/lib/view/view.js210
13 files changed, 2967 insertions, 0 deletions
diff --git a/node_modules/express/lib/express.js b/node_modules/express/lib/express.js
new file mode 100644
index 0000000..0a0d5ad
--- /dev/null
+++ b/node_modules/express/lib/express.js
@@ -0,0 +1,79 @@
+
+/*!
+ * Express
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var connect = require('connect')
+ , HTTPSServer = require('./https')
+ , HTTPServer = require('./http')
+ , Route = require('./router/route')
+
+/**
+ * Re-export connect auto-loaders.
+ *
+ * This prevents the need to `require('connect')` in order
+ * to access core middleware, so for example `express.logger()` instead
+ * of `require('connect').logger()`.
+ */
+
+var exports = module.exports = connect.middleware;
+
+/**
+ * Framework version.
+ */
+
+exports.version = '2.5.8';
+
+/**
+ * Shortcut for `new Server(...)`.
+ *
+ * @param {Function} ...
+ * @return {Server}
+ * @api public
+ */
+
+exports.createServer = function(options){
+ if ('object' == typeof options) {
+ return new HTTPSServer(options, Array.prototype.slice.call(arguments, 1));
+ } else {
+ return new HTTPServer(Array.prototype.slice.call(arguments));
+ }
+};
+
+/**
+ * Expose constructors.
+ */
+
+exports.HTTPServer = HTTPServer;
+exports.HTTPSServer = HTTPSServer;
+exports.Route = Route;
+
+/**
+ * View extensions.
+ */
+
+exports.View =
+exports.view = require('./view');
+
+/**
+ * Response extensions.
+ */
+
+require('./response');
+
+/**
+ * Request extensions.
+ */
+
+require('./request');
+
+// Error handler title
+
+exports.errorHandler.title = 'Express';
+
diff --git a/node_modules/express/lib/http.js b/node_modules/express/lib/http.js
new file mode 100644
index 0000000..da2158f
--- /dev/null
+++ b/node_modules/express/lib/http.js
@@ -0,0 +1,582 @@
+/*!
+ * Express - HTTPServer
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var qs = require('qs')
+ , connect = require('connect')
+ , router = require('./router')
+ , Router = require('./router')
+ , view = require('./view')
+ , toArray = require('./utils').toArray
+ , methods = router.methods.concat('del', 'all')
+ , url = require('url')
+ , utils = connect.utils;
+
+/**
+ * Expose `HTTPServer`.
+ */
+
+exports = module.exports = HTTPServer;
+
+/**
+ * Server proto.
+ */
+
+var app = HTTPServer.prototype;
+
+/**
+ * Initialize a new `HTTPServer` with optional `middleware`.
+ *
+ * @param {Array} middleware
+ * @api public
+ */
+
+function HTTPServer(middleware){
+ connect.HTTPServer.call(this, []);
+ this.init(middleware);
+};
+
+/**
+ * Inherit from `connect.HTTPServer`.
+ */
+
+app.__proto__ = connect.HTTPServer.prototype;
+
+/**
+ * Initialize the server.
+ *
+ * @param {Array} middleware
+ * @api private
+ */
+
+app.init = function(middleware){
+ var self = this;
+ this.cache = {};
+ this.settings = {};
+ this.redirects = {};
+ this.isCallbacks = {};
+ this._locals = {};
+ this.dynamicViewHelpers = {};
+ this.errorHandlers = [];
+
+ this.set('env', process.env.NODE_ENV || 'development');
+
+ // expose objects to each other
+ this.use(function(req, res, next){
+ req.query = req.query || {};
+ res.setHeader('X-Powered-By', 'Express');
+ req.app = res.app = self;
+ req.res = res;
+ res.req = req;
+ req.next = next;
+ // assign req.query
+ if (req.url.indexOf('?') > 0) {
+ var query = url.parse(req.url).query;
+ req.query = qs.parse(query);
+ }
+ next();
+ });
+
+ // apply middleware
+ if (middleware) middleware.forEach(self.use.bind(self));
+
+ // router
+ this.routes = new Router(this);
+ this.__defineGetter__('router', function(){
+ this.__usedRouter = true;
+ return self.routes.middleware;
+ });
+
+ // default locals
+ this.locals({
+ settings: this.settings
+ , app: this
+ });
+
+ // default development configuration
+ this.configure('development', function(){
+ this.enable('hints');
+ });
+
+ // default production configuration
+ this.configure('production', function(){
+ this.enable('view cache');
+ });
+
+ // register error handlers on "listening"
+ // so that they disregard definition position.
+ this.on('listening', this.registerErrorHandlers.bind(this));
+
+ // route manipulation methods
+ methods.forEach(function(method){
+ self.lookup[method] = function(path){
+ return self.routes.lookup(method, path);
+ };
+
+ self.match[method] = function(path){
+ return self.routes.match(method, path);
+ };
+
+ self.remove[method] = function(path){
+ return self.routes.lookup(method, path).remove();
+ };
+ });
+
+ // del -> delete
+ self.lookup.del = self.lookup.delete;
+ self.match.del = self.match.delete;
+ self.remove.del = self.remove.delete;
+};
+
+/**
+ * Remove routes matching the given `path`.
+ *
+ * @param {Route} path
+ * @return {Boolean}
+ * @api public
+ */
+
+app.remove = function(path){
+ return this.routes.lookup('all', path).remove();
+};
+
+/**
+ * Lookup routes defined with a path
+ * equivalent to `path`.
+ *
+ * @param {Stirng} path
+ * @return {Array}
+ * @api public
+ */
+
+app.lookup = function(path){
+ return this.routes.lookup('all', path);
+};
+
+/**
+ * Lookup routes matching the given `url`.
+ *
+ * @param {Stirng} url
+ * @return {Array}
+ * @api public
+ */
+
+app.match = function(url){
+ return this.routes.match('all', url);
+};
+
+/**
+ * When using the vhost() middleware register error handlers.
+ */
+
+app.onvhost = function(){
+ this.registerErrorHandlers();
+};
+
+/**
+ * Register error handlers.
+ *
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.registerErrorHandlers = function(){
+ this.errorHandlers.forEach(function(fn){
+ this.use(function(err, req, res, next){
+ fn.apply(this, arguments);
+ });
+ }, this);
+ return this;
+};
+
+/**
+ * Proxy `connect.HTTPServer#use()` to apply settings to
+ * mounted applications.
+ *
+ * @param {String|Function|Server} route
+ * @param {Function|Server} middleware
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.use = function(route, middleware){
+ var app, base, handle;
+
+ if ('string' != typeof route) {
+ middleware = route, route = '/';
+ }
+
+ // express app
+ if (middleware.handle && middleware.set) app = middleware;
+
+ // restore .app property on req and res
+ if (app) {
+ app.route = route;
+ middleware = function(req, res, next) {
+ var orig = req.app;
+ app.handle(req, res, function(err){
+ req.app = res.app = orig;
+ next(err);
+ });
+ };
+ }
+
+ connect.HTTPServer.prototype.use.call(this, route, middleware);
+
+ // mounted an app, invoke the hook
+ // and adjust some settings
+ if (app) {
+ base = this.set('basepath') || this.route;
+ if ('/' == base) base = '';
+ base = base + (app.set('basepath') || app.route);
+ app.set('basepath', base);
+ app.parent = this;
+ if (app.__mounted) app.__mounted.call(app, this);
+ }
+
+ return this;
+};
+
+/**
+ * Assign a callback `fn` which is called
+ * when this `Server` is passed to `Server#use()`.
+ *
+ * Examples:
+ *
+ * var app = express.createServer()
+ * , blog = express.createServer();
+ *
+ * blog.mounted(function(parent){
+ * // parent is app
+ * // "this" is blog
+ * });
+ *
+ * app.use(blog);
+ *
+ * @param {Function} fn
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.mounted = function(fn){
+ this.__mounted = fn;
+ return this;
+};
+
+/**
+ * See: view.register.
+ *
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.register = function(){
+ view.register.apply(this, arguments);
+ return this;
+};
+
+/**
+ * Register the given view helpers `obj`. This method
+ * can be called several times to apply additional helpers.
+ *
+ * @param {Object} obj
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.helpers =
+app.locals = function(obj){
+ utils.merge(this._locals, obj);
+ return this;
+};
+
+/**
+ * Register the given dynamic view helpers `obj`. This method
+ * can be called several times to apply additional helpers.
+ *
+ * @param {Object} obj
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.dynamicHelpers = function(obj){
+ utils.merge(this.dynamicViewHelpers, obj);
+ return this;
+};
+
+/**
+ * Map the given param placeholder `name`(s) to the given callback(s).
+ *
+ * Param mapping is used to provide pre-conditions to routes
+ * which us normalized placeholders. This callback has the same
+ * signature as regular middleware, for example below when ":userId"
+ * is used this function will be invoked in an attempt to load the user.
+ *
+ * app.param('userId', 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'));
+ * }
+ * });
+ * });
+ *
+ * Passing a single function allows you to map logic
+ * to the values passed to `app.param()`, for example
+ * this is useful to provide coercion support in a concise manner.
+ *
+ * The following example maps regular expressions to param values
+ * ensuring that they match, otherwise passing control to the next
+ * route:
+ *
+ * app.param(function(name, regexp){
+ * if (regexp instanceof RegExp) {
+ * return function(req, res, next, val){
+ * var captures;
+ * if (captures = regexp.exec(String(val))) {
+ * req.params[name] = captures;
+ * next();
+ * } else {
+ * next('route');
+ * }
+ * }
+ * }
+ * });
+ *
+ * We can now use it as shown below, where "/commit/:commit" expects
+ * that the value for ":commit" is at 5 or more digits. The capture
+ * groups are then available as `req.params.commit` as we defined
+ * in the function above.
+ *
+ * app.param('commit', /^\d{5,}$/);
+ *
+ * For more of this useful functionality take a look
+ * at [express-params](http://github.com/visionmedia/express-params).
+ *
+ * @param {String|Array|Function} name
+ * @param {Function} fn
+ * @return {Server} 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.routes.param(name);
+ // single
+ } else {
+ if (':' == name[0]) name = name.substr(1);
+ fns.forEach(function(fn){
+ self.routes.param(name, fn);
+ });
+ }
+
+ return this;
+};
+
+/**
+ * Assign a custom exception handler callback `fn`.
+ * These handlers are always _last_ in the middleware stack.
+ *
+ * @param {Function} fn
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.error = function(fn){
+ this.errorHandlers.push(fn);
+ return this;
+};
+
+/**
+ * Register the given callback `fn` for the given `type`.
+ *
+ * @param {String} type
+ * @param {Function} fn
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.is = function(type, fn){
+ if (!fn) return this.isCallbacks[type];
+ this.isCallbacks[type] = fn;
+ return this;
+};
+
+/**
+ * Assign `setting` to `val`, or return `setting`'s value.
+ * Mounted servers inherit their parent server's settings.
+ *
+ * @param {String} setting
+ * @param {String} val
+ * @return {Server|Mixed} for chaining, or the setting value
+ * @api public
+ */
+
+app.set = function(setting, val){
+ if (val === undefined) {
+ 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;
+ }
+};
+
+/**
+ * Check if `setting` is enabled.
+ *
+ * @param {String} setting
+ * @return {Boolean}
+ * @api public
+ */
+
+app.enabled = function(setting){
+ return !!this.set(setting);
+};
+
+/**
+ * Check if `setting` is disabled.
+ *
+ * @param {String} setting
+ * @return {Boolean}
+ * @api public
+ */
+
+app.disabled = function(setting){
+ return !this.set(setting);
+};
+
+/**
+ * Enable `setting`.
+ *
+ * @param {String} setting
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.enable = function(setting){
+ return this.set(setting, true);
+};
+
+/**
+ * Disable `setting`.
+ *
+ * @param {String} setting
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.disable = function(setting){
+ return this.set(setting, false);
+};
+
+/**
+ * Redirect `key` to `url`.
+ *
+ * @param {String} key
+ * @param {String} url
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.redirect = function(key, url){
+ this.redirects[key] = url;
+ return this;
+};
+
+/**
+ * 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
+ * });
+ *
+ * @param {String} env...
+ * @param {Function} fn
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.configure = function(env, fn){
+ var envs = 'all'
+ , args = toArray(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 `.route(VERB, ...)`.
+ */
+
+methods.forEach(function(method){
+ app[method] = function(path){
+ if (1 == arguments.length) return this.routes.lookup(method, path);
+ var args = [method].concat(toArray(arguments));
+ if (!this.__usedRouter) this.use(this.router);
+ return this.routes._route.apply(this.routes, args);
+ }
+});
+
+/**
+ * Special-cased "all" method, applying the given route `path`,
+ * middleware, and callback to _every_ HTTP method.
+ *
+ * @param {String} path
+ * @param {Function} ...
+ * @return {Server} for chaining
+ * @api public
+ */
+
+app.all = function(path){
+ var args = arguments;
+ if (1 == args.length) return this.routes.lookup('all', path);
+ methods.forEach(function(method){
+ if ('all' == method || 'del' == method) return;
+ app[method].apply(this, args);
+ }, this);
+ return this;
+};
+
+// del -> delete alias
+
+app.del = app.delete;
+
diff --git a/node_modules/express/lib/https.js b/node_modules/express/lib/https.js
new file mode 100644
index 0000000..8a8c008
--- /dev/null
+++ b/node_modules/express/lib/https.js
@@ -0,0 +1,52 @@
+
+/*!
+ * Express - HTTPSServer
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var connect = require('connect')
+ , HTTPServer = require('./http')
+ , https = require('https');
+
+/**
+ * Expose `HTTPSServer`.
+ */
+
+exports = module.exports = HTTPSServer;
+
+/**
+ * Server proto.
+ */
+
+var app = HTTPSServer.prototype;
+
+/**
+ * Initialize a new `HTTPSServer` with the
+ * given `options`, and optional `middleware`.
+ *
+ * @param {Object} options
+ * @param {Array} middleware
+ * @api public
+ */
+
+function HTTPSServer(options, middleware){
+ connect.HTTPSServer.call(this, options, []);
+ this.init(middleware);
+};
+
+/**
+ * Inherit from `connect.HTTPSServer`.
+ */
+
+app.__proto__ = connect.HTTPSServer.prototype;
+
+// mixin HTTPServer methods
+
+Object.keys(HTTPServer.prototype).forEach(function(method){
+ app[method] = HTTPServer.prototype[method];
+});
diff --git a/node_modules/express/lib/request.js b/node_modules/express/lib/request.js
new file mode 100644
index 0000000..1d5ab40
--- /dev/null
+++ b/node_modules/express/lib/request.js
@@ -0,0 +1,323 @@
+
+/*!
+ * Express - request
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var http = require('http')
+ , req = http.IncomingMessage.prototype
+ , utils = require('./utils')
+ , parse = require('url').parse
+ , mime = require('mime');
+
+/**
+ * Default flash formatters.
+ *
+ * @type Object
+ */
+
+var flashFormatters = exports.flashFormatters = {
+ s: function(val){
+ return String(val);
+ }
+};
+
+/**
+ * Return request header or optional default.
+ *
+ * The `Referrer` header field is special-cased,
+ * both `Referrer` and `Referer` will yield are
+ * interchangeable.
+ *
+ * Examples:
+ *
+ * req.header('Content-Type');
+ * // => "text/plain"
+ *
+ * req.header('content-type');
+ * // => "text/plain"
+ *
+ * req.header('Accept');
+ * // => undefined
+ *
+ * req.header('Accept', 'text/html');
+ * // => "text/html"
+ *
+ * @param {String} name
+ * @param {String} defaultValue
+ * @return {String}
+ * @api public
+ */
+
+req.header = function(name, defaultValue){
+ switch (name = name.toLowerCase()) {
+ case 'referer':
+ case 'referrer':
+ return this.headers.referrer
+ || this.headers.referer
+ || defaultValue;
+ default:
+ return this.headers[name] || defaultValue;
+ }
+};
+
+/**
+ * Get `field`'s `param` value, defaulting to ''.
+ *
+ * Examples:
+ *
+ * req.get('content-disposition', 'filename');
+ * // => "something.png"
+ *
+ * @param {String} field
+ * @param {String} param
+ * @return {String}
+ * @api public
+ */
+
+req.get = function(field, param){
+ var val = this.header(field);
+ if (!val) return '';
+ var regexp = new RegExp(param + ' *= *(?:"([^"]+)"|([^;]+))', 'i');
+ if (!regexp.exec(val)) return '';
+ return RegExp.$1 || RegExp.$2;
+};
+
+/**
+ * Short-hand for `require('url').parse(req.url).pathname`.
+ *
+ * @return {String}
+ * @api public
+ */
+
+req.__defineGetter__('path', function(){
+ return parse(this.url).pathname;
+});
+
+/**
+ * Check if the _Accept_ header is present, and includes the given `type`.
+ *
+ * When the _Accept_ header is not present `true` is returned. Otherwise
+ * the given `type` is matched by an exact match, and then subtypes. You
+ * may pass the subtype such as "html" which is then converted internally
+ * to "text/html" using the mime lookup table.
+ *
+ * Examples:
+ *
+ * // Accept: text/html
+ * req.accepts('html');
+ * // => true
+ *
+ * // Accept: text/*; application/json
+ * req.accepts('html');
+ * req.accepts('text/html');
+ * req.accepts('text/plain');
+ * req.accepts('application/json');
+ * // => true
+ *
+ * req.accepts('image/png');
+ * req.accepts('png');
+ * // => false
+ *
+ * @param {String} type
+ * @return {Boolean}
+ * @api public
+ */
+
+req.accepts = function(type){
+ var accept = this.header('Accept');
+
+ // normalize extensions ".json" -> "json"
+ if (type && '.' == type[0]) type = type.substr(1);
+
+ // when Accept does not exist, or is '*/*' return true
+ if (!accept || '*/*' == accept) {
+ return true;
+ } else if (type) {
+ // allow "html" vs "text/html" etc
+ if (!~type.indexOf('/')) type = mime.lookup(type);
+
+ // check if we have a direct match
+ if (~accept.indexOf(type)) return true;
+
+ // check if we have type/*
+ type = type.split('/')[0] + '/*';
+ return !!~accept.indexOf(type);
+ } else {
+ return false;
+ }
+};
+
+/**
+ * Return the value of param `name` when present or `defaultValue`.
+ *
+ * - Checks route placeholders, ex: _/user/:id_
+ * - Checks query string params, ex: ?id=12
+ * - Checks urlencoded body params, ex: id=12
+ *
+ * To utilize urlencoded 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){
+ // route params like /user/:id
+ if (this.params && this.params.hasOwnProperty(name) && undefined !== this.params[name]) {
+ return this.params[name];
+ }
+ // query string params
+ if (undefined !== this.query[name]) {
+ return this.query[name];
+ }
+ // request body params via connect.bodyParser
+ if (this.body && undefined !== this.body[name]) {
+ return this.body[name];
+ }
+ return defaultValue;
+};
+
+/**
+ * Queue flash `msg` of the given `type`.
+ *
+ * Examples:
+ *
+ * req.flash('info', 'email sent');
+ * req.flash('error', 'email delivery failed');
+ * req.flash('info', 'email re-sent');
+ * // => 2
+ *
+ * req.flash('info');
+ * // => ['email sent', 'email re-sent']
+ *
+ * req.flash('info');
+ * // => []
+ *
+ * req.flash();
+ * // => { error: ['email delivery failed'], info: [] }
+ *
+ * Formatting:
+ *
+ * Flash notifications also support arbitrary formatting support.
+ * For example you may pass variable arguments to `req.flash()`
+ * and use the %s specifier to be replaced by the associated argument:
+ *
+ * req.flash('info', 'email has been sent to %s.', userName);
+ *
+ * To add custom formatters use the `exports.flashFormatters` object.
+ *
+ * @param {String} type
+ * @param {String} msg
+ * @return {Array|Object|Number}
+ * @api public
+ */
+
+req.flash = function(type, msg){
+ if (this.session === undefined) throw Error('req.flash() requires sessions');
+ var msgs = this.session.flash = this.session.flash || {};
+ if (type && msg) {
+ var i = 2
+ , args = arguments
+ , formatters = this.app.flashFormatters || {};
+ formatters.__proto__ = flashFormatters;
+ msg = utils.miniMarkdown(msg);
+ msg = msg.replace(/%([a-zA-Z])/g, function(_, format){
+ var formatter = formatters[format];
+ if (formatter) return formatter(utils.escape(args[i++]));
+ });
+ return (msgs[type] = msgs[type] || []).push(msg);
+ } else if (type) {
+ var arr = msgs[type];
+ delete msgs[type];
+ return arr || [];
+ } else {
+ this.session.flash = {};
+ return msgs;
+ }
+};
+
+/**
+ * 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');
+ * // => true
+ *
+ * // When Content-Type is application/json
+ * req.is('json');
+ * req.is('application/json');
+ * // => true
+ *
+ * req.is('html');
+ * // => false
+ *
+ * Ad-hoc callbacks can also be registered with Express, to perform
+ * assertions again the request, for example if we need an expressive
+ * way to check if our incoming request is an image, we can register "an image"
+ * callback:
+ *
+ * app.is('an image', function(req){
+ * return 0 == req.headers['content-type'].indexOf('image');
+ * });
+ *
+ * Now within our route callbacks, we can use to to assert content types
+ * such as "image/jpeg", "image/png", etc.
+ *
+ * app.post('/image/upload', function(req, res, next){
+ * if (req.is('an image')) {
+ * // do something
+ * } else {
+ * next();
+ * }
+ * });
+ *
+ * @param {String} type
+ * @return {Boolean}
+ * @api public
+ */
+
+req.is = function(type){
+ var fn = this.app.is(type);
+ if (fn) return fn(this);
+ var ct = this.headers['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);
+};
+
+// Callback for isXMLHttpRequest / xhr
+
+function isxhr() {
+ return this.header('X-Requested-With', '').toLowerCase() === 'xmlhttprequest';
+}
+
+/**
+ * Check if the request was an _XMLHttpRequest_.
+ *
+ * @return {Boolean}
+ * @api public
+ */
+
+req.__defineGetter__('isXMLHttpRequest', isxhr);
+req.__defineGetter__('xhr', isxhr);
diff --git a/node_modules/express/lib/response.js b/node_modules/express/lib/response.js
new file mode 100644
index 0000000..a671771
--- /dev/null
+++ b/node_modules/express/lib/response.js
@@ -0,0 +1,460 @@
+
+/*!
+ * Express - response
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var fs = require('fs')
+ , http = require('http')
+ , path = require('path')
+ , connect = require('connect')
+ , utils = connect.utils
+ , parseRange = require('./utils').parseRange
+ , res = http.ServerResponse.prototype
+ , send = connect.static.send
+ , mime = require('mime')
+ , basename = path.basename
+ , join = path.join;
+
+/**
+ * Send a response with the given `body` and optional `headers` and `status` code.
+ *
+ * Examples:
+ *
+ * res.send();
+ * res.send(new Buffer('wahoo'));
+ * res.send({ some: 'json' });
+ * res.send('<p>some html</p>');
+ * res.send('Sorry, cant find that', 404);
+ * res.send('text', { 'Content-Type': 'text/plain' }, 201);
+ * res.send(404);
+ *
+ * @param {String|Object|Number|Buffer} body or status
+ * @param {Object|Number} headers or status
+ * @param {Number} status
+ * @return {ServerResponse}
+ * @api public
+ */
+
+res.send = function(body, headers, status){
+ // allow status as second arg
+ if ('number' == typeof headers) {
+ status = headers,
+ headers = null;
+ }
+
+ // default status
+ status = status || this.statusCode;
+
+ // allow 0 args as 204
+ if (!arguments.length || undefined === body) status = 204;
+
+ // determine content type
+ switch (typeof body) {
+ case 'number':
+ if (!this.header('Content-Type')) {
+ this.contentType('.txt');
+ }
+ body = http.STATUS_CODES[status = body];
+ break;
+ case 'string':
+ if (!this.header('Content-Type')) {
+ this.charset = this.charset || 'utf-8';
+ this.contentType('.html');
+ }
+ break;
+ case 'boolean':
+ case 'object':
+ if (Buffer.isBuffer(body)) {
+ if (!this.header('Content-Type')) {
+ this.contentType('.bin');
+ }
+ } else {
+ return this.json(body, headers, status);
+ }
+ break;
+ }
+
+ // populate Content-Length
+ if (undefined !== body && !this.header('Content-Length')) {
+ this.header('Content-Length', Buffer.isBuffer(body)
+ ? body.length
+ : Buffer.byteLength(body));
+ }
+
+ // merge headers passed
+ if (headers) {
+ var fields = Object.keys(headers);
+ for (var i = 0, len = fields.length; i < len; ++i) {
+ var field = fields[i];
+ this.header(field, headers[field]);
+ }
+ }
+
+ // strip irrelevant headers
+ if (204 == status || 304 == status) {
+ this.removeHeader('Content-Type');
+ this.removeHeader('Content-Length');
+ body = '';
+ }
+
+ // respond
+ this.statusCode = status;
+ this.end('HEAD' == this.req.method ? null : body);
+ return this;
+};
+
+/**
+ * Send JSON response with `obj`, optional `headers`, and optional `status`.
+ *
+ * Examples:
+ *
+ * res.json(null);
+ * res.json({ user: 'tj' });
+ * res.json('oh noes!', 500);
+ * res.json('I dont have that', 404);
+ *
+ * @param {Mixed} obj
+ * @param {Object|Number} headers or status
+ * @param {Number} status
+ * @return {ServerResponse}
+ * @api public
+ */
+
+res.json = function(obj, headers, status){
+ var body = JSON.stringify(obj)
+ , callback = this.req.query.callback
+ , jsonp = this.app.enabled('jsonp callback');
+
+ this.charset = this.charset || 'utf-8';
+ this.header('Content-Type', 'application/json');
+
+ if (callback && jsonp) {
+ this.header('Content-Type', 'text/javascript');
+ body = callback.replace(/[^\w$.]/g, '') + '(' + body + ');';
+ }
+
+ return this.send(body, headers, status);
+};
+
+/**
+ * Set status `code`.
+ *
+ * @param {Number} code
+ * @return {ServerResponse}
+ * @api public
+ */
+
+res.status = function(code){
+ this.statusCode = code;
+ return this;
+};
+
+/**
+ * Transfer the file at the given `path`. Automatically sets
+ * the _Content-Type_ response header field. `next()` is called
+ * when `path` is a directory, or when an error occurs.
+ *
+ * Options:
+ *
+ * - `maxAge` defaulting to 0
+ * - `root` root directory for relative filenames
+ *
+ * @param {String} path
+ * @param {Object|Function} options or fn
+ * @param {Function} fn
+ * @api public
+ */
+
+res.sendfile = function(path, options, fn){
+ var next = this.req.next;
+ options = options || {};
+
+ // support function as second arg
+ if ('function' == typeof options) {
+ fn = options;
+ options = {};
+ }
+
+ options.path = encodeURIComponent(path);
+ options.callback = fn;
+ send(this.req, this, next, options);
+};
+
+/**
+ * Set _Content-Type_ response header passed through `mime.lookup()`.
+ *
+ * Examples:
+ *
+ * var filename = 'path/to/image.png';
+ * res.contentType(filename);
+ * // res.headers['Content-Type'] is now "image/png"
+ *
+ * res.contentType('.html');
+ * res.contentType('html');
+ * res.contentType('json');
+ * res.contentType('png');
+ *
+ * @param {String} type
+ * @return {String} the resolved mime type
+ * @api public
+ */
+
+res.contentType = function(type){
+ return this.header('Content-Type', mime.lookup(type));
+};
+
+/**
+ * Set _Content-Disposition_ header to _attachment_ with optional `filename`.
+ *
+ * @param {String} filename
+ * @return {ServerResponse}
+ * @api public
+ */
+
+res.attachment = function(filename){
+ if (filename) this.contentType(filename);
+ this.header('Content-Disposition', filename
+ ? 'attachment; filename="' + basename(filename) + '"'
+ : 'attachment');
+ return this;
+};
+
+/**
+ * Transfer the file at the given `path`, with optional
+ * `filename` as an attachment and optional callback `fn(err)`,
+ * and optional `fn2(err)` which is invoked when an error has
+ * occurred after header has been sent.
+ *
+ * @param {String} path
+ * @param {String|Function} filename or fn
+ * @param {Function} fn
+ * @param {Function} fn2
+ * @api public
+ */
+
+res.download = function(path, filename, fn, fn2){
+ var self = this;
+
+ // support callback as second arg
+ if ('function' == typeof filename) {
+ fn2 = fn;
+ fn = filename;
+ filename = null;
+ }
+
+ // transfer the file
+ this.attachment(filename || path).sendfile(path, function(err){
+ var sentHeader = self._header;
+ if (err) {
+ if (!sentHeader) self.removeHeader('Content-Disposition');
+ if (sentHeader) {
+ fn2 && fn2(err);
+ } else if (fn) {
+ fn(err);
+ } else {
+ self.req.next(err);
+ }
+ } else if (fn) {
+ fn();
+ }
+ });
+};
+
+/**
+ * Set or get response header `name` with optional `val`.
+ *
+ * @param {String} name
+ * @param {String} val
+ * @return {ServerResponse} for chaining
+ * @api public
+ */
+
+res.header = function(name, val){
+ if (1 == arguments.length) return this.getHeader(name);
+ this.setHeader(name, val);
+ return this;
+};
+
+/**
+ * Clear cookie `name`.
+ *
+ * @param {String} name
+ * @param {Object} options
+ * @api public
+ */
+
+res.clearCookie = function(name, options){
+ var opts = { expires: new Date(1) };
+ this.cookie(name, '', options
+ ? utils.merge(options, opts)
+ : opts);
+};
+
+/**
+ * Set cookie `name` to `val`, with the given `options`.
+ *
+ * Options:
+ *
+ * - `maxAge` max-age in milliseconds, converted to `expires`
+ * - `path` defaults to the "basepath" setting which is typically "/"
+ *
+ * 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} val
+ * @param {Options} options
+ * @api public
+ */
+
+res.cookie = function(name, val, options){
+ options = options || {};
+ if ('maxAge' in options) options.expires = new Date(Date.now() + options.maxAge);
+ if (undefined === options.path) options.path = this.app.set('basepath');
+ var cookie = utils.serializeCookie(name, val, options);
+ this.header('Set-Cookie', cookie);
+};
+
+/**
+ * Redirect to the given `url` with optional response `status`
+ * defauling to 302.
+ *
+ * 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 the application's
+ * "basepath" setting. Express also supports "basepath" out of the box,
+ * which can be set via `app.set('basepath', '/blog');`, and defaults
+ * to '/'.
+ *
+ * Redirect Mapping:
+ *
+ * To extend the redirect mapping capabilities that Express provides,
+ * we may use the `app.redirect()` method:
+ *
+ * app.redirect('google', 'http://google.com');
+ *
+ * Now in a route we may call:
+ *
+ * res.redirect('google');
+ *
+ * We may also map dynamic redirects:
+ *
+ * app.redirect('comments', function(req, res){
+ * return '/post/' + req.params.id + '/comments';
+ * });
+ *
+ * So now we may do the following, and the redirect will dynamically adjust to
+ * the context of the request. If we called this route with _GET /post/12_ our
+ * redirect _Location_ would be _/post/12/comments_.
+ *
+ * app.get('/post/:id', function(req, res){
+ * res.redirect('comments');
+ * });
+ *
+ * Unless an absolute `url` is given, the app's mount-point
+ * will be respected. For example if we redirect to `/posts`,
+ * and our app is mounted at `/blog` we will redirect to `/blog/posts`.
+ *
+ * @param {String} url
+ * @param {Number} code
+ * @api public
+ */
+
+res.redirect = function(url, status){
+ var app = this.app
+ , req = this.req
+ , base = app.set('basepath') || app.route
+ , status = status || 302
+ , head = 'HEAD' == req.method
+ , body;
+
+ // Setup redirect map
+ var map = {
+ back: req.header('Referrer', base)
+ , home: base
+ };
+
+ // Support custom redirect map
+ map.__proto__ = app.redirects;
+
+ // Attempt mapped redirect
+ var mapped = 'function' == typeof map[url]
+ ? map[url](req, this)
+ : map[url];
+
+ // Perform redirect
+ url = mapped || url;
+
+ // Relative
+ if (!~url.indexOf('://')) {
+ // Respect mount-point
+ if ('/' != base && 0 != url.indexOf(base)) url = base + url;
+
+ // Absolute
+ var host = req.headers.host
+ , tls = req.connection.encrypted;
+ url = 'http' + (tls ? 's' : '') + '://' + host + url;
+ }
+
+ // Support text/{plain,html} by default
+ if (req.accepts('html')) {
+ body = '<p>' + http.STATUS_CODES[status] + '. Redirecting to <a href="' + url + '">' + url + '</a></p>';
+ this.header('Content-Type', 'text/html');
+ } else {
+ body = http.STATUS_CODES[status] + '. Redirecting to ' + url;
+ this.header('Content-Type', 'text/plain');
+ }
+
+ // Respond
+ this.statusCode = status;
+ this.header('Location', url);
+ this.end(head ? null : body);
+};
+
+/**
+ * Assign the view local variable `name` to `val` or return the
+ * local previously assigned to `name`.
+ *
+ * @param {String} name
+ * @param {Mixed} val
+ * @return {Mixed} val
+ * @api public
+ */
+
+res.local = function(name, val){
+ this._locals = this._locals || {};
+ return undefined === val
+ ? this._locals[name]
+ : this._locals[name] = val;
+};
+
+/**
+ * Assign several locals with the given `obj`,
+ * or return the locals.
+ *
+ * @param {Object} obj
+ * @return {Object|Undefined}
+ * @api public
+ */
+
+res.locals =
+res.helpers = function(obj){
+ if (obj) {
+ for (var key in obj) {
+ this.local(key, obj[key]);
+ }
+ } else {
+ return this._locals;
+ }
+};
diff --git a/node_modules/express/lib/router/collection.js b/node_modules/express/lib/router/collection.js
new file mode 100644
index 0000000..991a9a2
--- /dev/null
+++ b/node_modules/express/lib/router/collection.js
@@ -0,0 +1,53 @@
+
+/*!
+ * Express - router - Collection
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Expose `Collection`.
+ */
+
+module.exports = Collection;
+
+/**
+ * Initialize a new route `Collection`
+ * with the given `router`.
+ *
+ * @param {Router} router
+ * @api private
+ */
+
+function Collection(router) {
+ Array.apply(this, arguments);
+ this.router = router;
+}
+
+/**
+ * Inherit from `Array.prototype`.
+ */
+
+Collection.prototype.__proto__ = Array.prototype;
+
+/**
+ * Remove the routes in this collection.
+ *
+ * @return {Collection} of routes removed
+ * @api public
+ */
+
+Collection.prototype.remove = function(){
+ var router = this.router
+ , len = this.length
+ , ret = new Collection(this.router);
+
+ for (var i = 0; i < len; ++i) {
+ if (router.remove(this[i])) {
+ ret.push(this[i]);
+ }
+ }
+
+ return ret;
+};
+
diff --git a/node_modules/express/lib/router/index.js b/node_modules/express/lib/router/index.js
new file mode 100644
index 0000000..ff1498b
--- /dev/null
+++ b/node_modules/express/lib/router/index.js
@@ -0,0 +1,398 @@
+
+/*!
+ * Express - Router
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var Route = require('./route')
+ , Collection = require('./collection')
+ , utils = require('../utils')
+ , parse = require('url').parse
+ , toArray = utils.toArray;
+
+/**
+ * Expose `Router` constructor.
+ */
+
+exports = module.exports = Router;
+
+/**
+ * Expose HTTP methods.
+ */
+
+var methods = exports.methods = require('./methods');
+
+/**
+ * Initialize a new `Router` with the given `app`.
+ *
+ * @param {express.HTTPServer} app
+ * @api private
+ */
+
+function Router(app) {
+ var self = this;
+ this.app = app;
+ this.routes = {};
+ this.params = {};
+ this._params = [];
+
+ this.middleware = function(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;
+};
+
+/**
+ * Return a `Collection` of all routes defined.
+ *
+ * @return {Collection}
+ * @api public
+ */
+
+Router.prototype.all = function(){
+ return this.find(function(){
+ return true;
+ });
+};
+
+/**
+ * Remove the given `route`, returns
+ * a bool indicating if the route was present
+ * or not.
+ *
+ * @param {Route} route
+ * @return {Boolean}
+ * @api public
+ */
+
+Router.prototype.remove = function(route){
+ var routes = this.routes[route.method]
+ , len = routes.length;
+
+ for (var i = 0; i < len; ++i) {
+ if (route == routes[i]) {
+ routes.splice(i, 1);
+ return true;
+ }
+ }
+};
+
+/**
+ * Return routes with route paths matching `path`.
+ *
+ * @param {String} method
+ * @param {String} path
+ * @return {Collection}
+ * @api public
+ */
+
+Router.prototype.lookup = function(method, path){
+ return this.find(function(route){
+ return path == route.path
+ && (route.method == method
+ || method == 'all');
+ });
+};
+
+/**
+ * Return routes with regexps that match the given `url`.
+ *
+ * @param {String} method
+ * @param {String} url
+ * @return {Collection}
+ * @api public
+ */
+
+Router.prototype.match = function(method, url){
+ return this.find(function(route){
+ return route.match(url)
+ && (route.method == method
+ || method == 'all');
+ });
+};
+
+/**
+ * Find routes based on the return value of `fn`
+ * which is invoked once per route.
+ *
+ * @param {Function} fn
+ * @return {Collection}
+ * @api public
+ */
+
+Router.prototype.find = function(fn){
+ var len = methods.length
+ , ret = new Collection(this)
+ , method
+ , routes
+ , route;
+
+ for (var i = 0; i < len; ++i) {
+ method = methods[i];
+ routes = this.routes[method];
+ if (!routes) continue;
+ for (var j = 0, jlen = routes.length; j < jlen; ++j) {
+ route = routes[j];
+ if (fn(route)) ret.push(route);
+ }
+ }
+
+ return ret;
+};
+
+/**
+ * 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;
+
+ // route dispatch
+ (function pass(i, err){
+ var paramCallbacks
+ , paramIndex = 0
+ , paramVal
+ , route
+ , keys
+ , key
+ , ret;
+
+ // match next route
+ function nextRoute(err) {
+ pass(req._route_index + 1, err);
+ }
+
+ // match route
+ req.route = route = self._match(req, i);
+
+ // implied OPTIONS
+ if (!route && 'OPTIONS' == req.method) return self._options(req, res);
+
+ // no route
+ if (!route) return next(err);
+
+ // 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) {
+ fn(req, res, callbacks);
+ } else {
+ nextRoute(err);
+ }
+ } catch (err) {
+ callbacks(err);
+ }
+ }
+ })(0);
+};
+
+/**
+ * Respond to __OPTIONS__ method.
+ *
+ * @param {IncomingMessage} req
+ * @param {ServerResponse} res
+ * @api private
+ */
+
+Router.prototype._options = function(req, res){
+ var path = parse(req.url).pathname
+ , body = this._optionsFor(path).join(',');
+ res.send(body, { Allow: body });
+};
+
+/**
+ * Return an array of HTTP verbs or "options" for `path`.
+ *
+ * @param {String} path
+ * @return {Array}
+ * @api private
+ */
+
+Router.prototype._optionsFor = function(path){
+ var self = this;
+ return methods.filter(function(method){
+ var routes = self.routes[method];
+ if (!routes || 'options' == method) return;
+ for (var i = 0, len = routes.length; i < len; ++i) {
+ if (routes[i].match(path)) return true;
+ }
+ }).map(function(method){
+ return method.toUpperCase();
+ });
+};
+
+/**
+ * Attempt to match a route for `req`
+ * starting from offset `i`.
+ *
+ * @param {IncomingMessage} req
+ * @param {Number} i
+ * @return {Route}
+ * @api private
+ */
+
+Router.prototype._match = function(req, i){
+ var method = req.method.toLowerCase()
+ , url = parse(req.url)
+ , path = url.pathname
+ , routes = this.routes
+ , captures
+ , route
+ , keys;
+
+ // pass HEAD to GET routes
+ if ('head' == method) method = 'get';
+
+ // routes for this method
+ if (routes = routes[method]) {
+
+ // matching routes
+ for (var len = routes.length; i < len; ++i) {
+ route = routes[i];
+ if (captures = route.match(path)) {
+ keys = route.keys;
+ route.params = [];
+
+ // params from capture groups
+ for (var j = 1, jlen = captures.length; j < jlen; ++j) {
+ var key = keys[j-1]
+ , val = 'string' == typeof captures[j]
+ ? decodeURIComponent(captures[j])
+ : captures[j];
+ if (key) {
+ route.params[key.name] = val;
+ } else {
+ route.params.push(val);
+ }
+ }
+
+ // all done
+ req._route_index = i;
+ return route;
+ }
+ }
+ }
+};
+
+/**
+ * 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 app = this.app
+ , callbacks = utils.flatten(toArray(arguments, 2));
+
+ // ensure path was given
+ if (!path) throw new Error('app.' + method + '() requires a path');
+
+ // create the route
+ var route = new Route(method, path, callbacks, {
+ sensitive: app.enabled('case sensitive routes')
+ , strict: app.enabled('strict routing')
+ });
+
+ // add it
+ (this.routes[method] = this.routes[method] || [])
+ .push(route);
+ return this;
+};
diff --git a/node_modules/express/lib/router/methods.js b/node_modules/express/lib/router/methods.js
new file mode 100644
index 0000000..e19787b
--- /dev/null
+++ b/node_modules/express/lib/router/methods.js
@@ -0,0 +1,70 @@
+
+/*!
+ * Express - router - methods
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Hypertext Transfer Protocol -- HTTP/1.1
+ * http://www.ietf.org/rfc/rfc2616.txt
+ */
+
+var RFC2616 = ['OPTIONS', 'GET', 'POST', 'PUT', 'DELETE', 'TRACE', 'CONNECT'];
+
+/**
+ * HTTP Extensions for Distributed Authoring -- WEBDAV
+ * http://www.ietf.org/rfc/rfc2518.txt
+ */
+
+var RFC2518 = ['PROPFIND', 'PROPPATCH', 'MKCOL', 'COPY', 'MOVE', 'LOCK', 'UNLOCK'];
+
+/**
+ * Versioning Extensions to WebDAV
+ * http://www.ietf.org/rfc/rfc3253.txt
+ */
+
+var RFC3253 = ['VERSION-CONTROL', 'REPORT', 'CHECKOUT', 'CHECKIN', 'UNCHECKOUT', 'MKWORKSPACE', 'UPDATE', 'LABEL', 'MERGE', 'BASELINE-CONTROL', 'MKACTIVITY'];
+
+/**
+ * Ordered Collections Protocol (WebDAV)
+ * http://www.ietf.org/rfc/rfc3648.txt
+ */
+
+var RFC3648 = ['ORDERPATCH'];
+
+/**
+ * Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol
+ * http://www.ietf.org/rfc/rfc3744.txt
+ */
+
+var RFC3744 = ['ACL'];
+
+/**
+ * Web Distributed Authoring and Versioning (WebDAV) SEARCH
+ * http://www.ietf.org/rfc/rfc5323.txt
+ */
+
+var RFC5323 = ['SEARCH'];
+
+/**
+ * PATCH Method for HTTP
+ * http://www.ietf.org/rfc/rfc5789.txt
+ */
+
+var RFC5789 = ['PATCH'];
+
+/**
+ * Expose the methods.
+ */
+
+module.exports = [].concat(
+ RFC2616
+ , RFC2518
+ , RFC3253
+ , RFC3648
+ , RFC3744
+ , RFC5323
+ , RFC5789).map(function(method){
+ return method.toLowerCase();
+ });
diff --git a/node_modules/express/lib/router/route.js b/node_modules/express/lib/router/route.js
new file mode 100644
index 0000000..7f2965c
--- /dev/null
+++ b/node_modules/express/lib/router/route.js
@@ -0,0 +1,88 @@
+
+/*!
+ * Express - router - Route
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * 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 = normalize(path
+ , this.keys = []
+ , options.sensitive
+ , options.strict);
+}
+
+/**
+ * Check if this route matches `path` and return captures made.
+ *
+ * @param {String} path
+ * @return {Array}
+ * @api private
+ */
+
+Route.prototype.match = function(path){
+ return this.regexp.exec(path);
+};
+
+/**
+ * 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} path
+ * @param {Array} keys
+ * @param {Boolean} sensitive
+ * @param {Boolean} strict
+ * @return {RegExp}
+ * @api private
+ */
+
+function normalize(path, keys, sensitive, strict) {
+ if (path instanceof RegExp) return path;
+ path = path
+ .concat(strict ? '' : '/?')
+ .replace(/\/\(/g, '(?:/')
+ .replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?/g, function(_, slash, format, key, capture, optional){
+ keys.push({ name: key, optional: !! optional });
+ slash = slash || '';
+ return ''
+ + (optional ? '' : slash)
+ + '(?:'
+ + (optional ? slash : '')
+ + (format || '') + (capture || (format && '([^/.]+?)' || '([^/]+?)')) + ')'
+ + (optional || '');
+ })
+ .replace(/([\/.])/g, '\\$1')
+ .replace(/\*/g, '(.*)');
+ return new RegExp('^' + path + '$', sensitive ? '' : 'i');
+}
diff --git a/node_modules/express/lib/utils.js b/node_modules/express/lib/utils.js
new file mode 100644
index 0000000..d579f7c
--- /dev/null
+++ b/node_modules/express/lib/utils.js
@@ -0,0 +1,152 @@
+
+/*!
+ * Express - Utils
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * 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;
+};
+
+/**
+ * Merge object `b` with `a` giving precedence to
+ * values in object `a`.
+ *
+ * @param {Object} a
+ * @param {Object} b
+ * @return {Object} a
+ * @api private
+ */
+
+exports.union = function(a, b){
+ if (a && b) {
+ var keys = Object.keys(b)
+ , len = keys.length
+ , key;
+ for (var i = 0; i < len; ++i) {
+ key = keys[i];
+ if (!a.hasOwnProperty(key)) {
+ a[key] = b[key];
+ }
+ }
+ }
+ return a;
+};
+
+/**
+ * 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;
+};
+
+/**
+ * Parse mini markdown implementation.
+ * The following conversions are supported,
+ * primarily for the "flash" middleware:
+ *
+ * _foo_ or *foo* become <em>foo</em>
+ * __foo__ or **foo** become <strong>foo</strong>
+ * [A](B) becomes <a href="B">A</a>
+ *
+ * @param {String} str
+ * @return {String}
+ * @api private
+ */
+
+exports.miniMarkdown = function(str){
+ return String(str)
+ .replace(/(__|\*\*)(.*?)\1/g, '<strong>$2</strong>')
+ .replace(/(_|\*)(.*?)\1/g, '<em>$2</em>')
+ .replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>');
+};
+
+/**
+ * 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;');
+};
+
+/**
+ * Parse "Range" header `str` relative to the given file `size`.
+ *
+ * @param {Number} size
+ * @param {String} str
+ * @return {Array}
+ * @api private
+ */
+
+exports.parseRange = function(size, str){
+ var valid = true;
+ var arr = str.substr(6).split(',').map(function(range){
+ var range = range.split('-')
+ , start = parseInt(range[0], 10)
+ , end = parseInt(range[1], 10);
+
+ // -500
+ if (isNaN(start)) {
+ start = size - end;
+ end = size - 1;
+ // 500-
+ } else if (isNaN(end)) {
+ end = size - 1;
+ }
+
+ // Invalid
+ if (isNaN(start) || isNaN(end) || start > end) valid = false;
+
+ return { start: start, end: end };
+ });
+ return valid ? arr : undefined;
+};
+
+/**
+ * Fast alternative to `Array.prototype.slice.call()`.
+ *
+ * @param {Arguments} args
+ * @param {Number} n
+ * @return {Array}
+ * @api public
+ */
+
+exports.toArray = function(args, i){
+ var arr = []
+ , len = args.length
+ , i = i || 0;
+ for (; i < len; ++i) arr.push(args[i]);
+ return arr;
+};
diff --git a/node_modules/express/lib/view.js b/node_modules/express/lib/view.js
new file mode 100644
index 0000000..5258249
--- /dev/null
+++ b/node_modules/express/lib/view.js
@@ -0,0 +1,460 @@
+
+/*!
+ * Express - view
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var path = require('path')
+ , extname = path.extname
+ , dirname = path.dirname
+ , basename = path.basename
+ , utils = require('connect').utils
+ , View = require('./view/view')
+ , partial = require('./view/partial')
+ , union = require('./utils').union
+ , merge = utils.merge
+ , http = require('http')
+ , res = http.ServerResponse.prototype;
+
+/**
+ * Expose constructors.
+ */
+
+exports = module.exports = View;
+
+/**
+ * Export template engine registrar.
+ */
+
+exports.register = View.register;
+
+/**
+ * Lookup and compile `view` with cache support by supplying
+ * both the `cache` object and `cid` string,
+ * followed by `options` passed to `exports.lookup()`.
+ *
+ * @param {String} view
+ * @param {Object} cache
+ * @param {Object} cid
+ * @param {Object} options
+ * @return {View}
+ * @api private
+ */
+
+exports.compile = function(view, cache, cid, options){
+ if (cache && cid && cache[cid]){
+ options.filename = cache[cid].path;
+ return cache[cid];
+ }
+
+ // lookup
+ view = exports.lookup(view, options);
+
+ // hints
+ if (!view.exists) {
+ if (options.hint) hintAtViewPaths(view.original, options);
+ var err = new Error('failed to locate view "' + view.original.view + '"');
+ err.view = view.original;
+ throw err;
+ }
+
+ // compile
+ options.filename = view.path;
+ view.fn = view.templateEngine.compile(view.contents, options);
+ cache[cid] = view;
+
+ return view;
+};
+
+/**
+ * Lookup `view`, returning an instanceof `View`.
+ *
+ * Options:
+ *
+ * - `root` root directory path
+ * - `defaultEngine` default template engine
+ * - `parentView` parent `View` object
+ * - `cache` cache object
+ * - `cacheid` optional cache id
+ *
+ * Lookup:
+ *
+ * - partial `_<name>`
+ * - any `<name>/index`
+ * - non-layout `../<name>/index`
+ * - any `<root>/<name>`
+ * - partial `<root>/_<name>`
+ *
+ * @param {String} view
+ * @param {Object} options
+ * @return {View}
+ * @api private
+ */
+
+exports.lookup = function(view, options){
+ var orig = view = new View(view, options)
+ , partial = options.isPartial
+ , layout = options.isLayout;
+
+ // Try _ prefix ex: ./views/_<name>.jade
+ // taking precedence over the direct path
+ if (partial) {
+ view = new View(orig.prefixPath, options);
+ if (!view.exists) view = orig;
+ }
+
+ // Try index ex: ./views/user/index.jade
+ if (!layout && !view.exists) view = new View(orig.indexPath, options);
+
+ // Try ../<name>/index ex: ../user/index.jade
+ // when calling partial('user') within the same dir
+ if (!layout && !view.exists) view = new View(orig.upIndexPath, options);
+
+ // Try root ex: <root>/user.jade
+ if (!view.exists) view = new View(orig.rootPath, options);
+
+ // Try root _ prefix ex: <root>/_user.jade
+ if (!view.exists && partial) view = new View(view.prefixPath, options);
+
+ view.original = orig;
+ return view;
+};
+
+/**
+ * Partial render helper.
+ *
+ * @api private
+ */
+
+function renderPartial(res, view, options, parentLocals, parent){
+ var collection, object, locals;
+
+ if (options) {
+ // collection
+ if (options.collection) {
+ collection = options.collection;
+ delete options.collection;
+ } else if ('length' in options) {
+ collection = options;
+ options = {};
+ }
+
+ // locals
+ if (options.locals) {
+ locals = options.locals;
+ delete options.locals;
+ }
+
+ // object
+ if ('Object' != options.constructor.name) {
+ object = options;
+ options = {};
+ } else if (undefined != options.object) {
+ object = options.object;
+ delete options.object;
+ }
+ } else {
+ options = {};
+ }
+
+ // Inherit locals from parent
+ union(options, parentLocals);
+
+ // Merge locals
+ if (locals) merge(options, locals);
+
+ // Partials dont need layouts
+ options.isPartial = true;
+ options.layout = false;
+
+ // Deduce name from view path
+ var name = options.as || partial.resolveObjectName(view);
+
+ // Render partial
+ function render(){
+ if (object) {
+ if ('string' == typeof name) {
+ options[name] = object;
+ } else if (name === global) {
+ merge(options, object);
+ }
+ }
+ return res.render(view, options, null, parent, true);
+ }
+
+ // Collection support
+ if (collection) {
+ var len = collection.length
+ , buf = ''
+ , keys
+ , key
+ , val;
+
+ options.collectionLength = len;
+
+ if ('number' == typeof len || Array.isArray(collection)) {
+ for (var i = 0; i < len; ++i) {
+ val = collection[i];
+ options.firstInCollection = i == 0;
+ options.indexInCollection = i;
+ options.lastInCollection = i == len - 1;
+ object = val;
+ buf += render();
+ }
+ } else {
+ keys = Object.keys(collection);
+ len = keys.length;
+ options.collectionLength = len;
+ options.collectionKeys = keys;
+ for (var i = 0; i < len; ++i) {
+ key = keys[i];
+ val = collection[key];
+ options.keyInCollection = key;
+ options.firstInCollection = i == 0;
+ options.indexInCollection = i;
+ options.lastInCollection = i == len - 1;
+ object = val;
+ buf += render();
+ }
+ }
+
+ return buf;
+ } else {
+ return render();
+ }
+};
+
+/**
+ * Render `view` partial with the given `options`. Optionally a
+ * callback `fn(err, str)` may be passed instead of writing to
+ * the socket.
+ *
+ * Options:
+ *
+ * - `object` Single object with name derived from the view (unless `as` is present)
+ *
+ * - `as` Variable name for each `collection` value, defaults to the view name.
+ * * as: 'something' will add the `something` local variable
+ * * as: this will use the collection value as the template context
+ * * as: global will merge the collection value's properties with `locals`
+ *
+ * - `collection` Array of objects, the name is derived from the view name itself.
+ * For example _video.html_ will have a object _video_ available to it.
+ *
+ * @param {String} view
+ * @param {Object|Array|Function} options, collection, callback, or object
+ * @param {Function} fn
+ * @return {String}
+ * @api public
+ */
+
+res.partial = function(view, options, fn){
+ var app = this.app
+ , options = options || {}
+ , viewEngine = app.set('view engine')
+ , parent = {};
+
+ // accept callback as second argument
+ if ('function' == typeof options) {
+ fn = options;
+ options = {};
+ }
+
+ // root "views" option
+ parent.dirname = app.set('views') || process.cwd() + '/views';
+
+ // utilize "view engine" option
+ if (viewEngine) parent.engine = viewEngine;
+
+ // render the partial
+ try {
+ var str = renderPartial(this, view, options, null, parent);
+ } catch (err) {
+ if (fn) {
+ fn(err);
+ } else {
+ this.req.next(err);
+ }
+ return;
+ }
+
+ // callback or transfer
+ if (fn) {
+ fn(null, str);
+ } else {
+ this.send(str);
+ }
+};
+
+/**
+ * Render `view` with the given `options` and optional callback `fn`.
+ * When a callback function is given a response will _not_ be made
+ * automatically, however otherwise a response of _200_ and _text/html_ is given.
+ *
+ * Options:
+ *
+ * - `scope` Template evaluation context (the value of `this`)
+ * - `debug` Output debugging information
+ * - `status` Response status code
+ *
+ * @param {String} view
+ * @param {Object|Function} options or callback function
+ * @param {Function} fn
+ * @api public
+ */
+
+res.render = function(view, opts, fn, parent, sub){
+ // support callback function as second arg
+ if ('function' == typeof opts) {
+ fn = opts, opts = null;
+ }
+
+ try {
+ return this._render(view, opts, fn, parent, sub);
+ } catch (err) {
+ // callback given
+ if (fn) {
+ fn(err);
+ // unwind to root call to prevent multiple callbacks
+ } else if (sub) {
+ throw err;
+ // root template, next(err)
+ } else {
+ this.req.next(err);
+ }
+ }
+};
+
+// private render()
+
+res._render = function(view, opts, fn, parent, sub){
+ var options = {}
+ , self = this
+ , app = this.app
+ , helpers = app._locals
+ , dynamicHelpers = app.dynamicViewHelpers
+ , viewOptions = app.set('view options')
+ , root = app.set('views') || process.cwd() + '/views';
+
+ // cache id
+ var cid = app.enabled('view cache')
+ ? view + (parent ? ':' + parent.path : '')
+ : false;
+
+ // merge "view options"
+ if (viewOptions) merge(options, viewOptions);
+
+ // merge res._locals
+ if (this._locals) merge(options, this._locals);
+
+ // merge render() options
+ if (opts) merge(options, opts);
+
+ // merge render() .locals
+ if (opts && opts.locals) merge(options, opts.locals);
+
+ // status support
+ if (options.status) this.statusCode = options.status;
+
+ // capture attempts
+ options.attempts = [];
+
+ var partial = options.isPartial
+ , layout = options.layout;
+
+ // Layout support
+ if (true === layout || undefined === layout) {
+ layout = 'layout';
+ }
+
+ // Default execution scope to a plain object
+ options.scope = options.scope || {};
+
+ // Populate view
+ options.parentView = parent;
+
+ // "views" setting
+ options.root = root;
+
+ // "view engine" setting
+ options.defaultEngine = app.set('view engine');
+
+ // charset option
+ if (options.charset) this.charset = options.charset;
+
+ // Dynamic helper support
+ if (false !== options.dynamicHelpers) {
+ // cache
+ if (!this.__dynamicHelpers) {
+ this.__dynamicHelpers = {};
+ for (var key in dynamicHelpers) {
+ this.__dynamicHelpers[key] = dynamicHelpers[key].call(
+ this.app
+ , this.req
+ , this);
+ }
+ }
+
+ // apply
+ merge(options, this.__dynamicHelpers);
+ }
+
+ // Merge view helpers
+ union(options, helpers);
+
+ // Always expose partial() as a local
+ options.partial = function(path, opts){
+ return renderPartial(self, path, opts, options, view);
+ };
+
+ // View lookup
+ options.hint = app.enabled('hints');
+ view = exports.compile(view, app.cache, cid, options);
+
+ // layout helper
+ options.layout = function(path){
+ layout = path;
+ };
+
+ // render
+ var str = view.fn.call(options.scope, options);
+
+ // layout expected
+ if (layout) {
+ options.isLayout = true;
+ options.layout = false;
+ options.body = str;
+ this.render(layout, options, fn, view, true);
+ // partial return
+ } else if (partial) {
+ return str;
+ // render complete, and
+ // callback given
+ } else if (fn) {
+ fn(null, str);
+ // respond
+ } else {
+ this.send(str);
+ }
+}
+
+/**
+ * Hint at view path resolution, outputting the
+ * paths that Express has tried.
+ *
+ * @api private
+ */
+
+function hintAtViewPaths(view, options) {
+ console.error();
+ console.error('failed to locate view "' + view.view + '", tried:');
+ options.attempts.forEach(function(path){
+ console.error(' - %s', path);
+ });
+ console.error();
+}
diff --git a/node_modules/express/lib/view/partial.js b/node_modules/express/lib/view/partial.js
new file mode 100644
index 0000000..7d2f69b
--- /dev/null
+++ b/node_modules/express/lib/view/partial.js
@@ -0,0 +1,40 @@
+
+/*!
+ * Express - view - Partial
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Memory cache.
+ */
+
+var cache = {};
+
+/**
+ * Resolve partial object name from the view path.
+ *
+ * Examples:
+ *
+ * "user.ejs" becomes "user"
+ * "forum thread.ejs" becomes "forumThread"
+ * "forum/thread/post.ejs" becomes "post"
+ * "blog-post.ejs" becomes "blogPost"
+ *
+ * @return {String}
+ * @api private
+ */
+
+exports.resolveObjectName = function(view){
+ return cache[view] || (cache[view] = view
+ .split('/')
+ .slice(-1)[0]
+ .split('.')[0]
+ .replace(/^_/, '')
+ .replace(/[^a-zA-Z0-9 ]+/g, ' ')
+ .split(/ +/).map(function(word, i){
+ return i
+ ? word[0].toUpperCase() + word.substr(1)
+ : word;
+ }).join(''));
+}; \ No newline at end of file
diff --git a/node_modules/express/lib/view/view.js b/node_modules/express/lib/view/view.js
new file mode 100644
index 0000000..7d9392c
--- /dev/null
+++ b/node_modules/express/lib/view/view.js
@@ -0,0 +1,210 @@
+
+/*!
+ * Express - View
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var path = require('path')
+ , utils = require('../utils')
+ , extname = path.extname
+ , dirname = path.dirname
+ , basename = path.basename
+ , fs = require('fs')
+ , stat = fs.statSync;
+
+/**
+ * Expose `View`.
+ */
+
+exports = module.exports = View;
+
+/**
+ * Require cache.
+ */
+
+var cache = {};
+
+/**
+ * Initialize a new `View` with the given `view` path and `options`.
+ *
+ * @param {String} view
+ * @param {Object} options
+ * @api private
+ */
+
+function View(view, options) {
+ options = options || {};
+ this.view = view;
+ this.root = options.root;
+ this.relative = false !== options.relative;
+ this.defaultEngine = options.defaultEngine;
+ this.parent = options.parentView;
+ this.basename = basename(view);
+ this.engine = this.resolveEngine();
+ this.extension = '.' + this.engine;
+ this.name = this.basename.replace(this.extension, '');
+ this.path = this.resolvePath();
+ this.dirname = dirname(this.path);
+ if (options.attempts) {
+ if (!~options.attempts.indexOf(this.path))
+ options.attempts.push(this.path);
+ }
+};
+
+/**
+ * Check if the view path exists.
+ *
+ * @return {Boolean}
+ * @api public
+ */
+
+View.prototype.__defineGetter__('exists', function(){
+ try {
+ stat(this.path);
+ return true;
+ } catch (err) {
+ return false;
+ }
+});
+
+/**
+ * Resolve view engine.
+ *
+ * @return {String}
+ * @api private
+ */
+
+View.prototype.resolveEngine = function(){
+ // Explicit
+ if (~this.basename.indexOf('.')) return extname(this.basename).substr(1);
+ // Inherit from parent
+ if (this.parent) return this.parent.engine;
+ // Default
+ return this.defaultEngine;
+};
+
+/**
+ * Resolve view path.
+ *
+ * @return {String}
+ * @api private
+ */
+
+View.prototype.resolvePath = function(){
+ var path = this.view;
+ // Implicit engine
+ if (!~this.basename.indexOf('.')) path += this.extension;
+ // Absolute
+ if (utils.isAbsolute(path)) return path;
+ // Relative to parent
+ if (this.relative && this.parent) return this.parent.dirname + '/' + path;
+ // Relative to root
+ return this.root
+ ? this.root + '/' + path
+ : path;
+};
+
+/**
+ * Get view contents. This is a one-time hit, so we
+ * can afford to be sync.
+ *
+ * @return {String}
+ * @api public
+ */
+
+View.prototype.__defineGetter__('contents', function(){
+ return fs.readFileSync(this.path, 'utf8');
+});
+
+/**
+ * Get template engine api, cache exports to reduce
+ * require() calls.
+ *
+ * @return {Object}
+ * @api public
+ */
+
+View.prototype.__defineGetter__('templateEngine', function(){
+ var ext = this.extension;
+ return cache[ext] || (cache[ext] = require(this.engine));
+});
+
+/**
+ * Return root path alternative.
+ *
+ * @return {String}
+ * @api public
+ */
+
+View.prototype.__defineGetter__('rootPath', function(){
+ this.relative = false;
+ return this.resolvePath();
+});
+
+/**
+ * Return index path alternative.
+ *
+ * @return {String}
+ * @api public
+ */
+
+View.prototype.__defineGetter__('indexPath', function(){
+ return this.dirname
+ + '/' + this.basename.replace(this.extension, '')
+ + '/index' + this.extension;
+});
+
+/**
+ * Return ../<name>/index path alternative.
+ *
+ * @return {String}
+ * @api public
+ */
+
+View.prototype.__defineGetter__('upIndexPath', function(){
+ return this.dirname + '/../' + this.name + '/index' + this.extension;
+});
+
+/**
+ * Return _ prefix path alternative
+ *
+ * @return {String}
+ * @api public
+ */
+
+View.prototype.__defineGetter__('prefixPath', function(){
+ return this.dirname + '/_' + this.basename;
+});
+
+/**
+ * Register the given template engine `exports`
+ * as `ext`. For example we may wish to map ".html"
+ * files to jade:
+ *
+ * app.register('.html', require('jade'));
+ *
+ * or
+ *
+ * app.register('html', require('jade'));
+ *
+ * This is also useful for libraries that may not
+ * match extensions correctly. For example my haml.js
+ * library is installed from npm as "hamljs" so instead
+ * of layout.hamljs, we can register the engine as ".haml":
+ *
+ * app.register('.haml', require('haml-js'));
+ *
+ * @param {String} ext
+ * @param {Object} obj
+ * @api public
+ */
+
+exports.register = function(ext, exports) {
+ if ('.' != ext[0]) ext = '.' + ext;
+ cache[ext] = exports;
+};