Commits

kai zhu  committed c78b120

move require js2 code from moduleMain to moduleInit

  • Participants
  • Parent commits 2f8b49c

Comments (0)

Files changed (4)

File moduleInit.js

+#!/usr/bin/env node
+/*FILE_BEG {"actions": ["jslint", "cover", "eval"], "name": "/FS_MODULE/moduleMain.js"}*/
+/*jslint bitwise: true, evil: true, indent: 2, nomen: true, regexp: true, stupid: true*/
+
+/**
+ * @class EXPORTS
+ */
+
+/**
+ * initialization code
+ * @module moduleInit
+ */
+
+(function () {
+
+  'use strict';
+
+  var EXPORTS = process.EXPORTS = process.EXPORTS || {}, local = {
+
+    _init: function () {
+      //// debug
+      global[String('p' + 'rintd')] = console.log;
+      //// EXPORTS
+      EXPORTS.exportLocal = local.exportLocal;
+      EXPORTS.exportLocal(local);
+      EXPORTS.require = EXPORTS.require || require;
+      EXPORTS.requireChildProcess = EXPORTS.requireChildProcess || require('child_process');
+      EXPORTS.requireCommander = EXPORTS.requireCommander || require('commander');
+      EXPORTS.requireCrypto = EXPORTS.requireCrypto || require('crypto');
+      EXPORTS.requireExpress = EXPORTS.requireExpress || require('express');
+      EXPORTS.requireFs = EXPORTS.requireFs || require('fs');
+      EXPORTS.requireFsExtra = EXPORTS.requireFsExtra || require('fs-extra');
+      EXPORTS.requireHttp = EXPORTS.requireHttp || require('http');
+      EXPORTS.requireIstanbul = EXPORTS.requireIstanbul || require('istanbul');
+      EXPORTS.requireJslintLinter = EXPORTS.requireJslintLinter || require('./node_modules/jslint/lib/linter');
+      EXPORTS.requireJslintReporter = EXPORTS.requireJslintReporter || require('./node_modules/jslint/lib/reporter');
+      EXPORTS.requireMime = EXPORTS.requireMime || require('mime');
+      EXPORTS.requireModule = EXPORTS.requireModule || require('module');
+      EXPORTS.requirePath = EXPORTS.requirePath || require('path');
+      EXPORTS.requireRepl = EXPORTS.requireRepl || require('repl');
+      EXPORTS.requireUrl = EXPORTS.requireUrl || require('url');
+      EXPORTS.requireUtil = EXPORTS.requireUtil || require('util');
+      EXPORTS.requireVm = EXPORTS.requireVm || require('vm');
+      EXPORTS.COVER = EXPORTS.COVER || new EXPORTS.requireIstanbul.Instrumenter();
+      EXPORTS.COVER_FILE = EXPORTS.COVER_FILE || {};
+      EXPORTS.FS_CWD = EXPORTS.FS_CWD || process.cwd();
+      EXPORTS.FS_MODULE = EXPORTS.FS_MODULE || EXPORTS.requirePath.dirname(module.filename);
+      EXPORTS.IS_CLI = EXPORTS.IS_CLI || module === require.main;
+      EXPORTS.JSLINT_WATCH = EXPORTS.JSLINT_WATCH || {};
+      EXPORTS.MODULE = EXPORTS.MODULE || module;
+      EXPORTS.MODULES = EXPORTS.MODULES || {};
+      EXPORTS.MODULE_ACTION = {
+        base64Decode: EXPORTS.moduleBase64Decode,
+        cover: EXPORTS.moduleCover,
+        eval: EXPORTS.moduleEval,
+        jslint: EXPORTS.moduleJslint,
+        write: EXPORTS.moduleWrite
+      };
+      /**
+       * @attribute MODULE_FILE
+       */
+      EXPORTS.MODULE_FILE = EXPORTS.MODULE_FILE || {};
+      EXPORTS.MODULE_WATCH = EXPORTS.MODULE_WATCH || {};
+      //// reload self
+      if (!EXPORTS.MODULE_FILE.hasOwnProperty(module.filename)) {
+        EXPORTS.MODULE_FILE[module.filename] = true;
+        process.nextTick(function () { EXPORTS.moduleLoad(module); });
+        return;
+      }
+      EXPORTS.requireIstanbul.Store.mix(EXPORTS.requireIstanbul.Report.create('html').opts.sourceStore.constructor, {
+        get: function (key) {
+          return EXPORTS.COVER_FILE[key];
+        }
+      });
+      EXPORTS.STR_ASCII = EXPORTS.STR_ASCII || '\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+      EXPORTS.TEST = EXPORTS.TEST || {};
+      EXPORTS.TEST_HTTP = EXPORTS.TEST_HTTP || {};
+      //// initialize command-line code
+      if (EXPORTS.IS_CLI) {
+        EXPORTS.ARGV = EXPORTS.ARGV || EXPORTS.requireCommander
+          .option('--build', 'build mode')
+          .option('--cover', 'enable code coverage')
+          .option('--debug', 'debug mode')
+          .option('--port []', 'http port', parseInt)
+          .parse(process.argv);
+        Object.keys(EXPORTS.ARGV).forEach(function (key) {
+          var val = EXPORTS.ARGV[key];
+          if (!val) { return; }
+          //// auto-set environment variables
+          try { val = JSON.parse(val); } catch (errParse) {}
+          EXPORTS['IS_' + key.replace((/\W/g), '_').toUpperCase()] = val;
+          switch (key) {
+          case 'port':
+            EXPORTS.HTTP_PORT = val;
+            break;
+          }
+        });
+        //// initialize command-line modules
+        EXPORTS.ARGV.args.forEach(function (filename) {
+          EXPORTS.moduleLoad(EXPORTS.requirePath.resolve(EXPORTS.FS_CWD, filename));
+        });
+        if (process.EXIT) { return; }
+      } else {
+        //// display environment
+        console.log(['process.argv', process.argv]);
+        console.log(['cwd', process.cwd]);
+        console.log(['nodejs', process.version]);
+        console.log(['module', module.id, module.filename]);
+      }
+      //// require
+      require.extensions['.js2'] = EXPORTS.moduleLoad;
+      require('./moduleMain.js2');
+    },
+
+    coverClear: function () {
+      //// clear __coverage__
+      var arr, cov = global.__coverage__, key, obj;
+      for (key in cov) {
+        if (cov.hasOwnProperty(key)) {
+          obj = cov[key];
+          arr = obj.b;
+          for (key in arr) { if (arr.hasOwnProperty(key)) { arr[key] = [0, 0]; } }
+          arr = obj.f;
+          for (key in arr) { if (arr.hasOwnProperty(key)) { arr[key] = 0; } }
+          arr = obj.s;
+          for (key in arr) { if (arr.hasOwnProperty(key)) { arr[key] = 0; } }
+        }
+      }
+    },
+
+    coverInstrument: function (code, filename) {
+      var ii = 0;
+      switch ((/\w*$/).exec(filename)[0]) {
+      //// instrument javascript embedded in .html file
+      case 'html':
+        EXPORTS.COVER_FILE[filename] = code;
+        return code.replace((/<script>([\S\s]+)<\/script>/g), function (_, code) {
+          return '<script>' + EXPORTS.COVER.instrumentSync(code, filename + '.script.' + (ii += 1)) + '</script>';
+        });
+      //// instrument .js file
+      case 'js':
+        EXPORTS.COVER_FILE[filename] = code;
+        return EXPORTS.COVER.instrumentSync(code, filename);
+      default:
+        return code;
+      }
+    },
+
+    coverReport: function () {
+      var collector = new EXPORTS.requireIstanbul.Collector();
+      collector.add(global.__coverage__);
+      EXPORTS.requireIstanbul.Report.create('lcov', { dir: EXPORTS.FS_CWD + '/coverage' }).writeReport(collector);
+    },
+
+    exportLocal: function (local) {
+      //// export local methods to EXPORTS
+      var arr, ii, key;
+      for (key in local) {
+        if (local.hasOwnProperty(key) && key[0] !== '_') {
+          EXPORTS[key] = local[key];
+        }
+      }
+    },
+
+    jslintReport: function (filename, code) {
+      code = code || EXPORTS.requireFs.readFileSync(filename, 'utf8');
+      //// jslint ignore
+      code = code.replace(
+        (/^\/\*JSLINT_IGNORE_BEG\*\/$[\S\s]*?^\/\*JSLINT_IGNORE_END\*\/$/gm),
+        local._jslintReportIgnore
+      );
+      switch (EXPORTS.requirePath.extname(filename)) {
+      case '.css':
+        code = code.replace((/^(\n+)@charset "UTF-8";/), '@charset "UTF-8";$1');
+        break;
+      }
+      //// jslint file and report to stdout
+      EXPORTS.requireJslintReporter.report(
+        filename,
+        EXPORTS.requireJslintLinter.lint(code),
+        true
+      );
+    },
+
+    _jslintReportIgnore: function (code) {
+      //// OPTIMIZATION - cached callback
+      return code.match('\n').join('');
+    },
+
+    /**
+     * watch file and auto-jslint if modified
+     * @method jslintWatch
+     * @param {String} filename
+     * @static
+     */
+    jslintWatch: function (filename) {
+      EXPORTS.JSLINT_WATCH[filename] = EXPORTS.JSLINT_WATCH[filename] || EXPORTS.requireFs.watchFile(
+        filename,
+        {interval: 1000, persistent: false},
+        function (curr, prev) {
+          if (curr.mtime > prev.mtime) { EXPORTS.jslintReport(filename); }
+        }
+      );
+    },
+
+    moduleBase64Decode: function (module, file, code) {
+      EXPORTS.MODULE_FILE[file.name] = new Buffer(code, 'base64');
+    },
+
+    moduleCover: function (module, file, code) {
+      if (EXPORTS.IS_COVER) {
+        EXPORTS.MODULE_FILE[file.name] = EXPORTS.coverInstrument(code, module.filename + '.' + file.name);
+      }
+    },
+
+    moduleEval: function (module, file, code) {
+      code = code.replace((/^#!/m), '// #!');
+      module._compile(code, module.filename);
+    },
+
+    moduleJslint: function (module, file, code) {
+      code = code.replace((/^#!/m), '// #!');
+      EXPORTS.jslintReport(file.name, code);
+    },
+
+    moduleLoad: function (module) {
+      //// custom module loader
+      var action, content = EXPORTS.requireFs.readFileSync(module.filename || module, 'utf8'), ii;
+      //// if module is a filename, create a new module with filename as module id
+      if (typeof module === 'string') {
+        module = EXPORTS.requirePath.resolve(EXPORTS.FS_CWD, module);
+        module = EXPORTS.MODULES[module] || new EXPORTS.requireModule.Module(module);
+        module.filename = module.filename || module.id;
+      }
+      EXPORTS.MODULES[module.filename] = module;
+      //// bump up version
+      EXPORTS.VERSION = new Date().toISOString().replace((/(....)-(..)-(..)T(..):(..):(..).*/), '$1.$2.$3-$4.$5.$6');
+      return content.replace((/^\/\*FILE_BEG (.*?)\*\/$([\S\s]*?)^\/\*FILE_END\*\/$/gm), function (_, file, code, start) {
+        file = JSON.parse(file);
+        //// filename
+        file.name = file.name.replace((/\/FS_MODULE\b/), EXPORTS.FS_MODULE);
+        //// preserve line number position
+        code = (content.slice(0, start).match(/\n/g) || []).join('') + code;
+        //// save source code
+        EXPORTS.MODULE_FILE[file.name] = EXPORTS.stringFormat ? EXPORTS.stringFormat(code, { EXPORTS: EXPORTS }) : code;
+        for (ii = 0; ii < file.actions.length; ii += 1) {
+          action = file.actions[ii];
+          EXPORTS.MODULE_ACTION[action](module, file, EXPORTS.MODULE_FILE[file.name]);
+        }
+        if (ii) {
+          //// auto-reload module if modified
+          EXPORTS.MODULE_WATCH[module.filename] = EXPORTS.MODULE_WATCH[module.filename] || EXPORTS.requireFs.watchFile(module.filename, {interval: 1000, persistent: false}, function (curr, prev) {
+            //// reload module if modified
+            if (curr.mtime > prev.mtime) { EXPORTS.moduleLoad(module, null, 'reload'); }
+          });
+        } else {
+          module._compile(content, module.id);
+        }
+      });
+    },
+
+    moduleWrite: function (module, file, code) {
+      //// write code to file
+      if (EXPORTS.IS_BUILD) {
+        EXPORTS.requireFs.writeFileSync(
+          EXPORTS.requirePath.resolve(EXPORTS.FS_CWD, file.name),
+          //// trim text
+          typeof code === 'string' ? code.trim() : code
+        );
+      }
+    }
+
+  };
+
+  local._init();
+
+}());
+/*FILE_END*/

File moduleMain.js

-#!/usr/bin/env node
-
-
-
-/*
-CHANGELOG
-fix lineno.  use module.filename instead of module.id.
-
-TODO
-add client-side interactive tests.
-rewrite db.
-*/
-
-
-
-/**
- * @class EXPORTS
- */
-
-
-
-/*FILE_BEG {"actions": ["jslint", "cover", "eval"], "name": "/FS_MODULE/moduleMain.js"}*/
-/*jslint bitwise: true, evil: true, indent: 2, nomen: true, regexp: true, stupid: true*/
-
-
-
-/**
- * initialization code
- * @module moduleInit
- */
-
-(function () {
-
-  'use strict';
-
-  var EXPORTS = process.EXPORTS = process.EXPORTS || {}, local = {
-
-    _init: function () {
-      //// debug
-      global[String('p' + 'rintd')] = console.log;
-      //// EXPORTS
-      EXPORTS.exportLocal = local.exportLocal;
-      EXPORTS.exportLocal(local);
-      EXPORTS.require = EXPORTS.require || require;
-      EXPORTS.requireChildProcess = EXPORTS.requireChildProcess || require('child_process');
-      EXPORTS.requireCommander = EXPORTS.requireCommander || require('commander');
-      EXPORTS.requireCrypto = EXPORTS.requireCrypto || require('crypto');
-      EXPORTS.requireExpress = EXPORTS.requireExpress || require('express');
-      EXPORTS.requireFs = EXPORTS.requireFs || require('fs');
-      EXPORTS.requireFsExtra = EXPORTS.requireFsExtra || require('fs-extra');
-      EXPORTS.requireHttp = EXPORTS.requireHttp || require('http');
-      EXPORTS.requireIstanbul = EXPORTS.requireIstanbul || require('istanbul');
-      EXPORTS.requireJslintLinter = EXPORTS.requireJslintLinter || require('./node_modules/jslint/lib/linter');
-      EXPORTS.requireJslintReporter = EXPORTS.requireJslintReporter || require('./node_modules/jslint/lib/reporter');
-      EXPORTS.requireMime = EXPORTS.requireMime || require('mime');
-      EXPORTS.requireModule = EXPORTS.requireModule || require('module');
-      EXPORTS.requirePath = EXPORTS.requirePath || require('path');
-      EXPORTS.requireRepl = EXPORTS.requireRepl || require('repl');
-      EXPORTS.requireUrl = EXPORTS.requireUrl || require('url');
-      EXPORTS.requireUtil = EXPORTS.requireUtil || require('util');
-      EXPORTS.requireVm = EXPORTS.requireVm || require('vm');
-      EXPORTS.COVER = EXPORTS.COVER || new EXPORTS.requireIstanbul.Instrumenter();
-      EXPORTS.COVER_FILE = EXPORTS.COVER_FILE || {};
-      EXPORTS.FS_CWD = EXPORTS.FS_CWD || process.cwd();
-      EXPORTS.FS_MODULE = EXPORTS.FS_MODULE || EXPORTS.requirePath.dirname(module.filename);
-      EXPORTS.IS_CLI = EXPORTS.IS_CLI || module === require.main;
-      EXPORTS.JSLINT_WATCH = EXPORTS.JSLINT_WATCH || {};
-      EXPORTS.MODULE = EXPORTS.MODULE || module;
-      EXPORTS.MODULES = EXPORTS.MODULES || {};
-      EXPORTS.MODULE_ACTION = {
-        base64Decode: EXPORTS.moduleBase64Decode,
-        cover: EXPORTS.moduleCover,
-        eval: EXPORTS.moduleEval,
-        jslint: EXPORTS.moduleJslint,
-        write: EXPORTS.moduleWrite
-      };
-      /**
-       * @attribute MODULE_FILE
-       */
-      EXPORTS.MODULE_FILE = EXPORTS.MODULE_FILE || {};
-      EXPORTS.MODULE_WATCH = EXPORTS.MODULE_WATCH || {};
-      EXPORTS.requireIstanbul.Store.mix(EXPORTS.requireIstanbul.Report.create('html').opts.sourceStore.constructor, {
-        get: function (key) {
-          return EXPORTS.COVER_FILE[key];
-        }
-      });
-      EXPORTS.STR_ASCII = EXPORTS.STR_ASCII || '\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
-      EXPORTS.TEST = EXPORTS.TEST || {};
-      EXPORTS.TEST_HTTP = EXPORTS.TEST_HTTP || {};
-      if (!EXPORTS.IS_CLI) {
-        //// display environment
-        console.log(['process.argv', process.argv]);
-        console.log(['cwd', process.cwd]);
-        console.log(['nodejs', process.version]);
-        console.log(['module', module.id, module.filename]);
-        return;
-      }
-      //// initialize command-line code
-      EXPORTS.ARGV = EXPORTS.ARGV || EXPORTS.requireCommander
-        .option('--build', 'build mode')
-        .option('--cover', 'enable code coverage')
-        .option('--debug', 'debug mode')
-        .option('--port []', 'http port', parseInt)
-        .parse(process.argv);
-      Object.keys(EXPORTS.ARGV).forEach(function (key) {
-        var val = EXPORTS.ARGV[key];
-        if (!val) { return; }
-        //// auto-set environment variables
-        try { val = JSON.parse(val); } catch (errParse) {}
-        EXPORTS['IS_' + key.replace((/\W/g), '_').toUpperCase()] = val;
-        switch (key) {
-        case 'port':
-          EXPORTS.HTTP_PORT = val;
-          break;
-        }
-      });
-      //// reload self
-      if (!EXPORTS.MODULE_FILE.hasOwnProperty(module.filename)) {
-        EXPORTS.moduleLoad(module);
-        return;
-      }
-      //// initialize command-line modules
-      EXPORTS.ARGV.args.forEach(function (filename) {
-        EXPORTS.moduleLoad(EXPORTS.requirePath.resolve(EXPORTS.FS_CWD, filename));
-      });
-    },
-
-    coverClear: function () {
-      //// clear __coverage__
-      var arr, cov = global.__coverage__, key, obj;
-      for (key in cov) {
-        if (cov.hasOwnProperty(key)) {
-          obj = cov[key];
-          arr = obj.b;
-          for (key in arr) { if (arr.hasOwnProperty(key)) { arr[key] = [0, 0]; } }
-          arr = obj.f;
-          for (key in arr) { if (arr.hasOwnProperty(key)) { arr[key] = 0; } }
-          arr = obj.s;
-          for (key in arr) { if (arr.hasOwnProperty(key)) { arr[key] = 0; } }
-        }
-      }
-    },
-
-    coverInstrument: function (code, filename) {
-      var ii = 0;
-      switch ((/\w*$/).exec(filename)[0]) {
-      //// instrument javascript embedded in .html file
-      case 'html':
-        EXPORTS.COVER_FILE[filename] = code;
-        return code.replace((/<script>([\S\s]+)<\/script>/g), function (_, code) {
-          return '<script>' + EXPORTS.COVER.instrumentSync(code, filename + '.script.' + (ii += 1)) + '</script>';
-        });
-      //// instrument .js file
-      case 'js':
-        EXPORTS.COVER_FILE[filename] = code;
-        return EXPORTS.COVER.instrumentSync(code, filename);
-      default:
-        return code;
-      }
-    },
-
-    coverReport: function () {
-      var collector = new EXPORTS.requireIstanbul.Collector();
-      collector.add(global.__coverage__);
-      EXPORTS.requireIstanbul.Report.create('lcov', { dir: EXPORTS.FS_CWD + '/coverage' }).writeReport(collector);
-    },
-
-    exportLocal: function (local) {
-      //// export local methods to EXPORTS
-      var arr, ii, key;
-      for (key in local) {
-        if (local.hasOwnProperty(key) && key[0] !== '_') {
-          EXPORTS[key] = local[key];
-        }
-      }
-    },
-
-    jslintReport: function (filename, code) {
-      code = code || EXPORTS.requireFs.readFileSync(filename, 'utf8');
-      //// jslint ignore
-      code = code.replace(
-        (/^\/\*JSLINT_IGNORE_BEG\*\/$[\S\s]*?^\/\*JSLINT_IGNORE_END\*\/$/gm),
-        local._jslintReportIgnore
-      );
-      switch (EXPORTS.requirePath.extname(filename)) {
-      case '.css':
-        code = code.replace((/^(\n+)@charset "UTF-8";/), '@charset "UTF-8";$1');
-        break;
-      }
-      //// jslint file and report to stdout
-      EXPORTS.requireJslintReporter.report(
-        filename,
-        EXPORTS.requireJslintLinter.lint(code),
-        true
-      );
-    },
-
-    _jslintReportIgnore: function (code) {
-      //// OPTIMIZATION - cached callback
-      return code.match('\n').join('');
-    },
-
-    /**
-     * watch file and auto-jslint if modified
-     * @method jslintWatch
-     * @param {String} filename
-     * @static
-     */
-    jslintWatch: function (filename) {
-      EXPORTS.JSLINT_WATCH[filename] = EXPORTS.JSLINT_WATCH[filename] || EXPORTS.requireFs.watchFile(
-        filename,
-        {interval: 1000, persistent: false},
-        function (curr, prev) {
-          if (curr.mtime > prev.mtime) { EXPORTS.jslintReport(filename); }
-        }
-      );
-    },
-
-    moduleBase64Decode: function (module, file, code) {
-      EXPORTS.MODULE_FILE[file.name] = new Buffer(code, 'base64');
-    },
-
-    moduleCover: function (module, file, code) {
-      if (EXPORTS.IS_COVER) {
-        EXPORTS.MODULE_FILE[file.name] = EXPORTS.coverInstrument(code, module.filename + '.' + file.name);
-      }
-    },
-
-    moduleEval: function (module, file, code) {
-      code = code.replace((/^#!/m), '// #!');
-      module._compile(code, module.filename);
-    },
-
-    moduleJslint: function (module, file, code) {
-      code = code.replace((/^#!/m), '// #!');
-      EXPORTS.jslintReport(file.name, code);
-    },
-
-    moduleLoad: function (module) {
-      //// custom module loader
-      var action, content = EXPORTS.requireFs.readFileSync(module.filename || module, 'utf8'), ii;
-      //// if module is a filename, create a new module with filename as module id
-      if (typeof module === 'string') {
-        module = EXPORTS.requirePath.resolve(EXPORTS.FS_CWD, module);
-        module = EXPORTS.MODULES[module] || new EXPORTS.requireModule.Module(module);
-        module.filename = module.filename || module.id;
-      }
-      EXPORTS.MODULES[module.filename] = module;
-      //// bump up version
-      EXPORTS.VERSION = new Date().toISOString().replace((/(....)-(..)-(..)T(..):(..):(..).*/), '$1.$2.$3-$4.$5.$6');
-      return content.replace((/^\/\*FILE_BEG (.*?)\*\/$([\S\s]*?)^\/\*FILE_END\*\/$/gm), function (_, file, code, start) {
-        file = JSON.parse(file);
-        //// filename
-        file.name = file.name.replace((/\/FS_MODULE\b/), EXPORTS.FS_MODULE);
-        //// preserve line number position
-        code = (content.slice(0, start).match(/\n/g) || []).join('') + code;
-        //// save source code
-        EXPORTS.MODULE_FILE[file.name] = EXPORTS.stringFormat ? EXPORTS.stringFormat(code, { EXPORTS: EXPORTS }) : code;
-        for (ii = 0; ii < file.actions.length; ii += 1) {
-          action = file.actions[ii];
-          EXPORTS.MODULE_ACTION[action](module, file, EXPORTS.MODULE_FILE[file.name]);
-        }
-        if (ii) {
-          //// auto-reload module if modified
-          EXPORTS.MODULE_WATCH[module.filename] = EXPORTS.MODULE_WATCH[module.filename] || EXPORTS.requireFs.watchFile(module.filename, {interval: 1000, persistent: false}, function (curr, prev) {
-            //// reload module if modified
-            if (curr.mtime > prev.mtime) { EXPORTS.moduleLoad(module, null, 'reload'); }
-          });
-        } else {
-          module._compile(content, module.id);
-        }
-      });
-    },
-
-    moduleWrite: function (module, file, code) {
-      //// write code to file
-      if (EXPORTS.IS_BUILD) {
-        EXPORTS.requireFs.writeFileSync(
-          EXPORTS.requirePath.resolve(EXPORTS.FS_CWD, file.name),
-          //// trim text
-          typeof code === 'string' ? code.trim() : code
-        );
-      }
-    }
-
-  };
-
-  local._init();
-
-}());
-
-
-
-/**
- * @module moduleGist
- */
-
-(function () {
-
-  'use strict';
-
-  var EXPORTS = process.EXPORTS || {}, local = {
-
-    _init: function () {
-      //// EXPORTS
-      EXPORTS.exportLocal(local);
-    },
-
-    arrayZeros: function (length) {
-      var arr = [], ii = length;
-      while (ii > 0) {
-        arr.push(0);
-        ii -= 1;
-      }
-      return arr;
-    },
-
-    hashSha256: function (str) {
-      var hash = require('crypto').createHash('sha256');
-      hash.update(typeof str === 'string' || Buffer.isBuffer(str) ? str : String(str));
-      return hash.digest('hex');
-    },
-
-    /**
-     * JSON.stringify circular object
-     * @method jsonStringifyCircular
-     * @param {Object} obj
-     * @return {String}
-     * @static
-     */
-    jsonStringifyCircular: function (obj) {
-      return local._jsonStringifyCircularRecurse(obj, []);
-    },
-
-    _jsonStringifyCircularRecurse: function (obj, arr) {
-      var ii, keys, result, val;
-      if (obj) {
-        for (ii = 0; ii < arr.length; ii += 1) {
-          if (obj === arr[ii]) {
-            obj = '[Circular]';
-            break;
-          }
-        }
-      }
-      try {
-        return JSON.stringify(obj);
-      } catch (err) {
-      }
-      //// fallback
-      arr.push(obj);
-      result = '';
-      //// array
-      if (Array.isArray(obj)) {
-        for (ii = 0; ii < obj.length; ii += 1) {
-          val = local._jsonStringifyCircularRecurse(obj[ii], arr);
-          if (val !== undefined) {
-            result += val + ',';
-          }
-        }
-        return '[' + result.slice(0, -1) + ']';
-      }
-      //// object
-      keys = Object.keys(obj).sort();
-      for (ii = 0; ii < keys.length; ii += 1) {
-        val = local._jsonStringifyCircularRecurse(obj[keys[ii]], arr);
-        if (val !== undefined) {
-          result += JSON.stringify(keys[ii]) + ':' + val + ',';
-        }
-      }
-      return '{' + result.slice(0, -1) + '}';
-    },
-
-    jsonStringifySorted: function (obj) {
-      //// recursively JSON.stringify dictionaries in sorted-key order
-      var ii, keys, result, val;
-      result = '';
-      //// array
-      if (Array.isArray(obj)) {
-        for (ii = 0; ii < obj.length; ii += 1) {
-          val = local.jsonStringifySorted(obj[ii]);
-          if (val !== undefined) {
-            result += val + ',';
-          }
-        }
-        return '[' + result.slice(0, -1) + ']';
-      }
-      //// object
-      if (typeof obj === 'object' && obj !== null) {
-        keys = Object.keys(obj).sort();
-        for (ii = 0; ii < keys.length; ii += 1) {
-          val = local.jsonStringifySorted(obj[keys[ii]]);
-          if (val !== undefined) {
-            result += JSON.stringify(keys[ii]) + ':' + val + ',';
-          }
-        }
-        return '{' + result.slice(0, -1) + '}';
-      }
-      return JSON.stringify(obj);
-    },
-
-    objectFirstKey: function (obj) {
-      //// get first iterated key in object
-      var key;
-      for (key in obj) { if (obj.hasOwnProperty(key)) { return key; } }
-    },
-
-    shell: function (command) {
-      //// quick and dirty convenience function for running shell commands
-      require('child_process').spawn('/bin/sh', ['-c', command], {stdio: [0, 1, 2]});
-    },
-
-    streamReadBuffer: function (reader, callback) {
-      //// efficiently pipe readable stream to buffer
-      //// and run callback(error, buffer) on end
-      //// example usage:
-      //// function (request, response) {
-      ////   streadReadBuffer(request, function (error, buffer) {
-      ////     response.write(JSON.parse(buffer).interestingStuff);
-      ////     response.end();
-      ////   }));
-      //// }
-      var chunks = [], ended = false;
-      function onData(chunk) {
-        console.assert(Buffer.isBuffer(chunk));
-        chunks.push(chunk);
-      }
-      function onEnd(err) {
-        if (ended) { return; }
-        ended = true;
-        callback(err, !err && Buffer.concat(chunks));
-        reader.removeListener('close', onEnd);
-        reader.removeListener('data', onData);
-        reader.removeListener('end', onEnd);
-        reader.removeListener('error', onEnd);
-      }
-      reader.on('close', onEnd);
-      reader.on('data', onData);
-      reader.on('end', onEnd);
-      reader.on('error', onEnd);
-    },
-
-    stringFormat: function (template, options) {
-      function getValue(keys) {
-        //// get value from options using keys
-        var fndKey, rgxKey = (/["']([^"'])+|(\w+)/g), val = options;
-        while (true) {
-          fndKey = rgxKey.exec(keys);
-          if (!(fndKey && val)) { break; }
-          val = val[fndKey[0] || fndKey[1]];
-        }
-        return val;
-      }
-      return template.replace((/\{\{.+?\}\}/g), function (code) {
-        //// format {{...}}
-        var args, result;
-        args = code.split('(');
-        result = getValue(args.pop());
-        try {
-          return result === undefined ? code : args.length ? getValue(args.pop())(result) : result;
-        } catch (err) {
-          return code;
-        }
-      });
-    },
-
-    uuid4: function () {
-      //// return uuid4 string of form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
-      var uuid = '', ii;
-      for (ii = 0; ii < 32; ii += 1) {
-        switch (ii) {
-        case 8:
-        case 20:
-          uuid += '-';
-          uuid += (Math.random() * 16 | 0).toString(16);
-          break;
-        case 12:
-          uuid += '-';
-          uuid += '4';
-          break;
-        case 16:
-          uuid += '-';
-          uuid += (Math.random() * 4 | 8).toString(16);
-          break;
-        default:
-          uuid += (Math.random() * 16 | 0).toString(16);
-        }
-      }
-      return uuid;
-    }
-
-  };
-
-  local._init();
-
-}());
-
-
-
-/**
- * @module moduleRepl
- */
-
-(function () {
-
-  'use strict';
-
-  var EXPORTS = process.EXPORTS || {}, local = {
-
-    _init: function () {
-      //// EXPORTS
-      EXPORTS.exportLocal(local);
-      if (EXPORTS.REPL && EXPORTS.REPL.context) {
-        EXPORTS.REPL.context.EXPORTS = EXPORTS;
-        EXPORTS.REPL.eval = local._replEval;
-      }
-    },
-
-    _replEval: function (code, context, file, callback) {
-      try {
-        callback(null, EXPORTS.requireVm.runInThisContext(local._replParse(code), file));
-      } catch (err) {
-        callback(err);
-      }
-    },
-
-    _replParse: function (code) {
-      var aa, bb;
-      //// null -> "(null\n)"
-      if (!/^\(.*\n\)$/.test(code)) {
-        return code;
-      }
-      code = code.slice(1, -2);
-      while (/\w@@ /.test(code)) {
-        code = code.replace(/(\w)@@ ([\S\s]*)/, '$1($2)');
-      }
-      aa = code.split(' ');
-      bb = aa.slice(1).join(' ');
-      aa = aa[0];
-      switch (aa) {
-      //// execute /bin/sh commands in console
-      case '$':
-        EXPORTS.shell(bb);
-        return;
-      case 'error':
-        try {
-          EXPORTS.requireVm.runInThisContext(bb);
-        } catch (errEval) {
-          console.error(errEval.stack);
-        }
-        return;
-      case 'git':
-        EXPORTS.shell('git ' + (bb === 'log' ? 'log | head -n 18' : bb));
-        return;
-      case 'grep':
-        EXPORTS.shell(
-          'grep -in ' + JSON.stringify(bb) + ' $(find . -type f | grep -v "/\\.\\|\\b\\(\\.\\d\\|build\\|coverage\\|docs\\|min\\|node_modules\\|rollup\\|swp\\|test\\|tmp\\)\\b")'
-        );
-        return;
-      //// print function
-      case 'print':
-        code = 'console.log(String(' + bb + '))';
-        break;
-      }
-      return '(' + code + '\n)';
-    },
-
-    startRepl: function () {
-      //// start interactive interpreter / debugger
-      EXPORTS.REPL = EXPORTS.REPL || EXPORTS.requireRepl.start({
-        eval: local._replEval,
-        useGlobal: true
-      });
-      local._init();
-    }
-
-  };
-
-  local._init();
-
-}());
-
-
-
-/**
- * @module moduleHttp
- */
-
-(function () {
-
-  'use strict';
-
-  var EXPORTS = process.EXPORTS || {}, local = {
-
-    _init: function () {
-      //// EXPORTS
-      EXPORTS.exportLocal(local);
-      EXPORTS.HTTP_HANDLER = EXPORTS.HTTP_HANDLER || {};
-      EXPORTS.HTTP_HANDLER['/echo'] = EXPORTS.handlerEcho;
-      EXPORTS.HTTP_HANDLER['/http:'] = EXPORTS.handlerHttpProxy;
-      EXPORTS.HTTP_HANDLER['/https:'] = EXPORTS.handlerHttpProxy;
-      EXPORTS.HTTP_HANDLER['/public'] = EXPORTS.handlerStatic;
-      EXPORTS.HTTP_HISTORY = EXPORTS.HTTP_HISTORY || EXPORTS.arrayZeros(8);
-      EXPORTS.HTTP_SECURITY = EXPORTS.HTTP_SECURITY || {};
-      EXPORTS.HTTP_SECURITY['/echo'] = EXPORTS.HTTP_SECURITY['/echo'] || true;
-      EXPORTS.HTTP_SECURITY['/http:'] = EXPORTS.HTTP_SECURITY['/http:'] || true;
-      EXPORTS.HTTP_SECURITY['/https:'] = EXPORTS.HTTP_SECURITY['/https:'] || true;
-      EXPORTS.HTTP_SECURITY['/public'] = EXPORTS.HTTP_SECURITY['/public'] || true;
-      //// create http  server app
-      if (!EXPORTS.HTTP_APP) {
-        EXPORTS.HTTP_APP = EXPORTS.HTTP_APP || EXPORTS.requireExpress();
-        //// middleware - logging
-        EXPORTS.HTTP_APP.use(EXPORTS.requireExpress.logger('dev'));
-        //// middleware - security
-        EXPORTS.HTTP_APP.use(EXPORTS.middlewareSecurity);
-        //// middleware - dynamic path handler
-        EXPORTS.HTTP_APP.use(EXPORTS.middlewarePath);
-      }
-    },
-
-    handlerEcho: function (request, response) {
-      //// echo's back request along with post data if any
-      var headers, name;
-      response.writeHead(200, {'content-type': 'text/plain'});
-      response.write(request.method + ' ' + request.url + ' http/' + request.httpVersion + '\n');
-      headers = request.headers;
-      for (name in headers) {
-        if (headers.hasOwnProperty(name)) {
-          response.write(name + ': ' + JSON.stringify(headers[name]) + '\n');
-        }
-      }
-      response.write('\n');
-      //// OPTIMIZATION - stream data
-      request.pipe(response);
-    },
-
-    handlerHttpProxy: function (request, response, next) {
-      var key, options = {
-        url: /http.*/.exec(request.url)[0],
-        headers: {},
-        method: request.method,
-      };
-      //// modify proxy request headers
-      for (key in request.headers) {
-        if (request.headers.hasOwnProperty(key) && key !== 'host') {
-          options.headers[key] = request.headers[key];
-        }
-      }
-      //// error callback
-      options.callbackError = function (err) { next(err); };
-      //// response callback
-      options.callbackResponse = function (proxyResponse) {
-        response.writeHead(proxyResponse.statusCode, proxyResponse.headers);
-        //// OPTIMIZATION - stream data
-        proxyResponse.pipe(response);
-      };
-      //// OPTIMIZATION - stream data
-      request.pipe(EXPORTS.httpRequest(options));
-    },
-
-    handlerStatic: function (request, response, next) {
-      var readStream, path;
-      path = request.absolutePath;
-      //// OPTIMIZATION - client-side cache versioning
-      path = path.replace((/\/cacheVersion\/[^\/]+\//), '/cacheVersion/');
-      if (path !== request.absolutePath) {
-        response.setHeader('cache-control', 'public, max-age=2592000');
-      }
-      //// OPTIMIZATION - serve cached file from memory
-      if (EXPORTS.MODULE_FILE.hasOwnProperty(path)) {
-        response.setHeader('content-type', EXPORTS.requireMime.lookup(path));
-        response.end(EXPORTS.MODULE_FILE[path]);
-        return;
-      }
-      //// serve physical file
-      try {
-        readStream = EXPORTS.requireFs.createReadStream(EXPORTS.FS_CWD + path);
-        readStream.once('error', function (err) { next(err); });
-      } catch (errExists) {
-        next();
-        return;
-      }
-      readStream.once('open', function () {
-        response.setHeader('content-type', EXPORTS.requireMime.lookup(path));
-        //// OPTIMIZATION - stream file to response
-        readStream.pipe(response);
-      });
-    },
-
-    httpGet: function (options) {
-      //// quick and dirty http GET / POST client
-      //// example usage:
-      //// httpGet({data: require('fs').readFileSync('foo.png'), url: 'http://www.upload.com'});
-      var request;
-      if (options.data) {
-        options.method = options.method || 'POST';
-      }
-      request = EXPORTS.httpRequest(options);
-      request.end(options.data);
-    },
-
-    httpGetLocal: function (options) {
-      options.url = 'http://localhost:' + EXPORTS.HTTP_PORT + options.url;
-      options.headers = options.headers || {};
-      options.headers.authorization = options.headers.authorization || 'Basic ' + EXPORTS.ADMIN_BASIC_AUTH;
-      EXPORTS.httpGet(options);
-    },
-
-    httpGetTest: function (options) {
-      var callback = options.callback;
-      options.callback = function (err, data, response) {
-        if (err) {
-          throw err;
-        }
-        console.assert(response.statusCode < 500, response.statusCode);
-        (callback || EXPORTS.httpRequestCallback)(err, data, response);
-      };
-      EXPORTS.httpGetLocal(options);
-    },
-
-    httpRequest: function (options) {
-      var url = EXPORTS.requireUrl.parse(options.url), request;
-      //// OPTIMIZATION - disable socket pooling
-      options.agent = false;
-      options.callback = options.callback || EXPORTS.httpRequestCallback;
-      options.callbackResponse = options.callbackResponse || function (response) {
-        EXPORTS.streamReadBuffer(response, function (err, data) {
-          options.callback(err, data, response);
-        });
-      };
-      options.hostname = url.hostname;
-      options.path = url.path;
-      options.port = url.port;
-      //// DEBUG
-      if (EXPORTS.IS_DEBUG) { console.log(['httpRequest', options]); }
-      request = (options.protocol === 'https:' ? EXPORTS.requireHttps : EXPORTS.requireHttp).request(options, options.callbackResponse);
-      request.once('error', options.callback);
-      return request;
-    },
-
-    httpRequestCallback: function (err, data, response) {
-      //// default http client request callback - prints received data
-      if (err) {
-        console.error(err.stack);
-      } else {
-        console.log(response.statusCode);
-        console.log(data.toString());
-      }
-    },
-
-    middlewarePath: function (request, response, next) {
-      var path;
-      //// debug history of requests / responses
-      EXPORTS.request = request;
-      EXPORTS.response = response;
-      EXPORTS.HTTP_HISTORY.unshift({request: request, response: response, url: request.url});
-      EXPORTS.HTTP_HISTORY.pop();
-      //// dyanamic path handler
-      for (path = request.absolutePath; path.length > 1; path = path.replace(/\/+[^\/]*$/, '')) {
-        if (EXPORTS.HTTP_HANDLER.hasOwnProperty(path)) {
-          EXPORTS.HTTP_HANDLER[path](request, response, next);
-          return;
-        }
-      }
-      //// fallback to next middleware
-      next();
-    },
-
-    middlewareSecurity: function (request, response, next) {
-      var check, path;
-      //// SECURITY - resolve absolute url path
-      request.absolutePath = EXPORTS.requirePath.resolve(
-        '/' +
-          //// filter out query parameters
-          (/[^?&#]*/).exec(
-            //// SECURITY - limit path to 256 characters
-            request.url.slice(0, 256)
-          )[0]
-      ).replace(/\/+$/, '');
-      //// dyanamic path handler
-      for (path = request.absolutePath; path.length > 1; path = path.replace(/\/+[^\/]*$/, '')) {
-        if (EXPORTS.HTTP_SECURITY.hasOwnProperty(path)) {
-          check = EXPORTS.HTTP_SECURITY[path];
-          if (typeof check === 'function') {
-            check(request, response, next);
-            return;
-          }
-          if (check) {
-            next();
-            return;
-          }
-          break;
-        }
-      }
-      response.writeHead(404, {'content-type': 'text/plain'});
-      response.end('404 Not Found');
-    },
-
-    startServer: function (port) {
-      //// start http server on specified port
-      EXPORTS.HTTP_SERVER = EXPORTS.HTTP_SERVER || EXPORTS.requireHttp.createServer(EXPORTS.HTTP_APP).listen(EXPORTS.HTTP_PORT = EXPORTS.HTTP_PORT || 1337, function () {
-        console.log('express server listening on port ' + EXPORTS.HTTP_PORT);
-      });
-    }
-
-  };
-
-  local._init();
-
-}());
-
-
-
-/**
- * @module moduleExternal
- */
-
-(function () {
-
-  'use strict';
-
-  var EXPORTS = process.EXPORTS || {}, local = {
-
-    _init: function () {
-      //// EXPORTS
-      EXPORTS.exportLocal(local);
-      EXPORTS.EXTERNAL_URL = {
-        //// jquery
-        'aa.jquery.js': 'http://code.jquery.com/jquery-1.9.1.js',
-        //// bootstrap
-        'bootstrap.glyphicons-halflings-white.png': 'http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/img/glyphicons-halflings-white.png',
-        'bootstrap.glyphicons-halflings.png': 'http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/img/glyphicons-halflings.png',
-        'bootstrap.css': 'http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/css/bootstrap.css',
-        'bootstrap.js': 'http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/js/bootstrap.js',
-        'bootstrap.responsive.css': 'http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/css/bootstrap-responsive.css',
-        //// datatables
-        'datatables.back_disabled.png': 'http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/images/back_disabled.png',
-        'datatables.back_enabled.png': 'http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/images/back_enabled.png',
-        'datatables.back_enabled_hover.png': 'http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/images/back_enabled_hover.png',
-        'datatables.css': 'http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/css/jquery.dataTables.css',
-        'datatables.forward_disabled.png': 'http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/images/forward_disabled.png',
-        'datatables.forward_enabled.png': 'http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/images/forward_enabled.png',
-        'datatables.forward_enabled_hover.png': 'http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/images/forward_enabled_hover.png',
-        'datatables.js': 'http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/jquery.dataTables.js',
-        'datatables.sort_asc.png': 'http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/images/sort_asc.png',
-        'datatables.sort_asc_disabled.png': 'http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/images/sort_asc_disabled.png',
-        'datatables.sort_both.png': 'http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/images/sort_both.png',
-        'datatables.sort_desc.png': 'http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/images/sort_desc.png',
-        'datatables.sort_desc_disabled.png': 'http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/images/sort_desc_disabled.png',
-        //// datatables extra
-        'datatables.copy_csv_xls.swf': 'http://datatables.net/release-datatables/extras/TableTools/media/swf/copy_csv_xls.swf',
-        'datatables.copy_csv_xls_pdf.swf': 'http://datatables.net/release-datatables/extras/TableTools/media/swf/copy_csv_xls_pdf.swf',
-        'datatables.tabletools.js': 'http://datatables.net/release-datatables/extras/TableTools/media/js/TableTools.js',
-        //// select
-        'select2.css': 'https://raw.github.com/ivaynberg/select2/3.3.1/select2.css',
-        'select2.js': 'https://raw.github.com/ivaynberg/select2/3.3.1/select2.js',
-        'select2.png': 'https://raw.github.com/ivaynberg/select2/3.3.1/select2.png',
-        'select2x2.png': 'https://raw.github.com/ivaynberg/select2/3.3.1/select2x2.png',
-        //// image ajax loader
-        //// 'ajaxLoader.gif': 'http://www.ajaxload.info/download.php?img=cache/FF/FF/FF/00/00/00/26-1.gif',
-      };
-      EXPORTS.FS_EXTERNAL = EXPORTS.FS_EXTERNAL || EXPORTS.FS_MODULE + '/node_modules/tinyjs-external';
-      //// load public external assets
-      [
-        'externalRollup.css',
-        'externalRollup.js',
-      ].forEach(function (filename) {
-        if (EXPORTS.requireFs.existsSync(EXPORTS.FS_EXTERNAL + '/' + filename)) {
-          EXPORTS.MODULE_FILE['/public/cacheVersion/' + filename] = EXPORTS.requireFs.readFileSync(EXPORTS.FS_EXTERNAL + '/' + filename);
-        }
-      });
-      //// auto rollup
-      if (EXPORTS.EXTERNAL_ROLLUP) {
-        EXPORTS.externalRollup();
-      }
-    },
-
-    externalDataUri: function (filename) {
-      return '\n"data:' + EXPORTS.requireMime.lookup(filename) + ';base64,' + EXPORTS.requireFs.readFileSync(filename, 'base64') + '"\n';
-    },
-
-    externalGet: function (arr) {
-      var filename, ii = 0, obj = {};
-      function closure(filename) {
-        ii += 1;
-        EXPORTS.httpGet({
-          callback: function (err, data, response) {
-            var arr;
-            ii -= 1;
-            try {
-              if (err) { throw err; }
-              console.assert(response.statusCode === 200, response.statusCode);
-              EXPORTS.requireFs.writeFileSync(EXPORTS.FS_EXTERNAL + '/' + filename, data);
-              delete obj[filename];
-            } catch (errCallback) {
-              console.log(errCallback.stack);
-              console.log(response.headers);
-            }
-            console.log(filename, 'EXPORTS.externalGet(' + JSON.stringify(Object.keys(obj).sort()) + ')\n');
-            //// finished attempting to download all files
-            if (ii === 0) { console.log(obj); }
-          },
-          url: obj[filename]
-        });
-      }
-      //// debug - test culled EXPORTS.EXTERNAL_URL
-      (arr || Object.keys(EXPORTS.EXTERNAL_URL)).forEach(function (filename) {
-        obj[filename] = EXPORTS.EXTERNAL_URL[filename];
-      });
-      for (filename in obj) {
-        if (obj.hasOwnProperty(filename)) { closure(filename); }
-      }
-    },
-
-    externalRollup: function () {
-      var css = '', js = '';
-      Object.keys(EXPORTS.EXTERNAL_URL).sort().forEach(function (filename) {
-        switch (EXPORTS.requirePath.extname(filename)) {
-        case '.css':
-          css += EXPORTS._externalRollupFile(filename);
-          break;
-        case '.js':
-          js += EXPORTS._externalRollupFile(filename);
-          break;
-        }
-      });
-      [
-        'imgAjaxLoader.gif'
-      ].forEach(function (filename) {
-        css += '.' + (/\w+/).exec(filename) + ' { background: url(' + EXPORTS.externalDataUri(EXPORTS.FS_EXTERNAL + '/' + filename) + ') no-repeat center center;';
-      });
-      EXPORTS.requireFs.writeFileSync(EXPORTS.FS_EXTERNAL + '/externalRollup.css', css);
-      EXPORTS.requireFs.writeFileSync(EXPORTS.FS_EXTERNAL + '/externalRollup.js', js);
-    },
-
-    _externalRollupFile: function (filename) {
-      var data = EXPORTS.requireFs.readFileSync(EXPORTS.FS_EXTERNAL + '/' + filename, 'utf8') + '\n';
-      switch (filename) {
-      case 'bootstrap.css':
-        data = data.replace(/"\.\.\/img\/(.+)"/g, function (_, filename) {
-          return EXPORTS.externalDataUri(EXPORTS.FS_EXTERNAL + '/bootstrap.' + filename);
-        });
-        break;
-      case 'datatables.css':
-        data = data.replace(/'\.\.\/images\/(.+)'/g, function (_, filename) {
-          return EXPORTS.externalDataUri(EXPORTS.FS_EXTERNAL + '/datatables.' + filename);
-        });
-        break;
-      case 'select2.css':
-        data = data.replace(/'(\w+\.png)'/g, function (_, filename) {
-          return EXPORTS.externalDataUri(EXPORTS.FS_EXTERNAL + '/' + filename);
-        });
-        break;
-      }
-      return (data += '\n');
-    }
-
-  };
-
-  local._init();
-
-}());
-
-
-
-/**
- * @module moduleAdmin
- */
-
-(function () {
-
-  'use strict';
-
-  var EXPORTS = process.EXPORTS || {}, local = {
-
-    _init: function () {
-      //// EXPORTS
-      EXPORTS.exportLocal(local);
-      EXPORTS.ADMIN_BASIC_AUTH = EXPORTS.ADMIN_BASIC_AUTH || new Buffer(Math.random().toString(16).slice(2) + ':' + Math.random().toString(16).slice(2)).toString('base64');
-      EXPORTS.HTTP_HANDLER['/admin'] = EXPORTS.handlerStatic;
-      EXPORTS.HTTP_SECURITY['/admin'] = EXPORTS.handlerAdminBasicAuth;
-    },
-
-    handlerAdminEval: function (request, response, next) {
-      EXPORTS.streamReadBuffer(request, function (err, data) {
-        if (err) {
-          next(err);
-          return;
-        }
-        try {
-          console.log(JSON.stringify(data.toString()));
-          data = EXPORTS.requireVm.runInThisContext(data);
-        } catch (errEval) {
-          next(errEval);
-        }
-        response.end(EXPORTS.jsonStringifyCircular(data));
-      });
-    },
-
-    adminBasicAuthGet: function () {
-      return new Buffer(EXPORTS.ADMIN_BASIC_AUTH, 'base64').toString();
-    },
-
-    adminBasicAuthSet: function (userPass) {
-      EXPORTS.ADMIN_BASIC_AUTH = new Buffer(userPass).toString('base64');
-    },
-
-    handlerAdminBasicAuth: function (request, response, next) {
-      if (/\S*$/.exec(request.headers.authorization || '')[0] === EXPORTS.ADMIN_BASIC_AUTH) {
-        next();
-        return;
-      }
-      response.writeHead(401, {'www-authenticate': 'basic realm="Authorization Required"'});
-      response.end('401 Unauthorized');
-    }
-
-  };
-
-  local._init();
-
-}());
-
-
-
-/**
- * filesystem-based, key-value database in pure nodejs
- * @module moduleDb
- */
-
-(function () {
-
-  'use strict';
-
-  var EXPORTS = process.EXPORTS || {}, local = {
-
-    _init: function () {
-      if (!EXPORTS.HTTP_PORT) { return; }
-      //// EXPORTS
-      EXPORTS.exportLocal(local);
-      EXPORTS.FS_CWD = EXPORTS.FS_CWD || process.cwd();
-      EXPORTS.FS_TMP = EXPORTS.FS_TMP || '/tmp/' + EXPORTS.FS_CWD.replace(/\W/g, '_') + '_' + EXPORTS.HTTP_PORT;
-      EXPORTS.FS_CACHE = EXPORTS.FS_CACHE || EXPORTS.FS_TMP + '/cache';
-      EXPORTS.FS_DB = EXPORTS.FS_DB || EXPORTS.FS_TMP + '/db';
-      EXPORTS.HTTP_HANDLER['/admin/db'] = EXPORTS.handlerDb;
-      //// create directories
-      EXPORTS.requireFsExtra.mkdirpSync(EXPORTS.FS_CACHE);
-      EXPORTS.requireFsExtra.mkdirpSync(EXPORTS.FS_DB);
-      //// remove stale tmp files
-      EXPORTS.requireFs.readdir(EXPORTS.FS_CACHE, function (err, data) {
-        (data || []).forEach(function (key) {
-          //// physically remove files after 60000 ms
-          setTimeout(function () {
-            EXPORTS.requireFsExtra.remove(EXPORTS.FS_CACHE + '/' + key);
-          }, 60000);
-        });
-      });
-    },
-
-    dbAssertKey: function (key) {
-      console.assert(/^\w[\w\-\.]*$/.test(key), [key]);
-      return key;
-    },
-
-    dbAssertPath: function (path) {
-      console.assert(/^(?:\/\w[\w\-\.]*)+$/.test(path), [path]);
-      return path;
-    },
-
-    fsTempFilename: function (filename) {
-      return EXPORTS.FS_CACHE + '/' + (filename || '').replace(/\W/g, '_') + '.' + new Date().getTime().toString(16) + Math.random().toString(16).slice(1);
-    },
-
-    fsWriteFileAtomic: function (filename, data, callback) {
-      //// atomicly write file by first writing to temporary file, and then renaming to filename
-      var tmp = EXPORTS.fsTempFilename(filename);
-      EXPORTS.requireFs.writeFile(tmp, data, function (err) {
-        if (err) {
-          callback(err);
-          return;
-        }
-        EXPORTS.requireFs.rename(tmp, filename, callback);
-      });
-    },
-
-    handlerDb: function (request, response, next) {
-      EXPORTS.streamReadBuffer(request, function (err, data) {
-        var action, fnd, path;
-        function callback(err, data) {
-          if (err) {
-            next(err);
-            return;
-          }
-          response.end(Array.isArray(data) ? JSON.stringify(data) : data);
-        }
-        try {
-          fnd = /\/db\/([\w]+)(.*)/.exec(EXPORTS.dbAssertPath(request.absolutePath));
-          //// SECURITY - fs
-          if (!fnd || fnd[2].length >= 256) {
-            next();
-            return;
-          }
-          action = fnd[1] + fnd[2].split('/').length + ((data.length && 'Data') || '');
-          path = EXPORTS.FS_DB + fnd[2];
-          switch (action) {
-          //// get record
-          case 'get3':
-            EXPORTS.requireFs.readFile(path, callback);
-            return;
-          //// list tables
-          case 'list1':
-          //// list table
-          case 'list2':
-            EXPORTS.requireFs.readdir(path, callback);
-            return;
-          //// remove table
-          case 'remove2':
-            EXPORTS.requireFs.rmdir(path, callback);
-            return;
-          //// remove record
-          case 'remove3':
-            EXPORTS.requireFs.unlink(path, callback);
-            return;
-          //// rename table
-          case 'rename2Data':
-          //// rename record
-          case 'rename3Data':
-            EXPORTS.requireFs.rename(path, path.replace(/[^\/]+$/, '') + EXPORTS.dbAssertKey(data.toString()), callback);
-            return;
-          //// create table
-          case 'set2':
-            EXPORTS.requireFs.mkdir(path, callback);
-            return;
-          //// set record
-          case 'set3Data':
-            EXPORTS.fsWriteFileAtomic(path, data, callback);
-            return;
-          }
-          next();
-        } catch (errHandler) {
-          next(errHandler);
-        }
-      });
-    }
-
-  };
-
-  local._init();
-
-}());
-
-
-
-/**
- * @module moduleTest
- */
-
-(function () {
-
-  'use strict';
-
-  var EXPORTS = process.EXPORTS || {}, local = {
-
-    _init: function () {
-      //// EXPORTS
-      EXPORTS.exportLocal(local);
-      //// http tests
-      if (!EXPORTS.HTTP_SERVER) { return; }
-      EXPORTS.TEST_HTTP.proxy = function () {
-        EXPORTS.httpGetTest({
-          callback: function (err, data) {
-            data = data && data.toString();
-            console.assert(/^POST \/echo\/foo http\/1\.1\n[\S\s]+\nbar\n$/.test(data), [data]);
-          },
-          data: 'bar\n',
-          url: '/http://localhost:' + EXPORTS.HTTP_PORT + '/echo/foo',
-        });
-      };
-      EXPORTS.startTest();
-    },
-
-    startTest: function () {
-      EXPORTS.coverClear();
-      //// run tests
-      Object.keys(EXPORTS.TEST).sort().forEach(function (key) { EXPORTS.TEST[key](); });
-      if (EXPORTS.HTTP_SERVER) {
-        Object.keys(EXPORTS.TEST_HTTP).sort().forEach(function (key) {
-          EXPORTS.TEST_HTTP[key]();
-        });
-      }
-    }
-
-  };
-
-  local._init();
-
-}());
-
-
-
-/**
- * @module moduleMain
- */
-
-(function () {
-
-  'use strict';
-
-  var EXPORTS = process.EXPORTS || {}, local = {
-
-    _init: function () {
-      //// EXPORTS
-      EXPORTS.exportLocal(local);
-      //// initialize tinyjs libraries
-      require.extensions['.js2'] = EXPORTS.moduleLoad;
-      require('tinyjs-external');
-      require('./moduleMisc.js2');
-      require('./moduleUnused.js2');
-      //// start application
-      if (EXPORTS.startApp) { EXPORTS.startApp(); }
-      //// main command-line code
-      if (!EXPORTS.IS_CLI) { return; }
-      Object.keys(EXPORTS.ARGV).forEach(function (key) {
-        var val = EXPORTS.ARGV[key];
-        if (!val) { return; }
-        switch (key) {
-        case 'rollup':
-          EXPORTS.externalRollup();
-          EXPORTS.EXIT = true;
-          break;
-        }
-      });
-      if (EXPORTS.EXIT) { process.exit(); }
-      //// start interactive debugger
-      EXPORTS.startRepl();
-      //// start http server if port exists
-      EXPORTS.startServer();
-    }
-
-  };
-
-  local._init();
-
-}());
-/*FILE_END*/

File moduleMain.js2

+#!/usr/bin/env node
+
+/*
+CHANGELOG
+fix lineno.  use module.filename instead of module.id.
+
+TODO
+add client-side interactive tests.
+rewrite db.
+*/
+
+
+
+/**
+ * @class EXPORTS
+ */
+
+/*FILE_BEG {"actions": ["jslint", "cover", "eval"], "name": "/FS_MODULE/moduleMain.js"}*/
+/*jslint bitwise: true, evil: true, indent: 2, nomen: true, regexp: true, stupid: true*/
+
+/**
+ * @module moduleGist
+ */
+
+(function () {
+
+  'use strict';
+
+  var EXPORTS = process.EXPORTS || {}, local = {
+
+    _init: function () {
+      //// EXPORTS
+      EXPORTS.exportLocal(local);
+    },
+
+    arrayZeros: function (length) {
+      var arr = [], ii = length;
+      while (ii > 0) {
+        arr.push(0);
+        ii -= 1;
+      }
+      return arr;
+    },
+
+    hashSha256: function (str) {
+      var hash = require('crypto').createHash('sha256');
+      hash.update(typeof str === 'string' || Buffer.isBuffer(str) ? str : String(str));
+      return hash.digest('hex');
+    },
+
+    /**
+     * JSON.stringify circular object
+     * @method jsonStringifyCircular
+     * @param {Object} obj
+     * @return {String}
+     * @static
+     */
+    jsonStringifyCircular: function (obj) {
+      return local._jsonStringifyCircularRecurse(obj, []);
+    },
+
+    _jsonStringifyCircularRecurse: function (obj, arr) {
+      var ii, keys, result, val;
+      if (obj) {
+        for (ii = 0; ii < arr.length; ii += 1) {
+          if (obj === arr[ii]) {
+            obj = '[Circular]';
+            break;
+          }
+        }
+      }
+      try {
+        return JSON.stringify(obj);
+      } catch (err) {
+      }
+      //// fallback
+      arr.push(obj);
+      result = '';
+      //// array
+      if (Array.isArray(obj)) {
+        for (ii = 0; ii < obj.length; ii += 1) {
+          val = local._jsonStringifyCircularRecurse(obj[ii], arr);
+          if (val !== undefined) {
+            result += val + ',';
+          }
+        }
+        return '[' + result.slice(0, -1) + ']';
+      }
+      //// object
+      keys = Object.keys(obj).sort();
+      for (ii = 0; ii < keys.length; ii += 1) {
+        val = local._jsonStringifyCircularRecurse(obj[keys[ii]], arr);
+        if (val !== undefined) {
+          result += JSON.stringify(keys[ii]) + ':' + val + ',';
+        }
+      }
+      return '{' + result.slice(0, -1) + '}';
+    },
+
+    jsonStringifySorted: function (obj) {
+      //// recursively JSON.stringify dictionaries in sorted-key order
+      var ii, keys, result, val;
+      result = '';
+      //// array
+      if (Array.isArray(obj)) {
+        for (ii = 0; ii < obj.length; ii += 1) {
+          val = local.jsonStringifySorted(obj[ii]);
+          if (val !== undefined) {
+            result += val + ',';
+          }
+        }
+        return '[' + result.slice(0, -1) + ']';
+      }
+      //// object
+      if (typeof obj === 'object' && obj !== null) {
+        keys = Object.keys(obj).sort();
+        for (ii = 0; ii < keys.length; ii += 1) {
+          val = local.jsonStringifySorted(obj[keys[ii]]);
+          if (val !== undefined) {
+            result += JSON.stringify(keys[ii]) + ':' + val + ',';
+          }
+        }
+        return '{' + result.slice(0, -1) + '}';
+      }
+      return JSON.stringify(obj);
+    },
+
+    objectFirstKey: function (obj) {
+      //// get first iterated key in object
+      var key;
+      for (key in obj) { if (obj.hasOwnProperty(key)) { return key; } }
+    },
+
+    shell: function (command) {
+      //// quick and dirty convenience function for running shell commands
+      require('child_process').spawn('/bin/sh', ['-c', command], {stdio: [0, 1, 2]});
+    },
+
+    streamReadBuffer: function (reader, callback) {
+      //// efficiently pipe readable stream to buffer
+      //// and run callback(error, buffer) on end
+      //// example usage:
+      //// function (request, response) {
+      ////   streadReadBuffer(request, function (error, buffer) {
+      ////     response.write(JSON.parse(buffer).interestingStuff);
+      ////     response.end();
+      ////   }));
+      //// }
+      var chunks = [], ended = false;
+      function onData(chunk) {
+        console.assert(Buffer.isBuffer(chunk));
+        chunks.push(chunk);
+      }
+      function onEnd(err) {
+        if (ended) { return; }
+        ended = true;
+        callback(err, !err && Buffer.concat(chunks));
+        reader.removeListener('close', onEnd);
+        reader.removeListener('data', onData);
+        reader.removeListener('end', onEnd);
+        reader.removeListener('error', onEnd);
+      }
+      reader.on('close', onEnd);
+      reader.on('data', onData);
+      reader.on('end', onEnd);
+      reader.on('error', onEnd);
+    },
+
+    stringFormat: function (template, options) {
+      function getValue(keys) {
+        //// get value from options using keys
+        var fndKey, rgxKey = (/["']([^"'])+|(\w+)/g), val = options;
+        while (true) {
+          fndKey = rgxKey.exec(keys);
+          if (!(fndKey && val)) { break; }
+          val = val[fndKey[0] || fndKey[1]];
+        }
+        return val;
+      }
+      return template.replace((/\{\{.+?\}\}/g), function (code) {
+        //// format {{...}}
+        var args, result;
+        args = code.split('(');
+        result = getValue(args.pop());
+        try {
+          return result === undefined ? code : args.length ? getValue(args.pop())(result) : result;
+        } catch (err) {
+          return code;
+        }
+      });
+    },
+
+    uuid4: function () {
+      //// return uuid4 string of form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
+      var uuid = '', ii;
+      for (ii = 0; ii < 32; ii += 1) {
+        switch (ii) {
+        case 8:
+        case 20:
+          uuid += '-';
+          uuid += (Math.random() * 16 | 0).toString(16);
+          break;
+        case 12:
+          uuid += '-';
+          uuid += '4';
+          break;
+        case 16:
+          uuid += '-';
+          uuid += (Math.random() * 4 | 8).toString(16);
+          break;
+        default:
+          uuid += (Math.random() * 16 | 0).toString(16);
+        }
+      }
+      return uuid;
+    }
+
+  };
+
+  local._init();
+
+}());
+
+
+
+/**
+ * @module moduleRepl
+ */
+
+(function () {
+
+  'use strict';
+
+  var EXPORTS = process.EXPORTS || {}, local = {
+
+    _init: function () {
+      //// EXPORTS
+      EXPORTS.exportLocal(local);
+      if (EXPORTS.REPL && EXPORTS.REPL.context) {
+        EXPORTS.REPL.context.EXPORTS = EXPORTS;
+        EXPORTS.REPL.eval = local._replEval;
+      }
+    },
+
+    _replEval: function (code, context, file, callback) {
+      try {
+        callback(null, EXPORTS.requireVm.runInThisContext(local._replParse(code), file));
+      } catch (err) {
+        callback(err);
+      }
+    },
+
+    _replParse: function (code) {
+      var aa, bb;
+      //// null -> "(null\n)"
+      if (!/^\(.*\n\)$/.test(code)) {
+        return code;
+      }
+      code = code.slice(1, -2);
+      while (/\w@@ /.test(code)) {
+        code = code.replace(/(\w)@@ ([\S\s]*)/, '$1($2)');
+      }
+      aa = code.split(' ');
+      bb = aa.slice(1).join(' ');
+      aa = aa[0];
+      switch (aa) {
+      //// execute /bin/sh commands in console
+      case '$':
+        EXPORTS.shell(bb);
+        return;
+      case 'error':
+        try {
+          EXPORTS.requireVm.runInThisContext(bb);
+        } catch (errEval) {
+          console.error(errEval.stack);
+        }
+        return;
+      case 'git':
+        EXPORTS.shell('git ' + (bb === 'log' ? 'log | head -n 18' : bb));
+        return;
+      case 'grep':
+        EXPORTS.shell(
+          'grep -in ' + JSON.stringify(bb) + ' $(find . -type f | grep -v "/\\.\\|\\b\\(\\.\\d\\|build\\|coverage\\|docs\\|min\\|node_modules\\|rollup\\|swp\\|test\\|tmp\\)\\b")'
+        );
+        return;
+      //// print function
+      case 'print':
+        code = 'console.log(String(' + bb + '))';
+        break;
+      }
+      return '(' + code + '\n)';
+    },
+
+    startRepl: function () {
+      //// start interactive interpreter / debugger
+      EXPORTS.REPL = EXPORTS.REPL || EXPORTS.requireRepl.start({
+        eval: local._replEval,
+        useGlobal: true
+      });
+      local._init();
+    }
+
+  };
+
+  local._init();
+
+}());
+
+
+
+/**
+ * @module moduleHttp
+ */
+
+(function () {
+
+  'use strict';
+
+  var EXPORTS = process.EXPORTS || {}, local = {
+
+    _init: function () {
+      //// EXPORTS
+      EXPORTS.exportLocal(local);
+      EXPORTS.HTTP_HANDLER = EXPORTS.HTTP_HANDLER || {};
+      EXPORTS.HTTP_HANDLER['/echo'] = EXPORTS.handlerEcho;
+      EXPORTS.HTTP_HANDLER['/http:'] = EXPORTS.handlerHttpProxy;
+      EXPORTS.HTTP_HANDLER['/https:'] = EXPORTS.handlerHttpProxy;
+      EXPORTS.HTTP_HANDLER['/public'] = EXPORTS.handlerStatic;
+      EXPORTS.HTTP_HISTORY = EXPORTS.HTTP_HISTORY || EXPORTS.arrayZeros(8);
+      EXPORTS.HTTP_SECURITY = EXPORTS.HTTP_SECURITY || {};
+      EXPORTS.HTTP_SECURITY['/echo'] = EXPORTS.HTTP_SECURITY['/echo'] || true;
+      EXPORTS.HTTP_SECURITY['/http:'] = EXPORTS.HTTP_SECURITY['/http:'] || true;
+      EXPORTS.HTTP_SECURITY['/https:'] = EXPORTS.HTTP_SECURITY['/https:'] || true;
+      EXPORTS.HTTP_SECURITY['/public'] = EXPORTS.HTTP_SECURITY['/public'] || true;
+      //// create http  server app
+      if (!EXPORTS.HTTP_APP) {
+        EXPORTS.HTTP_APP = EXPORTS.HTTP_APP || EXPORTS.requireExpress();
+        //// middleware - logging
+        EXPORTS.HTTP_APP.use(EXPORTS.requireExpress.logger('dev'));
+        //// middleware - security
+        EXPORTS.HTTP_APP.use(EXPORTS.middlewareSecurity);
+        //// middleware - dynamic path handler
+        EXPORTS.HTTP_APP.use(EXPORTS.middlewarePath);
+      }
+    },
+
+    handlerEcho: function (request, response) {
+      //// echo's back request along with post data if any
+      var headers, name;
+      response.writeHead(200, {'content-type': 'text/plain'});
+      response.write(request.method + ' ' + request.url + ' http/' + request.httpVersion + '\n');
+      headers = request.headers;
+      for (name in headers) {
+        if (headers.hasOwnProperty(name)) {
+          response.write(name + ': ' + JSON.stringify(headers[name]) + '\n');
+        }
+      }
+      response.write('\n');
+      //// OPTIMIZATION - stream data
+      request.pipe(response);
+    },
+
+    handlerHttpProxy: function (request, response, next) {
+      var key, options = {
+        url: /http.*/.exec(request.url)[0],
+        headers: {},
+        method: request.method,
+      };
+      //// modify proxy request headers
+      for (key in request.headers) {
+        if (request.headers.hasOwnProperty(key) && key !== 'host') {
+          options.headers[key] = request.headers[key];
+        }
+      }
+      //// error callback
+      options.callbackError = function (err) { next(err); };
+      //// response callback
+      options.callbackResponse = function (proxyResponse) {
+        response.writeHead(proxyResponse.statusCode, proxyResponse.headers);
+        //// OPTIMIZATION - stream data
+        proxyResponse.pipe(response);
+      };
+      //// OPTIMIZATION - stream data
+      request.pipe(EXPORTS.httpRequest(options));
+    },
+
+    handlerStatic: function (request, response, next) {
+      var readStream, path;
+      path = request.absolutePath;
+      //// OPTIMIZATION - client-side cache versioning
+      path = path.replace((/\/cacheVersion\/[^\/]+\//), '/cacheVersion/');
+      if (path !== request.absolutePath) {
+        response.setHeader('cache-control', 'public, max-age=2592000');
+      }
+      //// OPTIMIZATION - serve cached file from memory
+      if (EXPORTS.MODULE_FILE.hasOwnProperty(path)) {
+        response.setHeader('content-type', EXPORTS.requireMime.lookup(path));
+        response.end(EXPORTS.MODULE_FILE[path]);
+        return;
+      }
+      //// serve physical file
+      try {
+        readStream = EXPORTS.requireFs.createReadStream(EXPORTS.FS_CWD + path);
+        readStream.once('error', function (err) { next(err); });
+      } catch (errExists) {
+        next();
+        return;
+      }
+      readStream.once('open', function () {
+        response.setHeader('content-type', EXPORTS.requireMime.lookup(path));
+        //// OPTIMIZATION - stream file to response
+        readStream.pipe(response);
+      });
+    },
+
+    httpGet: function (options) {
+      //// quick and dirty http GET / POST client
+      //// example usage:
+      //// httpGet({data: require('fs').readFileSync('foo.png'), url: 'http://www.upload.com'});
+      var request;
+      if (options.data) {
+        options.method = options.method || 'POST';
+      }
+      request = EXPORTS.httpRequest(options);
+      request.end(options.data);
+    },
+
+    httpGetLocal: function (options) {
+      options.url = 'http://localhost:' + EXPORTS.HTTP_PORT + options.url;
+      options.headers = options.headers || {};
+      options.headers.authorization = options.headers.authorization || 'Basic ' + EXPORTS.ADMIN_BASIC_AUTH;
+      EXPORTS.httpGet(options);
+    },
+
+    httpGetTest: function (options) {
+      var callback = options.callback;
+      options.callback = function (err, data, response) {
+        if (err) {
+          throw err;
+        }
+        console.assert(response.statusCode < 500, response.statusCode);
+        (callback || EXPORTS.httpRequestCallback)(err, data, response);
+      };
+      EXPORTS.httpGetLocal(options);
+    },
+
+    httpRequest: function (options) {
+      var url = EXPORTS.requireUrl.parse(options.url), request;
+      //// OPTIMIZATION - disable socket pooling
+      options.agent = false;
+      options.callback = options.callback || EXPORTS.httpRequestCallback;
+      options.callbackResponse = options.callbackResponse || function (response) {
+        EXPORTS.streamReadBuffer(response, function (err, data) {
+          options.callback(err, data, response);
+        });
+      };
+      options.hostname = url.hostname;
+      options.path = url.path;
+      options.port = url.port;
+      //// DEBUG
+      if (EXPORTS.IS_DEBUG) { console.log(['httpRequest', options]); }
+      request = (options.protocol === 'https:' ? EXPORTS.requireHttps : EXPORTS.requireHttp).request(options, options.callbackResponse);
+      request.once('error', options.callback);
+      return request;
+    },
+
+    httpRequestCallback: function (err, data, response) {
+      //// default http client request callback - prints received data
+      if (err) {
+        console.error(err.stack);
+      } else {
+        console.log(response.statusCode);
+        console.log(data.toString());
+      }
+    },
+
+    middlewarePath: function (request, response, next) {
+      var path;
+      //// debug history of requests / responses
+      EXPORTS.request = request;
+      EXPORTS.response = response;
+      EXPORTS.HTTP_HISTORY.unshift({request: request, response: response, url: request.url});
+      EXPORTS.HTTP_HISTORY.pop();
+      //// dyanamic path handler
+      for (path = request.absolutePath; path.length > 1; path = path.replace(/\/+[^\/]*$/, '')) {
+        if (EXPORTS.HTTP_HANDLER.hasOwnProperty(path)) {
+          EXPORTS.HTTP_HANDLER[path](request, response, next);
+          return;
+        }
+      }
+      //// fallback to next middleware
+      next();
+    },
+
+    middlewareSecurity: function (request, response, next) {
+      var check, path;
+      //// SECURITY - resolve absolute url path
+      request.absolutePath = EXPORTS.requirePath.resolve(
+        '/' +
+          //// filter out query parameters
+          (/[^?&#]*/).exec(
+            //// SECURITY - limit path to 256 characters
+            request.url.slice(0, 256)
+          )[0]
+      ).replace(/\/+$/, '');
+      //// dyanamic path handler
+      for (path = request.absolutePath; path.length > 1; path = path.replace(/\/+[^\/]*$/, '')) {
+        if (EXPORTS.HTTP_SECURITY.hasOwnProperty(path)) {
+          check = EXPORTS.HTTP_SECURITY[path];
+          if (typeof check === 'function') {
+            check(request, response, next);
+            return;
+          }
+          if (check) {
+            next();
+            return;
+          }
+          break;
+        }
+      }
+      response.writeHead(404, {'content-type': 'text/plain'});
+      response.end('404 Not Found');
+    },
+
+    startServer: function (port) {
+      //// start http server on specified port
+      EXPORTS.HTTP_SERVER = EXPORTS.HTTP_SERVER || EXPORTS.requireHttp.createServer(EXPORTS.HTTP_APP).listen(EXPORTS.HTTP_PORT = EXPORTS.HTTP_PORT || 1337, function () {
+        console.log('express server listening on port ' + EXPORTS.HTTP_PORT);
+      });
+    }
+
+  };
+
+  local._init();
+
+}());
+
+
+
+/**
+ * @module moduleExternal
+ */
+
+(function () {
+
+  'use strict';
+
+  var EXPORTS = process.EXPORTS || {}, local = {
+
+    _init: function () {
+      //// EXPORTS
+      EXPORTS.exportLocal(local);
+      EXPORTS.requireTinyjsExternal = EXPORTS.requireTinyjsExternal || require('tinyjs-external');
+      EXPORTS.EXTERNAL_URL = {
+        //// jquery
+        'aa.jquery.js': 'http://code.jquery.com/jquery-1.9.1.js',
+        //// bootstrap
+        'bootstrap.glyphicons-halflings-white.png': 'http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/img/glyphicons-halflings-white.png',
+        'bootstrap.glyphicons-halflings.png': 'http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/img/glyphicons-halflings.png',
+        'bootstrap.css': 'http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/css/bootstrap.css',
+        'bootstrap.js': 'http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/js/bootstrap.js',
+        'bootstrap.responsive.css': 'http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/css/bootstrap-responsive.css',
+        //// datatables
+        'datatables.back_disabled.png': 'http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/images/back_disabled.png',
+        'datatables.back_enabled.png': 'http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/images/back_enabled.png',
+        'datatables.back_enabled_hover.png': 'http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/images/back_enabled_hover.png',
+        'datatables.css': 'http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/css/jquery.dataTables.css',
+        'datatables.forward_disabled.png': 'http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/images/forward_disabled.png',
+        'datatables.forward_enabled.png': 'http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/images/forward_enabled.png',
+        'datatables.forward_enabled_hover.png': 'http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/images/forward_enabled_hover.png',
+        'datatables.js': 'http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/jquery.dataTables.js',
+        'datatables.sort_asc.png': 'http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/images/sort_asc.png',
+        'datatables.sort_asc_disabled.png': 'http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/images/sort_asc_disabled.png',
+        'datatables.sort_both.png': 'http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/images/sort_both.png',
+        'datatables.sort_desc.png': 'http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/images/sort_desc.png',
+        'datatables.sort_desc_disabled.png': 'http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/images/sort_desc_disabled.png',
+        //// datatables extra
+        'datatables.copy_csv_xls.swf': 'http://datatables.net/release-datatables/extras/TableTools/media/swf/copy_csv_xls.swf',
+        'datatables.copy_csv_xls_pdf.swf': 'http://datatables.net/release-datatables/extras/TableTools/media/swf/copy_csv_xls_pdf.swf',
+        'datatables.tabletools.js': 'http://datatables.net/release-datatables/extras/TableTools/media/js/TableTools.js',
+        //// select
+        'select2.css': 'https://raw.github.com/ivaynberg/select2/3.3.1/select2.css',
+        'select2.js': 'https://raw.github.com/ivaynberg/select2/3.3.1/select2.js',
+        'select2.png': 'https://raw.github.com/ivaynberg/select2/3.3.1/select2.png',
+        'select2x2.png': 'https://raw.github.com/ivaynberg/select2/3.3.1/select2x2.png',
+        //// image ajax loader
+        //// 'ajaxLoader.gif': 'http://www.ajaxload.info/download.php?img=cache/FF/FF/FF/00/00/00/26-1.gif',
+      };
+      EXPORTS.FS_EXTERNAL = EXPORTS.FS_EXTERNAL || EXPORTS.requirePath.dirname(EXPORTS.MODULE_EXTERNAL.filename);
+      //// load public external assets
+      [
+        'externalRollup.css',
+        'externalRollup.js',
+      ].forEach(function (filename) {
+        if (EXPORTS.requireFs.existsSync(EXPORTS.FS_EXTERNAL + '/' + filename)) {
+          EXPORTS.MODULE_FILE['/public/cacheVersion/' + filename] = EXPORTS.requireFs.readFileSync(EXPORTS.FS_EXTERNAL + '/' + filename);
+        }
+      });
+      //// auto rollup
+      if (EXPORTS.EXTERNAL_ROLLUP) {
+        EXPORTS.externalRollup();
+      }
+    },
+
+    externalDataUri: function (filename) {
+      return '\n"data:' + EXPORTS.requireMime.lookup(filename) + ';base64,' + EXPORTS.requireFs.readFileSync(filename, 'base64') + '"\n';
+    },
+
+    externalGet: function (arr) {
+      var filename, ii = 0, obj = {};
+      function closure(filename) {
+        ii += 1;
+        EXPORTS.httpGet({
+          callback: function (err, data, response) {
+            var arr;
+            ii -= 1;
+            try {
+              if (err) { throw err; }
+              console.assert(response.statusCode === 200, response.statusCode);
+              EXPORTS.requireFs.writeFileSync(EXPORTS.FS_EXTERNAL + '/' + filename, data);
+              delete obj[filename];
+            } catch (errCallback) {
+              console.log(errCallback.stack);
+              console.log(response.headers);
+            }
+            console.log(filename, 'EXPORTS.externalGet(' + JSON.stringify(Object.keys(obj).sort()) + ')\n');
+            //// finished attempting to download all files
+            if (ii === 0) { console.log(obj); }
+          },
+          url: obj[filename]
+        });
+      }
+      //// debug - test culled EXPORTS.EXTERNAL_URL
+      (arr || Object.keys(EXPORTS.EXTERNAL_URL)).forEach(function (filename) {
+        obj[filename] = EXPORTS.EXTERNAL_URL[filename];
+      });
+      for (filename in obj) {
+        if (obj.hasOwnProperty(filename)) { closure(filename); }
+      }
+    },
+
+    externalRollup: function () {
+      var css = '', js = '';
+      Object.keys(EXPORTS.EXTERNAL_URL).sort().forEach(function (filename) {
+        switch (EXPORTS.requirePath.extname(filename)) {
+        case '.css':
+          css += EXPORTS._externalRollupFile(filename);
+          break;
+        case '.js':
+          js += EXPORTS._externalRollupFile(filename);
+          break;
+        }
+      });
+      [
+        'imgAjaxLoader.gif'
+      ].forEach(function (filename) {
+        css += '.' + (/\w+/).exec(filename) + ' { background: url(' + EXPORTS.externalDataUri(EXPORTS.FS_EXTERNAL + '/' + filename) + ') no-repeat center center;';
+      });
+      EXPORTS.requireFs.writeFileSync(EXPORTS.FS_EXTERNAL + '/externalRollup.css', css);
+      EXPORTS.requireFs.writeFileSync(EXPORTS.FS_EXTERNAL + '/externalRollup.js', js);
+    },
+
+    _externalRollupFile: function (filename) {
+      var data = EXPORTS.requireFs.readFileSync(EXPORTS.FS_EXTERNAL + '/' + filename, 'utf8') + '\n';
+      switch (filename) {
+      case 'bootstrap.css':
+        data = data.replace(/"\.\.\/img\/(.+)"/g, function (_, filename) {
+          return EXPORTS.externalDataUri(EXPORTS.FS_EXTERNAL + '/bootstrap.' + filename);
+        });
+        break;
+      case 'datatables.css':
+        data = data.replace(/'\.\.\/images\/(.+)'/g, function (_, filename) {
+          return EXPORTS.externalDataUri(EXPORTS.FS_EXTERNAL + '/datatables.' + filename);
+        });
+        break;
+      case 'select2.css':
+        data = data.replace(/'(\w+\.png)'/g, function (_, filename) {
+          return EXPORTS.externalDataUri(EXPORTS.FS_EXTERNAL + '/' + filename);
+        });
+        break;
+      }
+      return (data += '\n');
+    }
+
+  };
+
+  local._init();
+
+}());
+
+
+
+/**
+ * @module moduleAdmin