text: // ====================
  // Packages and modules
  // ====================
  
  // native packages
  import path from 'path';
  import fs from 'fs';
  import http from 'http';
  
  // vendor packages
  import express from 'express';
  import Waterline from 'waterline';
  import React from 'react';
  import ReactDOMServer from 'react-dom/server';
  import async from 'async';
  
  // local modules
  import { DEFAULT_SETTINGS } from './constants';
  import { requireFrom, requireRawModule } from './utils';
  import { App, PageNotFound } from './classes';
  import opts from './options';
  import pOpts from './processOptions';
  import _Err from './classes/Err';
  export { _Err as Err };
  
  // ===============================
  // Private constants and variables
  // ===============================
  
  const _waterline = new Waterline();
  const _expressApp = express();
  const _settings = requireFrom.target('settings') || DEFAULT_SETTINGS;
  let _appInstMap = {};
  let _appInstArr = [];
  let _models = {};
  
  // =================
  // Private functions
  // =================
  
  // const { match, RouterContext } = require(path.join(
  //   opts.dir.root, 'node_modules/react-router'));
  const { match, RouterContext } = requireRawModule(
    opts.dir.root, 'node_modules/react-router') || {};
  
  function _getAppInstMap() {
    let appInstMap = {};
    _settings.installedApps
      .forEach((appPath) => {
        const appInst = new App(appPath);
        appInstMap[appInst.name] = appInst;
        appInstMap[appInst.alias] = appInst;
        _appInstArr.push(appInst);
      });
    return appInstMap;
  }
  
  function _forEachApp(func, done) {
    _appInstArr.forEach((element, index, arr) => {
      func(element, index, arr);
      if (index === arr.length - 1 && done !== undefined) {
        done();
      }
    });
  }
  
  function _addModel(schema) {
    // add default value for the schema
    Object.assign(schema, {
      connection: 'default',
  
      /*
       * migrate: 'alter'
       *   adds and/or removes columns on changes to the schema
       * migrate: 'drop'
       *   drops all your tables and then re-creates them. All data is deleted.
       * migrate: 'safe'
       *   doesn't do anything on sails lift- for use in production.
       */
      // Sets the schema to automatically `alter` the schema, `drop` the schema or make no changes (`safe`). Default: `alter`
      // ref: https://github.com/balderdashy/waterline-docs/blob/master/models/configuration.md#migrate
      migrate: schema.migrate || (
        opts.env.development? 'alter':
        opts.env.test? 'safe':
        'safe'),
    });
    let collections = Waterline.Collection.extend(schema);
    _waterline.loadCollection(collections);
  }
  
  function _setupWaterline(cb) {
    _forEachApp((appInst) => {
      const schemas = appInst._modelSchemas;
      if (schemas) {
        for (let key in schemas) {
          _addModel(schemas[key]);
        }
      }
    });
  
    _waterline.initialize(_settings.db[opts.env.NODE_ENV], (err, ontology) => {
      if (err) {
        return cb(err);
      }
      _models = ontology.collections;
      cb(null);
    });
  }
  
  function _initApp() {
    let appInstArr = [];
    if (pOpts.name) {
      // init specified app
      const appInst = _appInstMap[pOpts.name];
      if (appInst) {
        appInstArr.push(appInst);
      } else {
        console.error(`"${pOpts.name}" is not an installed app`);
      }
    } else {
      // init all apps
      appInstArr = _appInstArr;
    }
  
    async.eachSeries(appInstArr, (appInst, callback) => {
      console.log(`Initialize ${appInst.name}\n---\n`);
      appInst._func.init({ done: callback });
    }, () => {
      process.exit();
    });
  }
  
  function _injectLivereload() {
    console.log('using livereload');
  
    // dependencies for livereloading react
    const webpack = require('webpack');
    const config = requireFrom.cliRoot('dist/configs/webpack.livereload');
    const webpackDevMiddleware = require('webpack-dev-middleware');
    const webpackHotMiddleware = require('webpack-hot-middleware');
  
    // webpack compilation
    let appAliasArray = [];
  
    // insert entries
    _forEachApp((appInst) => {
      if (appInst._bootSrcPath) {
        config.entry[appInst.alias] = [
          appInst._bootSrcPath,
          'webpack-hot-middleware/client',
        ];
        return appInst.alias;
      }
      return false;
    });
  
    // insert resolve alias
    _forEachApp((appInst) => {
      config.resolve.alias[`@${appInst.alias}`] =
        path.join(opts.dir.src, appInst.appPath, 'flux');
    });
  
    // insert output path
    config.output.path = opts.dir.target;
  
    // insert common plugin
    config.plugins.push(
      new webpack.optimize.CommonsChunkPlugin(
        'js/common.js', appAliasArray)
    );
  
    // insert resolve paths of loaders
    config.resolveLoader = {
      modulesDirectories: [
        // the default value
        // see https://webpack.github.io/docs/configuration.html#resolveloader
        'web_loaders',
        'web_modules',
        'node_loaders',
        'node_modules',
        // use loaders (like babel-loader) installed in exseed-cli
        path.join(opts.dir.cliRoot, 'node_modules'),
      ],
    };
  
    config.resolve.modulesDirectories = [
      // the default value
      // see https://webpack.github.io/docs/configuration.html#resolve-modulesdirectories
      'web_modules',
      'node_modules',
      // only for resolving `webpack-hot-middleware/client`
      path.join(__dirname, '../node_modules'),
    ];
  
    let compiler = webpack(config, (err, stats) => {
      if (err) {
        throw err;
      }
      const jsonStats = stats.toJson();
      if (jsonStats.errors.length > 0) {
        throw jsonStats.errors;
      }
      if (jsonStats.warnings.length > 0) {
        console.warn(jsonStats.warnings);
      }
    });
  
    _expressApp.use(webpackDevMiddleware(compiler, {
      noInfo: true,
      publicPath: config.output.publicPath,
    }));
    _expressApp.use(webpackHotMiddleware(compiler));
  }
  
  function _handleStatics() {
    // global static files
    _expressApp.use(express.static(
      path.join(opts.dir.target, 'public')));
    // app's static files
    _forEachApp((appInst) => {
      _expressApp.use('/' + appInst.alias, express.static(
        path.join(opts.dir.target, appInst.name, 'public')));
    });
  }
  
  function _handleMiddlewares() {
    _forEachApp((appInst) => {
      appInst._func.middlewares({ app: _expressApp });
    });
  }
  
  function _handleRoutes() {
    _forEachApp((appInst) => {
      appInst._func.routes({ app: _expressApp });
    });
  }
  
  function _handlePageRender() {
    _forEachApp((appInst) => {
      const routes = appInst._pageRoutes;
      if (routes) {
        _expressApp.get('/*', (req, res, next) => {
          match({
            routes,
            location: req.url,
          }, (err, redirectLocation, renderProps) => {
            if (err) {
              res.status(500).send(err.message);
            } else if (redirectLocation) {
              res.redirect(
                302, redirectLocation.pathname + redirectLocation.search);
            } else if (renderProps) {
              // ref: https://github.com/rackt/react-router/issues/1414
              const notFound = renderProps.components
                .filter(component => component && component.isNotFound)
                .length > 0;
              if (notFound) {
                next();
              } else {
                const component = <RouterContext {...renderProps} />;
                res.status(200).send(renderComponent(component));
              }
            } else {
              next();
            }
          });
        });
      }
    });
  }
  
  function _handleRouteNotFound() {
    _expressApp.use((req, res, next) => {
      next(new PageNotFound());
    });
  }
  
  function _handleErrors() {
    _expressApp.use((err, req, res, next) => {
      if (err) {
        _forEachApp((appInst) => {
          appInst._func.errors({ err, req, res });
        });
  
        if (!res.headersSent) {
          _forEachApp((appInst) => {
            appInst._func.onAfterError({ err, req, res });
          });
        }
      }
    });
  }
  
  (function _main() {
    _appInstMap = _getAppInstMap();
    _setupWaterline(() => {
      // init
      if (pOpts.init) {
        _initApp();
      } else {
        // livereload
        if (opts.watch) {
          _injectLivereload();
        }
        // statics
        _handleStatics();
        // middlewares
        _handleMiddlewares();
        // routes
        _handleRoutes();
        // react full page render
        _handlePageRender();
        // 404
        _handleRouteNotFound();
        // error handling
        _handleErrors();
      }
    });
  })();
  
  // ===========
  // Public APIs
  // ===========
  
  export const env = opts.env;
  
  export { _expressApp as app };
  
  export function renderComponent(component) {
    const Helmet = requireFrom.module('react-helmet');
    const html = ReactDOMServer.renderToString(component);
    // call `rewind()` after `ReactDOM.renderToString` or `ReactDOM.renderToStaticMarkup`
    // see https://github.com/nfl/react-helmet#server-usage
    const head = Helmet.rewind();
    const title = head? head.title.toString(): '';
    const meta = head? head.meta.toString(): '';
    const link = head? head.link.toString(): '';
    return (
      '<!DOCTYPE html>' +
      '<head>' +
        title +
        meta +
        link +
      '</head>' +
      '<body>' +
        '<div id="exseed_root">' +
          html +
        '</div>' +
      '</body>'
    );
  };
  
  export function renderPath(appName, url, cb) {
    const appInst = _appInstMap[appName];
    const routes = requireFrom.target(appInst.name, 'flux/routes.js');
    match({
      routes,
      location: url,
    }, (err, redirectLocation, renderProps) => {
      if (renderProps) {
        const component = <RouterContext {...renderProps} />;
        const html = renderComponent(component);
        cb(err, html);
      } else {
        cb(err, null);
      }
    });
  }
  
  export { _models as models };