docs: function install(opts, cb) {
      assert.object(opts, 'opts');
      assert.optionalObject(opts.log, 'opts.log');
      assert.object(opts.enroute, 'opts.enroute');
      assert.object(opts.server, 'opts.server');
      assert.string(opts.basePath, 'opts.basePath');
      assert.optionalString(opts.excludePath, 'opts.excludePath');
      assert.optionalBool(opts.hotReload, 'opts.hotReload');
  
      var log;
  
      if (opts.log) {
          log = opts.log.child({ component : 'enroute' });
      } else {
          // only create default logger if one wasn't passed in.
          if (!LOG) {
              LOG = bunyan.createLogger({ name: 'enroute' });
          }
          log = LOG;
      }
  
      vasync.pipeline({arg: {}, funcs: [
          // Read the routes from disk and parse them as functions
          function getRoutes(ctx, cb1) {
              ctx.routes = [];
              var barrier = vasync.barrier();
              barrier.on('drain', function () {
                  return cb1();
              });
  
              if (opts.hotReload) {
                  log.info({ basePath: opts.basePath },
                          'hot reloading of routes is enabled for base dir');
              }
  
              // go through each of the route names
              _.forEach(opts.enroute.routes, function (methods, routeName) {
                  // go through each of the HTTP methods
                  _.forEach(methods, function (src, method) {
                      barrier.start(routeName + method);
                      // resolve to the correct file
                      var sourceFile = path.resolve(opts.basePath, src.source);
                      var route;
  
                      try {
                          var func = (opts.hotReload) ?
                              // restify middleware wrapper for hot reload
                              function enrouteHotReloadProxy(req, res, next) {
                                  return reloadProxy({
                                      basePath: opts.basePath,
                                      method: method,
                                      req: req,
                                      res: res,
                                      routeName: routeName,
                                      sourceFile: sourceFile,
                                      excludePath: opts.excludePath
                                  }, next);
                              } : require(sourceFile);
  
                          route = {
                              name: routeName,
                              method: method,
                              func: func
                          };
                      } catch (e) {
                          return cb1(new verror.VError({
                              name: 'EnrouteRequireError',
                              cause: e,
                              info: {
                                  file: sourceFile,
                                  route: routeName,
                                  method: method
                              }
                          }, 'failed to require file, possible syntax error'));
                      }
                      // if HTTP method is 'delete', since restify uses 'del'
                      // instead of 'delete', change it to 'del'
                      if (route.method === 'delete') {
                          route.method = 'del';
                      }
                      // if HTTP method is 'options', since restify uses
                      // 'opts' instead of 'options', change it to 'opts'
                      if (route.method === 'options') {
                          route.method = 'opts';
                      }
                      ctx.routes.push(route);
                      barrier.done(routeName + method);
                      return null;
                  });
              });
          },
          function installRoutes(ctx, cb1) {
              _.forEach(ctx.routes, function (route) {
                  var routePath = typeof route.name === 'string' &&
                       route.name[0] === '/'
                      ? route.name
                      : '/' + route.name;
                  opts.server[route.method](routePath, route.func);
              });
  
              return cb1();
          }
      ]}, function (err, res) {
          return cb(err);
      });
  }