text: /*!
   * Module dependencies.
   */
  
  var DataSource = require('loopback-datasource-juggler').DataSource
    , registry = require('./registry')
    , compat = require('./compat')
    , assert = require('assert')
    , fs = require('fs')
    , extend = require('util')._extend
    , _ = require('underscore')
    , RemoteObjects = require('strong-remoting')
    , swagger = require('strong-remoting/ext/swagger')
    , stringUtils = require('underscore.string')
    , path = require('path');
  
  /**
   * The `App` object represents a Loopback application.
   * 
   * The App object extends [Express](http://expressjs.com/api.html#express) and
   * supports
   * [Express / Connect middleware](http://expressjs.com/api.html#middleware). See
   * [Express documentation](http://expressjs.com/api.html) for details.
   * 
   * ```js
   * var loopback = require('loopback');
   * var app = loopback();
   * 
   * app.get('/', function(req, res){
   *   res.send('hello world');
   * });
   * 
   * app.listen(3000);
   * ```
   * 
   * @class LoopBackApplication
   * @header var app = loopback()
   */
  function App() {
    // this is a dummy placeholder for jsdox
  }
  
  /*!
   * Export the app prototype.
   */
  
  var app = exports = module.exports = {};
  
  /**
   * Lazily load a set of [remote objects](http://apidocs.strongloop.com/strong-remoting/#remoteobjectsoptions).
   *
   * **NOTE:** Calling `app.remotes()` more than once returns only a single set of remote objects.
   * @returns {RemoteObjects}
   */
  
  app.remotes = function () {
    if(this._remotes) {
      return this._remotes;
    } else {
      var options = {};
  
      if(this.get) {
        options = this.get('remoting');
      }
       
      return (this._remotes = RemoteObjects.create(options));
    }
  }
  
  /*!
   * Remove a route by reference.
   */
  
  app.disuse = function (route) {
    if(this.stack) {
      for (var i = 0; i < this.stack.length; i++) {
        if(this.stack[i].route === route) {
          this.stack.splice(i, 1);
        }
      }
    }
  }
  
  /**
   * Attach a model to the app. The `Model` will be available on the
   * `app.models` object.
   *
   * ```js
   * // Attach an existing model
   * var User = loopback.User;
   * app.model(User);
   *
   * // Attach an existing model, alter some aspects of the model
   * var User = loopback.User;
   * app.model(User, { dataSource: 'db' });
   *
   * // The old way: create and attach a new model (deprecated)
   * var Widget = app.model('Widget', {
   *   dataSource: 'db',
   *   properties: {
   *     name: 'string'
   *   }
   * });
   * ```
   * 
   * @param {Object|String} Model The model to attach.
   * @options {Object} config The model's configuration.
   * @property {String|DataSource} dataSource The `DataSource` to which to
   * attach the model.
   * @property {Boolean} [public] whether the model should be exposed via REST API
   * @property {Object} [relations] relations to add/update
   * @end
   * @returns {ModelConstructor} the model class
   */
  
  app.model = function (Model, config) {
    var isPublic = true;
    if (arguments.length > 1) {
      config = config || {};
      if (typeof Model === 'string') {
        // create & attach the model - backwards compatibility
  
        // create config for loopback.modelFromConfig
        var modelConfig = extend({}, config);
        modelConfig.options = extend({}, config.options);
        modelConfig.name = Model;
  
        // modeller does not understand `dataSource` option
        delete modelConfig.dataSource;
  
        Model = registry.createModel(modelConfig);
  
        // delete config options already applied
        ['relations', 'base', 'acls', 'hidden'].forEach(function(prop) {
          delete config[prop];
          if (config.options) delete config.options[prop];
        });
        delete config.properties;
      }
  
      configureModel(Model, config, this);
      isPublic = config.public !== false;
    } else {
      assert(Model.prototype instanceof registry.Model,
        'Model must be a descendant of loopback.Model');
    }
  
    var modelName = Model.modelName;
    this.models[modelName] =
      this.models[classify(modelName)] =
        this.models[camelize(modelName)] = Model;
  
    this.models().push(Model);
  
    if (isPublic) {
      var remotingClassName = compat.getClassNameForRemoting(Model);
      this.remotes().exports[remotingClassName] = Model;
      clearHandlerCache(this);
    }
  
    Model.shared = isPublic; // The base Model has shared = true
    Model.app = this;
    Model.emit('attached', this);
    return Model;
  };
  
  /**
   * Get the models exported by the app. Returns only models defined using `app.model()`
   *
   * **Deprecated. Use the package
   * [loopback-boot](https://github.com/strongloop/loopback-boot) instead.**
  
   * There are two ways to access models:
   *
   * 1.  Call `app.models()` to get a list of all models.
   *
   * ```js
   * var models = app.models();
   *
   * models.forEach(function (Model) {
   *  console.log(Model.modelName); // color
   * });
   * ```
   *
   * **2. Use `app.model` to access a model by name. 
   * `app.model` has properties for all defined models.
   *
   * The following example illustrates accessing the `Product` and `CustomerReceipt` models
   * using the `models` object.
   *
   * ```js
   * var loopback = require('loopback');
   *  var app = loopback();
   *  app.boot({
   *   dataSources: {
   *     db: {connector: 'memory'}
   *   }
   * });
   *
   * app.model('product', {dataSource: 'db'});
   * app.model('customer-receipt', {dataSource: 'db'});
   *
   * // available based on the given name
   * var Product = app.models.Product;
   *
   * // also available as camelCase
   * var product = app.models.product;
   *
   * // multi-word models are avaiable as pascal cased
   * var CustomerReceipt = app.models.CustomerReceipt;
   *
   * // also available as camelCase
   * var customerReceipt = app.models.customerReceipt;
   * ```
   *
   * @returns {Array} Array of model classes.
   */
  
  app.models = function () {
    return this._models || (this._models = []);
  }
  
  /**
   * Define a DataSource.
   *
   * @param {String} name The data source name
   * @param {Object} config The data source config 
   */
  
  app.dataSource = function (name, config) {
    this.dataSources[name] =
    this.dataSources[classify(name)] =
    this.dataSources[camelize(name)] =
      dataSourcesFromConfig(config, this.connectors);
  }
  
  /**
   * Register a connector.
   *
   * When a new data-source is being added via `app.dataSource`, the connector
   * name is looked up in the registered connectors first.
   *
   * Connectors are required to be explicitly registered only for applications
   * using browserify, because browserify does not support dynamic require,
   * which is used by LoopBack to automatically load the connector module.
   *
   * @param {String} name Name of the connector, e.g. 'mysql'.
   * @param {Object} connector Connector object as returned
   *   by `require('loopback-connector-{name}')`.
   */
  app.connector = function(name, connector) {
    this.connectors[name] =
    this.connectors[classify(name)] =
    this.connectors[camelize(name)] = connector;
  };
  
  /**
   * Get all remote objects.
   * @returns {Object} [Remote objects](http://apidocs.strongloop.com/strong-remoting/#remoteobjectsoptions).
   */
  
  app.remoteObjects = function () {
    var result = {};
    var models = this.models();
    
    // add in models
    models.forEach(function (ModelCtor) {
      // only add shared models
      if(ModelCtor.shared && typeof ModelCtor.sharedCtor === 'function') {
        result[compat.getClassNameForRemoting(ModelCtor)] = ModelCtor;
      }
    });
      
    return result;
  }
  
  /**
   * Enable swagger REST API documentation.
   *
   * **Note**: This method is deprecated.  Use [loopback-explorer](http://npmjs.org/package/loopback-explorer) instead.
   *
   * **Options**
   *
   * - `basePath` The basepath for your API - eg. 'http://localhost:3000'.
   *
   * **Example**
   *
   * ```js
   * // enable docs
   * app.docs({basePath: 'http://localhost:3000'});
   * ```
   *
   * Run your app then navigate to
   * [the API explorer](http://petstore.swagger.wordnik.com/).
   * Enter your API basepath to view your generated docs.
   *
   * @deprecated
   */
   
  app.docs = function (options) {
    var remotes = this.remotes();
    swagger(remotes, options);
  }
  
  /*!
   * Get a handler of the specified type from the handler cache.
   */
   
  app.handler = function (type) {
    var handlers = this._handlers || (this._handlers = {});
    if(handlers[type]) {
      return handlers[type];
    }
    
    var remotes = this.remotes();
    var handler = this._handlers[type] = remotes.handler(type);
    return handler;
  }
  
  /**
   * An object to store dataSource instances.
   */
  
  app.dataSources = app.datasources = {};
  
  /**
   * Enable app wide authentication.
   */
  
  app.enableAuth = function() {
    var remotes = this.remotes();
    var app = this;
  
    remotes.before('**', function(ctx, next, method) {
      var req = ctx.req;
      var Model = method.ctor;
      var modelInstance = ctx.instance;
      var modelId = modelInstance && modelInstance.id || req.param('id');
  
      var modelSettings = Model.settings || {};
      var errStatusCode = modelSettings.aclErrorStatus || app.get('aclErrorStatus') || 401;
      if(!req.accessToken){
        errStatusCode = 401;
      }
  
      if(Model.checkAccess) {
        // Pause the request before checking access
        // See https://github.com/strongloop/loopback-storage-service/issues/7
        req.pause();
        Model.checkAccess(
          req.accessToken,
          modelId,
          method,
          function(err, allowed) {
            // Emit any cached data events that fired while checking access.
            req.resume();
            if(err) {
              console.log(err);
              next(err);
            } else if(allowed) {
              next();
            } else {
  
              var messages = {
                403:'Access Denied',
                404: ('could not find a model with id ' + modelId),
                401:'Authorization Required'
              };
  
              var e = new Error(messages[errStatusCode] || messages[403]);
              e.statusCode = errStatusCode;
              next(e);
            }
          }
        );
      } else {
        next();
      }
    });
  
    this.isAuthEnabled = true;
  };
  
  /**
   * Initialize an application from an options object or a set of JSON and JavaScript files.
   * 
   * This function takes an optional argument that is either a string or an object.
   * 
   * If the argument is a string, then it sets the application root directory based on the string value.  Then it:
   * 1. Creates DataSources from the `datasources.json` file in the application root directory.
   * 2. Creates Models from the `models.json` file in the application root directory.
   * 
   * If the argument is an object, then it looks for `model`, `dataSources`, and `appRootDir` properties of the object.
   * If the object has no `appRootDir` property then it sets the current working directory as the application root directory.
   * Then it:
   * 1. Creates DataSources from the `options.dataSources` object.
   * 2. Creates Models from the `options.models` object.
   *
   * In both cases, the function loads JavaScript files in the `/models` and `/boot` subdirectories of the application root directory with `require()`.
   * 
   *  **NOTE:** mixing `app.boot()` and `app.model(name, config)` in multiple
   *  files may result in models being **undefined** due to race conditions.
   *  To avoid this when using `app.boot()` make sure all models are passed as part of the `models` definition.
   *
   * Throws an error if the config object is not valid or if boot fails.
   *
   * <a name="model-definition"></a>
   * **Model Definitions**
   * 
   * The following is example JSON for two `Model` definitions: "dealership" and "location".
   * 
   * ```js
   * {
   *   "dealership": {
   *     // a reference, by name, to a dataSource definition
   *     "dataSource": "my-db",
   *     // the options passed to Model.extend(name, properties, options)
   *     "options": {
   *       "relations": {
   *         "cars": {
   *           "type": "hasMany",
   *           "model": "Car",
   *           "foreignKey": "dealerId"  
   *         }
   *       }
   *     },
   *     // the properties passed to Model.extend(name, properties, options)
   *     "properties": {
   *       "id": {"id": true},
   *       "name": "String",
   *       "zip": "Number",
   *       "address": "String"
   *     }
   *   },
   *   "car": {
   *     "dataSource": "my-db"
   *     "properties": {
   *       "id": {
   *         "type": "String",
   *         "required": true,
   *         "id": true
   *       },
   *       "make": {
   *         "type": "String",
   *         "required": true
   *       },
   *       "model": {
   *         "type": "String",
   *         "required": true
   *       }
   *     }
   *   }
   * }
   * ```
   * @options {String|Object} options Boot options; If String, this is the application root directory; if object, has below properties. 
   * @property {String} appRootDir Directory to use when loading JSON and JavaScript files (optional).  Defaults to the current directory (`process.cwd()`).
   * @property {Object} models Object containing `Model` definitions (optional).
   * @property {Object} dataSources Object containing `DataSource` definitions (optional).
   * @end
   * 
   * @header app.boot([options])
   */
  
  app.boot = function(options) {
    options = options || {};
  
    if(typeof options === 'string') {
      options = {appRootDir: options};
    }
    var app = this;
    var appRootDir = options.appRootDir = options.appRootDir || process.cwd();
    var ctx = {};
    var appConfig = options.app;
    var modelConfig = options.models;
    var dataSourceConfig = options.dataSources;
  
    if(!appConfig) {
      appConfig = tryReadConfig(appRootDir, 'app') || {};
    }
    if(!modelConfig) {
      modelConfig = tryReadConfig(appRootDir, 'models') || {};
    }
   if(!dataSourceConfig) {
    if (process.env.VCAP_APP_PORT == null) {
     dataSourceConfig = tryReadConfig(appRootDir, 'datasources') || {};
    }
    else {
     dataSourceConfig = tryReadConfig(appRootDir, 'datasourcesprod') || {};
  //   if (process.env.VCAP_SERVICES) {
  //    var env = JSON.parse(process.env.VCAP_SERVICES);
  //    var mongo = env['mongodb-2.2'][0].credentials;
  //    console.log(mongo);
  //    dataSourceConfig.mongodb.host = mongo.hostname;
  //    dataSourceConfig.mongodb.database = mongo.db;
  //    dataSourceConfig.mongodb.username = mongo.username;
  //    dataSourceConfig.mongodb.password = mongo.password;
  //    dataSourceConfig.mongodb.port = mongo.port;
  //   }
    }
    console.log(dataSourceConfig);
  
   }
  
    assertIsValidConfig('app', appConfig);
    assertIsValidConfig('model', modelConfig);
    assertIsValidConfig('data source', dataSourceConfig);
  
    appConfig.host = 
      process.env.npm_config_host ||
      process.env.OPENSHIFT_SLS_IP ||
      process.env.OPENSHIFT_NODEJS_IP ||
      process.env.HOST ||
      appConfig.host ||
      process.env.npm_package_config_host ||
      app.get('host');
  
    appConfig.port = _.find([
      process.env.npm_config_port,
      process.env.OPENSHIFT_SLS_PORT,
      process.env.OPENSHIFT_NODEJS_PORT,
      process.env.PORT,
      appConfig.port,
      process.env.npm_package_config_port,
      app.get('port'),
      3000
    ], _.isFinite);
  
    appConfig.restApiRoot =
      appConfig.restApiRoot ||
      app.get('restApiRoot') ||
      '/api';
  
    if(appConfig.host !== undefined) {
      assert(typeof appConfig.host === 'string', 'app.host must be a string');
      app.set('host', appConfig.host);
    }
  
    if(appConfig.port !== undefined) {
      var portType = typeof appConfig.port;
      assert(portType === 'string' || portType === 'number', 'app.port must be a string or number');
      app.set('port', appConfig.port);
    }
  
    assert(appConfig.restApiRoot !== undefined, 'app.restApiRoot is required');
    assert(typeof appConfig.restApiRoot === 'string', 'app.restApiRoot must be a string');
    assert(/^\//.test(appConfig.restApiRoot), 'app.restApiRoot must start with "/"');
    app.set('restApiRoot', appConfig.restApiRoot);
  
    for(var configKey in appConfig) {
      var cur = app.get(configKey);
      if(cur === undefined || cur === null) {
        app.set(configKey, appConfig[configKey]);
      }
    }
  
    // instantiate data sources
    forEachKeyedObject(dataSourceConfig, function(key, obj) {
      app.dataSource(key, obj);
    });
  
    // instantiate models
    forEachKeyedObject(modelConfig, function(key, obj) {
      app.model(key, obj);
    });
  
    // try to attach models to dataSources by type
    try {
      registry.autoAttach();
    } catch(e) {
      if(e.name === 'AssertionError') {
        console.warn(e);
      } else {
        throw e;
      }
    }
  
    // disable token requirement for swagger, if available
    var swagger = app.remotes().exports.swagger;
    var requireTokenForSwagger = appConfig.swagger
                              && appConfig.swagger.requireToken;
    if(swagger) {
      swagger.requireToken = requireTokenForSwagger || false;
    }
  
    // require directories
    var requiredModels = requireDir(path.join(appRootDir, 'models'));
    var requiredBootScripts = requireDir(path.join(appRootDir, 'boot'));
  }
  
  function assertIsValidConfig(name, config) {
    if(config) {
      assert(typeof config === 'object', name + ' config must be a valid JSON object');  
    }
  }
  
  function forEachKeyedObject(obj, fn) {
    if(typeof obj !== 'object') return;
  
    Object.keys(obj).forEach(function(key) {
      fn(key, obj[key]);
    });
  }
  
  function classify(str) {
    return stringUtils.classify(str);
  }
  
  function camelize(str) {
    return stringUtils.camelize(str);
  }
  
  function dataSourcesFromConfig(config, connectorRegistry) {
    var connectorPath;
  
    assert(typeof config === 'object', 
      'cannont create data source without config object');
  
    if(typeof config.connector === 'string') {
      var name = config.connector;
      if (connectorRegistry[name]) {
        config.connector = connectorRegistry[name];
      } else {
        connectorPath = path.join(__dirname, 'connectors', name + '.js');
  
        if (fs.existsSync(connectorPath)) {
          config.connector = require(connectorPath);
        }
      }
    }
  
    return registry.createDataSource(config);
  }
  
  function configureModel(ModelCtor, config, app) {
    assert(ModelCtor.prototype instanceof registry.Model,
      'Model must be a descendant of loopback.Model');
  
    var dataSource = config.dataSource;
  
    if(typeof dataSource === 'string') {
      dataSource = app.dataSources[dataSource];
    }
  
    assert(dataSource instanceof DataSource,
        ModelCtor.modelName + ' is referencing a dataSource that does not exist: "' +
          config.dataSource +'"');
  
    config = extend({}, config);
    config.dataSource = dataSource;
  
    registry.configureModel(ModelCtor, config);
  }
  
  function requireDir(dir, basenames) {
    assert(dir, 'cannot require directory contents without directory name');
  
    var requires = {};
  
    if (arguments.length === 2) {
      // if basenames argument is passed, explicitly include those files
      basenames.forEach(function (basename) {
        var filepath = Path.resolve(Path.join(dir, basename));
        requires[basename] = tryRequire(filepath);
      });
    } else if (arguments.length === 1) {
      // if basenames arguments isn't passed, require all javascript
      // files (except for those prefixed with _) and all directories
  
      var files = tryReadDir(dir);
  
      // sort files in lowercase alpha for linux
      files.sort(function (a,b) {
        a = a.toLowerCase();
        b = b.toLowerCase();
  
        if (a < b) {
          return -1;
        } else if (b < a) {
          return 1;
        } else {
          return 0;
        }
      });
  
      files.forEach(function (filename) {
        // ignore index.js and files prefixed with underscore
        if ((filename === 'index.js') || (filename[0] === '_')) { return; }
  
        var filepath = path.resolve(path.join(dir, filename));
        var ext = path.extname(filename);
        var stats = fs.statSync(filepath);
  
        // only require files supported by require.extensions (.txt .md etc.)
        if (stats.isFile() && !(ext in require.extensions)) { return; }
  
        var basename = path.basename(filename, ext);
  
        requires[basename] = tryRequire(filepath);
      });
  
    }
  
    return requires;
  };
  
  function tryRequire(modulePath) {
    try {
      return require.apply(this, arguments);
    } catch(e) {
      console.error('failed to require "%s"', modulePath);
      throw e;
    }
  }
  
  function tryReadDir() {
    try {
      return fs.readdirSync.apply(fs, arguments);
    } catch(e) {
      return [];
    }
  }
  
  function tryReadConfig(cwd, fileName) {
    try {
      return require(path.join(cwd, fileName + '.json'));
    } catch(e) {
      if(e.code !== "MODULE_NOT_FOUND") {
        throw e;
      }
    }
  }
  
  function clearHandlerCache(app) {
    app._handlers = undefined;
  }
  
  /*!
   * This function is now deprecated.
   * Install all express middleware required by LoopBack.
   *
   * It is possible to inject your own middleware by listening on one of the
   * following events:
   *
   *  - `middleware:preprocessors` is emitted after all other
   *    request-preprocessing middleware was installed, but before any
   *    request-handling middleware is configured.
   *
   *    Usage:
   *    ```js
   *    app.once('middleware:preprocessors', function() {
   *      app.use(loopback.limit('5.5mb'))
   *    });
   *    ```
   *  - `middleware:handlers` is emitted when it's time to add your custom
   *    request-handling middleware. Note that you should not install any
   *    express routes at this point (express routes are discussed later).
   *
   *    Usage:
   *    ```js
   *    app.once('middleware:handlers', function() {
   *      app.use('/admin', adminExpressApp);
   *      app.use('/custom', function(req, res, next) {
   *        res.send(200, { url: req.url });
   *      });
   *    });
   *    ```
   *  - `middleware:error-loggers` is emitted at the end, before the loopback
   *    error handling middleware is installed. This is the point where you
   *    can install your own middleware to log errors.
   *
   *    Notes:
   *     - The middleware function must take four parameters, otherwise it won't
   *       be called by express.
   *
   *     - It should also call `next(err)` to let the loopback error handler convert
   *       the error to an HTTP error response.
   *
   *    Usage:
   *    ```js
   *    var bunyan = require('bunyan');
   *    var log = bunyan.createLogger({name: "myapp"});
   *    app.once('middleware:error-loggers', function() {
   *      app.use(function(err, req, res, next) {
   *        log.error(err);
   *        next(err);
   *      });
   *    });
   *    ```
   *
   * Express routes should be added after `installMiddleware` was called.
   * This way the express router middleware is injected at the right place in the
   * middleware chain. If you add an express route before calling this function,
   * bad things will happen: Express will automatically add the router
   * middleware and since we haven't added request-preprocessing middleware like
   * cookie & body parser yet, your route handlers will receive raw unprocessed
   * requests.
   *
   * This is the correct order in which to call `app` methods:
   * ```js
   * app.boot(__dirname); // optional
   *
   * app.installMiddleware();
   *
   * // [register your express routes here]
   *
   * app.listen();
   * ```
   */
  app.installMiddleware = function() {
    var loopback = require('../');
  
    /*
     * Request pre-processing
     */
    this.use(loopback.favicon());
    // TODO(bajtos) refactor to app.get('loggerFormat')
    var loggerFormat = this.get('env') === 'development' ? 'dev' : 'default';
    this.use(loopback.logger(loggerFormat));
    this.use(loopback.cookieParser(this.get('cookieSecret')));
    this.use(loopback.token({ model: this.models.accessToken }));
    this.use(loopback.bodyParser());
    this.use(loopback.methodOverride());
  
    // Allow the app to install custom preprocessing middleware
    this.emit('middleware:preprocessors');
  
    /*
     * Request handling
     */
  
    // LoopBack REST transport
    this.use(this.get('restApiRoot') || '/api', loopback.rest());
  
    // Allow the app to install custom request handling middleware
    this.emit('middleware:handlers');
  
    // Let express routes handle requests that were not handled
    // by any of the middleware registered above.
    // This way LoopBack REST and API Explorer take precedence over
    // express routes.
    this.use(this.router);
  
    // The static file server should come after all other routes
    // Every request that goes through the static middleware hits
    // the file system to check if a file exists.
    this.use(loopback.static(path.join(__dirname, 'public')));
  
    // Requests that get this far won't be handled
    // by any middleware. Convert them into a 404 error
    // that will be handled later down the chain.
    this.use(loopback.urlNotFound());
  
    /*
     * Error handling
     */
  
    // Allow the app to install custom error logging middleware
    this.emit('middleware:error-handlers');
  
    // The ultimate error handler.
    this.use(loopback.errorHandler());
  };
  
  /**
   * Listen for connections and update the configured port.
   *
   * When there are no parameters or there is only one callback parameter,
   * the server will listen on `app.get('host')` and `app.get('port')`.
   *
   * ```js
   * // listen on host/port configured in app config
   * app.listen();
   * ```
   *
   * Otherwise all arguments are forwarded to `http.Server.listen`.
   *
   * ```js
   * // listen on the specified port and all hosts, ignore app config
   * app.listen(80);
   * ```
   *
   * The function also installs a `listening` callback that calls
   * `app.set('port')` with the value returned by `server.address().port`.
   * This way the port param contains always the real port number, even when
   * listen was called with port number 0.
   *
   * @param {Function} cb If specified, the callback is added as a listener
   *   for the server's "listening" event.
   * @returns {http.Server} A node `http.Server` with this application configured
   *   as the request handler.
   */
  app.listen = function(cb) {
    var self = this;
  
    var server = require('http').createServer(this);
  
    server.on('listening', function() {
      self.set('port', this.address().port);
    });
  
    var useAppConfig =
      arguments.length == 0 ||
        (arguments.length == 1 && typeof arguments[0] == 'function');
  
    if (useAppConfig) {
      server.listen(this.get('port'), this.get('host'), cb);
    } else {
      server.listen.apply(server, arguments);
    }
  
    return server;
  }
  