text: /*!
   * express
   * Copyright(c) 2009-2013 TJ Holowaychuk
   * Copyright(c) 2013 Roman Shtylman
   * Copyright(c) 2014-2015 Douglas Christopher Wilson
   * MIT Licensed
   */
  
  'use strict';
  
  /**
   * Module dependencies.
   * @private
   */
  
  var Route = require('./route');
  var Layer = require('./layer');
  var methods = require('methods');
  var mixin = require('utils-merge');
  var debug = require('debug')('express:router');
  var deprecate = require('depd')('express');
  var flatten = require('array-flatten');
  var parseUrl = require('parseurl');
  var setPrototypeOf = require('setprototypeof')
  
  /**
   * Module variables.
   * @private
   */
  
  var objectRegExp = /^\[object (\S+)\]$/;
  var slice = Array.prototype.slice;
  var toString = Object.prototype.toString;
  
  /**
   * Initialize a new `Router` with the given `options`.
   *
   * @param {Object} [options]
   * @return {Router} which is an callable function
   * @public
   */
  
  var proto = module.exports = function(options) {
    var opts = options || {};
  
    function router(req, res, next) {
      router.handle(req, res, next);
    }
  
    // mixin Router class functions
    setPrototypeOf(router, proto)
  
    router.params = {};
    router._params = [];
    router.caseSensitive = opts.caseSensitive;
    router.mergeParams = opts.mergeParams;
    router.strict = opts.strict;
    router.stack = [];
  
    return router;
  };
  
  /**
   * Map the given param placeholder `name`(s) to the given callback.
   *
   * 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 same signature as middleware, the only difference
   * 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.
   *
   * Just like in middleware, you must either respond to the request or call next
   * to avoid stalling the request.
   *
   *  app.param('user_id', function(req, res, next, id){
   *    User.find(id, function(err, user){
   *      if (err) {
   *        return next(err);
   *      } else if (!user) {
   *        return next(new Error('failed to load user'));
   *      }
   *      req.user = user;
   *      next();
   *    });
   *  });
   *
   * @param {String} name
   * @param {Function} fn
   * @return {app} for chaining
   * @public
   */
  
  proto.param = function param(name, fn) {
    // param logic
    if (typeof name === 'function') {
      deprecate('router.param(fn): Refactor to use path params');
      this._params.push(name);
      return;
    }
  
    // apply param functions
    var params = this._params;
    var len = params.length;
    var ret;
  
    if (name[0] === ':') {
      deprecate('router.param(' + JSON.stringify(name) + ', fn): Use router.param(' + JSON.stringify(name.substr(1)) + ', fn) instead');
      name = name.substr(1);
    }
  
    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;
  };
  
  /**
   * Dispatch a req, res into the router.
   * @private
   */
  
  proto.handle = function handle(req, res, out) {
    var self = this;
  
    debug('dispatching %s %s', req.method, req.url);
  
    var idx = 0;
    var protohost = getProtohost(req.url) || ''
    var removed = '';
    var slashAdded = false;
    var paramcalled = {};
  
    // store options for OPTIONS request
    // only used if OPTIONS request
    var options = [];
  
    // middleware and routes
    var stack = self.stack;
  
    // manage inter-router variables
    var parentParams = req.params;
    var parentUrl = req.baseUrl || '';
    var done = restore(out, req, 'baseUrl', 'next', 'params');
  
    // setup next layer
    req.next = next;
  
    // for options requests, respond with a default if nothing else responds
    if (req.method === 'OPTIONS') {
      done = wrap(done, function(old, err) {
        if (err || options.length === 0) return old(err);
        sendOptionsResponse(res, options, old);
      });
    }
  
    // setup basic req values
    req.baseUrl = parentUrl;
    req.originalUrl = req.originalUrl || req.url;
  
    next();
  
    function next(err) {
      var layerError = err === 'route'
        ? null
        : err;
  
      // remove added slash
      if (slashAdded) {
        req.url = req.url.substr(1);
        slashAdded = false;
      }
  
      // restore altered req.url
      if (removed.length !== 0) {
        req.baseUrl = parentUrl;
        req.url = protohost + removed + req.url.substr(protohost.length);
        removed = '';
      }
  
      // signal to exit router
      if (layerError === 'router') {
        setImmediate(done, null)
        return
      }
  
      // no more matching layers
      if (idx >= stack.length) {
        setImmediate(done, layerError);
        return;
      }
  
      // get pathname of request
      var path = getPathname(req);
  
      if (path == null) {
        return done(layerError);
      }
  
      // find next matching layer
      var layer;
      var match;
      var route;
  
      while (match !== true && idx < stack.length) {
        layer = stack[idx++];
        match = matchLayer(layer, path);
        route = layer.route;
  
        if (typeof match !== 'boolean') {
          // hold on to layerError
          layerError = layerError || match;
        }
  
        if (match !== true) {
          continue;
        }
  
        if (!route) {
          // process non-route handlers normally
          continue;
        }
  
        if (layerError) {
          // routes do not match with a pending error
          match = false;
          continue;
        }
  
        var method = req.method;
        var has_method = route._handles_method(method);
  
        // build up automatic options response
        if (!has_method && method === 'OPTIONS') {
          appendMethods(options, route._options());
        }
  
        // don't even bother matching route
        if (!has_method && method !== 'HEAD') {
          match = false;
          continue;
        }
      }
  
      // no match
      if (match !== true) {
        return done(layerError);
      }
  
      // store route for dispatch on change
      if (route) {
        req.route = route;
      }
  
      // Capture one-time layer values
      req.params = self.mergeParams
        ? mergeParams(layer.params, parentParams)
        : layer.params;
      var layerPath = layer.path;
  
      // this should be done for the layer
      self.process_params(layer, paramcalled, req, res, function (err) {
        if (err) {
          return next(layerError || err);
        }
  
        if (route) {
          return layer.handle_request(req, res, next);
        }
  
        trim_prefix(layer, layerError, layerPath, path);
      });
    }
  
    function trim_prefix(layer, layerError, layerPath, path) {
      if (layerPath.length !== 0) {
        // Validate path breaks on a path separator
        var c = path[layerPath.length]
        if (c && c !== '/' && c !== '.') return next(layerError)
  
        // Trim off the part of the url that matches the route
        // middleware (.use stuff) needs to have the path stripped
        debug('trim prefix (%s) from url %s', layerPath, req.url);
        removed = layerPath;
        req.url = protohost + req.url.substr(protohost.length + removed.length);
  
        // Ensure leading slash
        if (!protohost && req.url[0] !== '/') {
          req.url = '/' + req.url;
          slashAdded = true;
        }
  
        // Setup base URL (no trailing slash)
        req.baseUrl = parentUrl + (removed[removed.length - 1] === '/'
          ? removed.substring(0, removed.length - 1)
          : removed);
      }
  
      debug('%s %s : %s', layer.name, layerPath, req.originalUrl);
  
      if (layerError) {
        layer.handle_error(layerError, req, res, next);
      } else {
        layer.handle_request(req, res, next);
      }
    }
  };
  
  /**
   * Process any parameters for the layer.
   * @private
   */
  
  proto.process_params = function process_params(layer, called, req, res, done) {
    var params = this.params;
  
    // captured parameters from the layer, keys and values
    var keys = layer.keys;
  
    // fast track
    if (!keys || keys.length === 0) {
      return done();
    }
  
    var i = 0;
    var name;
    var paramIndex = 0;
    var key;
    var paramVal;
    var paramCallbacks;
    var paramCalled;
  
    // process params in order
    // param callbacks can be async
    function param(err) {
      if (err) {
        return done(err);
      }
  
      if (i >= keys.length ) {
        return done();
      }
  
      paramIndex = 0;
      key = keys[i++];
      name = key.name;
      paramVal = req.params[name];
      paramCallbacks = params[name];
      paramCalled = called[name];
  
      if (paramVal === undefined || !paramCallbacks) {
        return param();
      }
  
      // param previously called with same value or error occurred
      if (paramCalled && (paramCalled.match === paramVal
        || (paramCalled.error && paramCalled.error !== 'route'))) {
        // restore value
        req.params[name] = paramCalled.value;
  
        // next param
        return param(paramCalled.error);
      }
  
      called[name] = paramCalled = {
        error: null,
        match: paramVal,
        value: paramVal
      };
  
      paramCallback();
    }
  
    // single param callbacks
    function paramCallback(err) {
      var fn = paramCallbacks[paramIndex++];
  
      // store updated value
      paramCalled.value = req.params[key.name];
  
      if (err) {
        // store error
        paramCalled.error = err;
        param(err);
        return;
      }
  
      if (!fn) return param();
  
      try {
        fn(req, res, paramCallback, paramVal, key.name);
      } catch (e) {
        paramCallback(e);
      }
    }
  
    param();
  };
  
  /**
   * Use the given middleware function, with optional path, defaulting to "/".
   *
   * Use (like `.all`) will run for any http METHOD, but it will not add
   * handlers for those methods so OPTIONS requests will not consider `.use`
   * functions even if they could respond.
   *
   * The other difference is that _route_ path is stripped and not visible
   * to the handler function. The main effect of this feature is that mounted
   * handlers can operate without any code changes regardless of the "prefix"
   * pathname.
   *
   * @public
   */
  
  proto.use = function use(fn) {
    var offset = 0;
    var path = '/';
  
    // default path to '/'
    // disambiguate router.use([fn])
    if (typeof fn !== 'function') {
      var arg = fn;
  
      while (Array.isArray(arg) && arg.length !== 0) {
        arg = arg[0];
      }
  
      // first arg is the path
      if (typeof arg !== 'function') {
        offset = 1;
        path = fn;
      }
    }
  
    var callbacks = flatten(slice.call(arguments, offset));
  
    if (callbacks.length === 0) {
      throw new TypeError('Router.use() requires a middleware function')
    }
  
    for (var i = 0; i < callbacks.length; i++) {
      var fn = callbacks[i];
     
      if (typeof fn !== 'function') {
        throw new TypeError('Router.use() requires a middleware function but got a ' + gettype(fn))
      }
  
      // add the middleware
      debug('use %o %s', path, fn.name || '<anonymous>')
  
      var layer = new Layer(path, {
        sensitive: this.caseSensitive,
        strict: false,
        end: false
      }, fn);
  
      layer.route = undefined;
  
      this.stack.push(layer);
    }
  
    return this;
  };
  
  /**
   * Create a new Route for the given path.
   *
   * Each route contains a separate middleware stack and VERB handlers.
   *
   * See the Route api documentation for details on adding handlers
   * and middleware to routes.
   *
   * @param {String} path
   * @return {Route}
   * @public
   */
  
  proto.route = function route(path) {
    var route = new Route(path);
  
    var layer = new Layer(path, {
      sensitive: this.caseSensitive,
      strict: this.strict,
      end: true
    }, route.dispatch.bind(route));
  
    layer.route = route;
  
    this.stack.push(layer);
    return route;
  };
  
  // create Router#VERB functions
  methods.concat('all').forEach(function(method){
    proto[method] = function(path){
      var route = this.route(path)
      route[method].apply(route, slice.call(arguments, 1));
      return this;
    };
  });
  
  // append methods to a list of methods
  function appendMethods(list, addition) {
    for (var i = 0; i < addition.length; i++) {
      var method = addition[i];
      if (list.indexOf(method) === -1) {
        list.push(method);
      }
    }
  }
  
  // get pathname of request
  function getPathname(req) {
    try {
      return parseUrl(req).pathname;
    } catch (err) {
      return undefined;
    }
  }
  
  // Get get protocol + host for a URL
  function getProtohost(url) {
    if (typeof url !== 'string' || url.length === 0 || url[0] === '/') {
      return undefined
    }
  
    var searchIndex = url.indexOf('?')
    var pathLength = searchIndex !== -1
      ? searchIndex
      : url.length
    var fqdnIndex = url.substr(0, pathLength).indexOf('://')
  
    return fqdnIndex !== -1
      ? url.substr(0, url.indexOf('/', 3 + fqdnIndex))
      : undefined
  }
  
  // get type for error message
  function gettype(obj) {
    var type = typeof obj;
  
    if (type !== 'object') {
      return type;
    }
  
    // inspect [[Class]] for objects
    return toString.call(obj)
      .replace(objectRegExp, '$1');
  }
  
  /**
   * Match path to a layer.
   *
   * @param {Layer} layer
   * @param {string} path
   * @private
   */
  
  function matchLayer(layer, path) {
    try {
      return layer.match(path);
    } catch (err) {
      return err;
    }
  }
  
  // merge params with parent params
  function mergeParams(params, parent) {
    if (typeof parent !== 'object' || !parent) {
      return params;
    }
  
    // make copy of parent for base
    var obj = mixin({}, parent);
  
    // simple non-numeric merging
    if (!(0 in params) || !(0 in parent)) {
      return mixin(obj, params);
    }
  
    var i = 0;
    var o = 0;
  
    // determine numeric gaps
    while (i in params) {
      i++;
    }
  
    while (o in parent) {
      o++;
    }
  
    // offset numeric indices in params before merge
    for (i--; i >= 0; i--) {
      params[i + o] = params[i];
  
      // create holes for the merge when necessary
      if (i < o) {
        delete params[i];
      }
    }
  
    return mixin(obj, params);
  }
  
  // restore obj props after function
  function restore(fn, obj) {
    var props = new Array(arguments.length - 2);
    var vals = new Array(arguments.length - 2);
  
    for (var i = 0; i < props.length; i++) {
      props[i] = arguments[i + 2];
      vals[i] = obj[props[i]];
    }
  
    return function () {
      // restore vals
      for (var i = 0; i < props.length; i++) {
        obj[props[i]] = vals[i];
      }
  
      return fn.apply(this, arguments);
    };
  }
  
  // send an OPTIONS response
  function sendOptionsResponse(res, options, next) {
    try {
      var body = options.join(',');
      res.set('Allow', body);
      res.send(body);
    } catch (err) {
      next(err);
    }
  }
  
  // wrap a function
  function wrap(old, fn) {
    return function proxy() {
      var args = new Array(arguments.length + 1);
  
      args[0] = old;
      for (var i = 0, len = arguments.length; i < len; i++) {
        args[i + 1] = arguments[i];
      }
  
      fn.apply(this, args);
    };
  }
  