[
  {
    "path": ".babelrc",
    "content": "{\n  \"presets\": [ [ \"babel-preset-env\", {\n    \"targets\": {\n      \"browsers\": [\"last 2 versions\", \"safari >= 7\"]\n    } } ], \"stage-0\", \"react\" ],\n  \"plugins\": [\n    \"glamor/babel-hoist\",\n    [\"transform-react-jsx\", {\n      \"pragma\": \"require('glamor/react').createElement\"\n    }]\n  ],\n  \"ignore\": [\n    \"node_modules/*\"\n  ]\n}"
  },
  {
    "path": ".gitignore",
    "content": "# osx noise\n.DS_Store\nprofile\n\n# xcode noise\nbuild/*\n*.mode1\n*.mode1v3\n*.mode2v3\n*.perspective\n*.perspectivev3\n*.pbxuser\n*.xcworkspace\nxcuserdata\n\n# svn & cvs\n.svn\nCVS\nnode_modules\nout\n"
  },
  {
    "path": "bin/ratpack",
    "content": "#!/usr/bin/env node\n// todo - windows\nlet opn = require('opn')\nlet spawn = require('child_process').spawn\nlet fs = require('fs')\nlet path = require('path')\nlet appdir = fs.readdirSync(path.join(__dirname, '../out')).filter(x => /^ratpack\\-/.test(x))[0] \nlet argv = require('minimist')(process.argv.slice(1))\nif(argv.app) {\n  // ratpack --app  \n  // opens directory holding the app\n  opn(path.join(__dirname, `../out/${appdir}`), { wait: false }).then(\n    () => process.exit(0), \n    err => console.error(err)) // eslint-disable-line no-console\n}\nelse {\n  // ratpack\n  // ratpack path/to/script.js \n  // this should open a new app instance, not hold a process in terminal. \n  // todo - windows, linux\n  let binpath = path.join(__dirname, `../out/${appdir}/ratpack.app/Contents/MacOS/ratpack`)\n\n  let script = argv._[1], \n    opts = argv.dev ? { stdio: 'inherit' } : { detached: true }, \n    args = script ? \n      [ binpath, [ path.join(process.cwd(), script) ], opts ]:\n      [ binpath, [], opts ],\n    child = spawn(...args)\n  \n  if(!argv.dev) {\n    child.unref()\n    process.exit(0)\n  } \n}\n\n// that's it. no other apis planned for now.\n"
  },
  {
    "path": "docs/pragmas.md",
    "content": "magic pragmas\n---\n\nratpack supports some magic incantations you can put at the top of your entry file \nto customize the webpack/babel backends. A simple example would look like this - \n\n```jsx\n/* @ratpack {\n  devtool: 'eval',\n  alias: {\n    react: 'preact-compat',\n    react-dom: 'preact-compat'\n  }\n}\n*/\nrequire('react-dom').render(<div>look, preact!</div>, window.root)\n```\n(assuming preact-compat is available locally or in `.ratpack/node_modules`)\n\n\nHere's a full list of working pragmas\n\n- `devtool: 'source-map'` [(ref.)](https://webpack.js.org/configuration/devtool/#devtool)\n- `reload: false` toggle live reloads, defaults to `true`\n- `port: 3999` \n- `stats: true` shows a [stats.js](https://github.com/mrdoob/stats.js/) fps window\n- `production: true` particularly good for running benchmarks, etc\n- `public: './my/public/folder'` [(ref.)](https://webpack.js.org/configuration/dev-server/#devserver-contentbase)\n- `jsx: 'Inferno.createElement'` This is different from babel's `@jsx` pragma, in that it will apply to *all* js files, not just the one \n- `proxy: { '/api': 'http://localhost:3000' }` [(ref.)](https://webpack.js.org/configuration/dev-server/#devserver-proxy)\n- `provide: { 'Glamor': 'glamor/react' }` [(ref.)](https://webpack.js.org/guides/shimming/#provide-plugin)\n- `alias`\n  \n  ```\n  alias: {\n    react: 'preact-compat',\n    react-dom: 'preact-compat'\n  }\n  ```\n  [(ref.)](https://webpack.js.org/configuration/resolve/#resolve-alias)\n- `define: { 'process.env.NODE_ENV': 'test' }` [(ref.)](https://webpack.js.org/plugins/define-plugin/)\n- `rules: [ { files: '*.vue', loader: 'vue-loader', options: { some: 'options' } } , ...]` \n  \n  nb: `files` is a glob, which gets converted to a regex for webpack's `test` prop \n- babel presets and plugins\n  \n  ```\n  babel: {\n    presets: ['vue', [ 'a11y', {...} ],\n    plugins: ['./some/path', ... ]\n  }\n  ```\n\n\n\nThese don't 'work' yet, but could/will in the future\n\n- `target: 'node'` [(ref.)](https://webpack.js.org/configuration/target/#target)\n- `hot: true` [(ref.)](https://webpack.js.org/concepts/hot-module-replacement/)\n- `offline: true || <options>` [(ref.)](https://github.com/NekR/offline-plugin)\n- `autoinstall: true` [(ref.)](https://github.com/ericclemmons/npm-install-webpack-plugin)\n- `plugins: [ {<module> <options>}, ... ]`\n\n\n\nthoughts/questions/ideas?"
  },
  {
    "path": "examples/polyf.js",
    "content": "let x = function* () {\n\n}\n"
  },
  {
    "path": "examples/pragmas.js",
    "content": "/* @ratpack {\n  target: 'node',\n  devtool: 'eval',\n  public: '../public',\n  proxy: {\n    '/yahoo': 'http://www.yahoo.com'\n  },\n  define: {\n    'process.env.NODE_ENV': 'test'\n  },\n  offline: true,\n  autoinstall: true,\n  rules: [{ loader: 'cowsay-loader' }]\n}\n*/\n\n/* eslint semi: 0 */\n\nimport { render } from 'react-dom';\nrender(<div>456</div>, window.root);\n\nfetch('/yahoo')\n \n"
  },
  {
    "path": "examples/scratch.js",
    "content": "// @ratpack { stats: true }\nconsole.log('here') //eslint-disable-line no-console\n\nrequire('react-dom').render(<div>what up</div>, window.root)\nconsole.log(123)"
  },
  {
    "path": "lib/app.js",
    "content": "'use strict';\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\nvar _querystring = require('querystring');\n\nvar _querystring2 = _interopRequireDefault(_querystring);\n\nvar _autoprefixer = require('autoprefixer');\n\nvar _autoprefixer2 = _interopRequireDefault(_autoprefixer);\n\nvar _react = require('react');\n\nvar _react2 = _interopRequireDefault(_react);\n\nvar _path = require('path');\n\nvar _path2 = _interopRequireDefault(_path);\n\nvar _reactDom = require('react-dom');\n\nrequire('glamor/reset');\n\nvar _hash = require('glamor/lib/hash');\n\nvar _hash2 = _interopRequireDefault(_hash);\n\nvar _pragmas = require('./pragmas');\n\nvar _pragmas2 = _interopRequireDefault(_pragmas);\n\nvar _globToRegexp = require('glob-to-regexp');\n\nvar _globToRegexp2 = _interopRequireDefault(_globToRegexp);\n\nvar _openBrowser = require('react-dev-utils/openBrowser');\n\nvar _openBrowser2 = _interopRequireDefault(_openBrowser);\n\nvar _offlinePlugin = require('offline-plugin');\n\nvar _offlinePlugin2 = _interopRequireDefault(_offlinePlugin);\n\nvar _webpackDevServer = require('webpack-dev-server');\n\nvar _webpackDevServer2 = _interopRequireDefault(_webpackDevServer);\n\nvar _webpack = require('webpack');\n\nvar _webpack2 = _interopRequireDefault(_webpack);\n\nvar _glamor = require('glamor');\n\nvar _nedb = require('nedb');\n\nvar _nedb2 = _interopRequireDefault(_nedb);\n\nvar _mkdirp = require('mkdirp');\n\nvar _mkdirp2 = _interopRequireDefault(_mkdirp);\n\nvar _touch = require('touch');\n\nvar _touch2 = _interopRequireDefault(_touch);\n\nvar _fs = require('fs');\n\nvar _fs2 = _interopRequireDefault(_fs);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nfunction _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return call && (typeof call === \"object\" || typeof call === \"function\") ? call : self; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function, not \" + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nvar electron = require('electron');\nvar app = electron.app || electron.remote.app;\n\nvar yellow = '#f7df1e';\n\nvar db = new _nedb2.default({\n  filename: _path2.default.join(app.getPath('userData'), 'store.db'),\n  autoload: true\n});\ndb.find({ _id: 'recently' }, function (err, docs) {\n  if (docs.length === 0) {\n    db.insert({ _id: 'recently', files: [] }, function (err) {\n      if (err) return console.error(err); //eslint-disable-line no-console\n      console.log('db initialized'); //eslint-disable-line no-console\n    });\n  } else console.log('db restarted'); //eslint-disable-line no-console\n});\n\n// todo - move this to main.js \n\n\n// todo - windows\n(0, _mkdirp2.default)(_path2.default.join(app.getPath('home'), '.ratpack'), function (err) {\n  if (err) {\n    throw err;\n  }\n  var pkjson = _path2.default.join(app.getPath('home'), '.ratpack/package.json');\n  if (!_fs2.default.existsSync(pkjson)) {\n    _touch2.default.sync(pkjson);\n    _fs2.default.writeFileSync(pkjson, JSON.stringify({\n      name: 'ratpack-local',\n      description: 'these modules are available to all scripts launched by ratpack'\n    }));\n  }\n  // among other things, this makes loaders defined in pragmas to work \n  require('module').globalPaths.push(_path2.default.join(app.getPath('home'), '.ratpack/node_modules'));\n});\n\nfunction times(n, fn) {\n  var arr = [];\n  for (var i = 0; i < n; i++) {\n    arr.push(fn(i));\n  }\n  return arr;\n}\n\n_glamor.css.global('html, body, #root', { position: 'relative', width: '100%', height: '100%', display: 'block', backgroundColor: yellow });\n\nvar Logo = function Logo() {\n  return require('glamor/react').createElement(\n    'div',\n    { css: _defineProperty({ width: 100, height: 100, position: 'absolute', bottom: 0, right: 0 }, _glamor.presets.Phablet, { width: 200, height: 200 }) },\n    require('glamor/react').createElement(\n      'svg',\n      { xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 630 630' },\n      require('glamor/react').createElement('path', { d: 'm423.2 492.19c12.69 20.72 29.2 35.95 58.4 35.95 24.53 0 40.2-12.26 40.2-29.2 0-20.3-16.1-27.49-43.1-39.3l-14.8-6.35c-42.72-18.2-71.1-41-71.1-89.2 0-44.4 33.83-78.2 86.7-78.2 37.64 0 64.7 13.1 84.2 47.4l-46.1 29.6c-10.15-18.2-21.1-25.37-38.1-25.37-17.34 0-28.33 11-28.33 25.37 0 17.76 11 24.95 36.4 35.95l14.8 6.34c50.3 21.57 78.7 43.56 78.7 93 0 53.3-41.87 82.5-98.1 82.5-54.98 0-90.5-26.2-107.88-60.54zm-209.13 5.13c9.3 16.5 17.76 30.45 38.1 30.45 19.45 0 31.72-7.61 31.72-37.2v-201.3h59.2v202.1c0 61.3-35.94 89.2-88.4 89.2-47.4 0-74.85-24.53-88.81-54.075z' })\n    )\n  );\n};\n\nvar _ref = { width: '100%', height: '100%', fontFamily: 'helvetica' };\nvar _ref2 = { padding: 20 };\n\nvar App = function (_React$Component) {\n  _inherits(App, _React$Component);\n\n  function App() {\n    var _ref4;\n\n    var _temp, _this, _ret;\n\n    _classCallCheck(this, App);\n\n    for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {\n      args[_key] = arguments[_key];\n    }\n\n    return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref4 = App.__proto__ || Object.getPrototypeOf(App)).call.apply(_ref4, [this].concat(args))), _this), _this.state = {\n      tick: 0,\n      filepath: undefined,\n      webpackCompiler: null,\n      webpackServer: null,\n      recently: [],\n      errors: [],\n      port: 0,\n      running: false\n    }, _this.onOpenFile = function (e, filepath) {\n      _this.loadFile(filepath);\n    }, _this.onDrop = function (e) {\n      e.preventDefault();\n      e.stopPropagation();\n      var filepath = e.nativeEvent.dataTransfer.files[0].path;\n      _this.loadFile(filepath);\n    }, _temp), _possibleConstructorReturn(_this, _ret);\n  }\n\n  _createClass(App, [{\n    key: 'refreshRecentList',\n    value: function refreshRecentList(cb) {\n      var _this2 = this;\n\n      db.find({ _id: 'recently' }, function (err, docs) {\n        if (err) {\n          _this2.setState({\n            errors: [].concat(_toConsumableArray(_this2.state.errors), [err])\n          });\n          return;\n        }\n        _this2.setState({\n          recently: docs[0].files\n        });\n        if (cb) cb();\n      });\n    }\n  }, {\n    key: 'componentDidMount',\n    value: function componentDidMount() {\n      var _this3 = this;\n\n      app.on('open-file', this.onOpenFile);\n      this.refreshRecentList(function () {\n        if (window.location.search) {\n          var filepath = _querystring2.default.parse(window.location.search.slice(1)).startsWith;\n          filepath && _this3.loadFile(filepath);\n        }\n      });\n      this.interval = setInterval(function () {\n        _this3.setState({\n          tick: (_this3.state.tick + 1) % 4\n        });\n      }, 400);\n    }\n  }, {\n    key: 'componentWillUnmount',\n    value: function componentWillUnmount() {\n      clearInterval(this.interval);\n      this.interval = null;\n\n      if (this.state.webpackServer) {\n        this.state.webpackServer.close();\n      }\n      if (this.watcher) {\n        this.watcher.close();\n        this.watcher = null;\n      }\n      app.removeEventListener('open-file', this.onOpenFile);\n    }\n  }, {\n    key: '_loadFile',\n    value: function _loadFile(filepath) {\n      var _this4 = this;\n\n      _fs2.default.readFile(filepath, 'utf8', function (err, src) {\n        if (err) throw err;\n        var options = (0, _pragmas2.default)(src);\n        _this4.setState(_extends({}, webpackify(filepath, options), { filepath: filepath, running: true, pragmas: options }));\n\n        // simultaneously start watching the entry file \n        _this4.watcher = _fs2.default.watch(filepath, function (e) {\n          if (e === 'rename') {\n            // ???\n            return;\n          }\n          // if any of the pragmas change, redo this shindig \n          _fs2.default.readFile(filepath, 'utf8', function (err, src) {\n            var options = (0, _pragmas2.default)(src);\n            if (JSON.stringify(options) !== JSON.stringify(_this4.state.pragmas)) {\n              _this4.loadFile(filepath);\n            }\n            // todo - prevent double read \n          });\n        });\n      });\n    }\n  }, {\n    key: 'loadFile',\n    value: function loadFile(filepath) {\n      var _this5 = this;\n\n      db.update({ _id: 'recently' }, { _id: 'recently', files: [{ path: filepath }].concat(_toConsumableArray(this.state.recently.filter(function (x) {\n          return x.path !== filepath;\n        }))).slice(0, 10) }, {}, function (err) {\n        if (err) {\n          _this5.setState({\n            errors: [].concat(_toConsumableArray(_this5.state.errors), [err])\n          });\n          return;\n        }\n        _this5.refreshRecentList();\n      });\n      if (this.watcher) {\n        this.watcher.close();\n        this.watcher = null;\n      }\n\n      if (this.state.webpackServer) {\n        this.state.webpackServer.close();\n        setTimeout(function () {\n          _this5._loadFile(filepath);\n        }, 500);\n      } else {\n        this._loadFile(filepath);\n      }\n    }\n  }, {\n    key: 'clearRecentList',\n    value: function clearRecentList() {\n      var _this6 = this;\n\n      db.update({ _id: 'recently' }, { _id: 'recently', files: [] }, function () {\n        _this6.refreshRecentList();\n      });\n    }\n  }, {\n    key: 'render',\n    value: function render() {\n      var _this7 = this;\n\n      return require('glamor/react').createElement(\n        'div',\n        {\n          css: _ref,\n          onDragOver: function onDragOver(e) {\n            return e.preventDefault();\n          } // chrome bug \n          , onDrop: this.onDrop },\n        require('glamor/react').createElement(\n          'div',\n          { css: _defineProperty({ fontWeight: 'bolder', fontSize: 32, padding: 20 }, _glamor.presets.Phablet, { fontSize: 64 }) },\n          this.state.running ? _path2.default.basename(this.state.filepath) + ' running at \\n        localhost:' + this.state.port + times(this.state.tick, function () {\n            return '.';\n          }).join('') : 'Drop a .js file here to get started '\n        ),\n        this.state.recently.length > 0 && require('glamor/react').createElement(\n          'div',\n          { css: _ref2 },\n          require('glamor/react').createElement(\n            'h1',\n            null,\n            'previously...'\n          ),\n          this.state.recently.map(function (x) {\n            return require('glamor/react').createElement(\n              'div',\n              { key: x.path, onClick: function onClick() {\n                  return _this7.loadFile(x.path);\n                } },\n              x.path\n            );\n          }),\n          require('glamor/react').createElement(\n            'h4',\n            { onClick: function onClick() {\n                return _this7.clearRecentList();\n              } },\n            'clear list'\n          )\n        ),\n        require('glamor/react').createElement(Logo, null)\n      );\n    }\n  }]);\n\n  return App;\n}(_react2.default.Component);\n\nfunction webpackify(filepath) {\n  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n\n  var webpackCompiler = (0, _webpack2.default)({\n    devtool: options.production ? false : options.devtool || 'cheap-module-source-map',\n    entry: [options.reload !== false || options.production !== true ? require.resolve('react-dev-utils/webpackHotDevClient.js') : undefined, options.stats ? require.resolve('./stats.js') : undefined, require.resolve('./polyfills'), options.offline ? require.resolve('./offline-plugin-runtime.js') : undefined, filepath].filter(function (x) {\n      return !!x;\n    }),\n    output: {\n      path: _path2.default.join(__dirname, '../public'),\n      pathinfo: true,\n      filename: 'bundle.js'\n    },\n    performance: {\n      hints: false\n    },\n    module: {\n      rules: [].concat(_toConsumableArray((options.rules || []).map(function (_ref6) {\n        var loader = _ref6.loader,\n            files = _ref6.files,\n            options = _ref6.options;\n        return { loader: require.resolve(loader), options: options, test: (0, _globToRegexp2.default)(files || '*') };\n      })), [{\n        enforce: 'pre',\n        test: /\\.(js|jsx)$/,\n        loader: require.resolve('eslint-loader'),\n        exclude: /node_modules/,\n        options: {\n          configFile: _path2.default.join(__dirname, '../resources/.eslintrc')\n        }\n      }, {\n        exclude: [/\\.html$/, /\\.(js|jsx)$/, /\\.css$/, /\\.json$/, /\\.svg$/],\n        loader: require.resolve('url-loader'),\n        query: {\n          limit: 10000,\n          name: 'static/media/[name].[hash:8].[ext]'\n        }\n      }, {\n        test: /\\.js$/,\n        exclude: /node_modules/,\n        loader: require.resolve('babel-loader'),\n        options: {\n          'presets': [[require('babel-preset-env'), {\n            'targets': {\n              'browsers': ['last 2 versions', 'safari >= 7']\n            },\n            modules: false\n          }], require('babel-preset-stage-0'), require('babel-preset-react')].concat(_toConsumableArray((options.babel || {}).presets || [])),\n          'plugins': [[require.resolve('babel-plugin-transform-runtime'), {\n            helpers: false,\n            polyfill: false,\n            regenerator: true\n            // Resolve the Babel runtime relative to the config.\n            // moduleName: path.dirname(require.resolve('babel-runtime/package'))\n          }], options.jsx ? [require('babel-plugin-transform-react-jsx'), { 'pragma': options.jsx }] : undefined, require('babel-plugin-transform-decorators-legacy').default, require('babel-plugin-transform-react-require').default].concat(_toConsumableArray((options.babel || {}).plugins || [])).filter(function (x) {\n            return !!x;\n          }),\n          cacheDirectory: false\n        }\n      }, {\n        test: /\\.css$/,\n        use: [require.resolve('style-loader'), {\n          loader: require.resolve('css-loader'),\n          options: { importLoaders: 1 }\n        }, require.resolve('postcss-loader') // options in the plugins section below             \n        ]\n      },\n      // {\n      //   test: /\\.json$/,\n      //   loader: require.resolve('json-loader')\n      // },\n      {\n        test: /\\.svg$/,\n        loader: require.resolve('file-loader'),\n        query: {\n          name: 'static/media/[name].[hash:8].[ext]'\n        }\n      }])\n    },\n    resolve: {\n      alias: options.alias || {},\n      extensions: ['.js', '.json', '.jsx'],\n      modules: ['node_modules', _path2.default.join(app.getPath('home'), '.ratpack/node_modules'), _path2.default.join(__dirname, '../node_modules')]\n    },\n    plugins: [new _webpack2.default.DefinePlugin(_extends({\n      'process.env.NODE_ENV': JSON.stringify(options.production && 'production' || process.env.NODE_ENV || 'development')\n    }, Object.keys(options.define || {}).reduce(function (o, key) {\n      return _extends({}, o, _defineProperty({}, key, JSON.stringify(options.define[key])));\n    }, {}))), options.offline ? new _offlinePlugin2.default(options.offline === true ? {} : options.offline) : undefined, new _webpack2.default.ProvidePlugin(options.provide || {}), new _webpack2.default.LoaderOptionsPlugin({\n      test: /\\.css$/,\n      debug: true,\n      options: {\n        postcss: [(0, _autoprefixer2.default)({\n          browsers: ['>1%', 'last 4 versions', 'Firefox ESR', 'not ie < 9' // React doesn't support IE8 anyway\n          ]\n        })]\n      }\n    })].filter(function (x) {\n      return !!x;\n    }),\n    stats: 'errors-only',\n    node: {\n      fs: 'empty',\n      net: 'empty',\n      tls: 'empty'\n    }\n  });\n\n  var webpackServer = new _webpackDevServer2.default(webpackCompiler, {\n    contentBase: [options.public ? _path2.default.join(_path2.default.dirname(filepath), options.public) : '', _path2.default.join(_path2.default.dirname(filepath), 'public'), _path2.default.join(__dirname, '../public')].filter(function (x) {\n      return !!x;\n    }),\n    historyApiFallback: true,\n    compress: true,\n    proxy: options.proxy || {},\n    // setup()\n    // staticOptions \n\n    quiet: true,\n    stats: { colors: false }\n  });\n  // this is to workaround some weird bug where webpack keeps the first loaded file \n  // also makes it look cool ha\n  var h = (0, _hash2.default)(filepath, filepath.length) + '';\n  var port = options.port || 3000 + parseInt(h.substr(h.length - 4), 10);\n  webpackServer.listen(port);\n  (0, _openBrowser2.default)('http://localhost:' + port);\n  return { webpackServer: webpackServer, webpackCompiler: webpackCompiler, port: port };\n}\n\n(0, _reactDom.render)(require('glamor/react').createElement(App, null), document.getElementById('root'));\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9hcHAuanMiXSwibmFtZXMiOlsiZWxlY3Ryb24iLCJyZXF1aXJlIiwiYXBwIiwicmVtb3RlIiwieWVsbG93IiwiZGIiLCJmaWxlbmFtZSIsImpvaW4iLCJnZXRQYXRoIiwiYXV0b2xvYWQiLCJmaW5kIiwiX2lkIiwiZXJyIiwiZG9jcyIsImxlbmd0aCIsImluc2VydCIsImZpbGVzIiwiY29uc29sZSIsImVycm9yIiwibG9nIiwicGtqc29uIiwiZXhpc3RzU3luYyIsInN5bmMiLCJ3cml0ZUZpbGVTeW5jIiwiSlNPTiIsInN0cmluZ2lmeSIsIm5hbWUiLCJkZXNjcmlwdGlvbiIsImdsb2JhbFBhdGhzIiwicHVzaCIsInRpbWVzIiwibiIsImZuIiwiYXJyIiwiaSIsImdsb2JhbCIsInBvc2l0aW9uIiwid2lkdGgiLCJoZWlnaHQiLCJkaXNwbGF5IiwiYmFja2dyb3VuZENvbG9yIiwiTG9nbyIsImJvdHRvbSIsInJpZ2h0IiwiUGhhYmxldCIsImZvbnRGYW1pbHkiLCJwYWRkaW5nIiwiQXBwIiwic3RhdGUiLCJ0aWNrIiwiZmlsZXBhdGgiLCJ1bmRlZmluZWQiLCJ3ZWJwYWNrQ29tcGlsZXIiLCJ3ZWJwYWNrU2VydmVyIiwicmVjZW50bHkiLCJlcnJvcnMiLCJwb3J0IiwicnVubmluZyIsIm9uT3BlbkZpbGUiLCJlIiwibG9hZEZpbGUiLCJvbkRyb3AiLCJwcmV2ZW50RGVmYXVsdCIsInN0b3BQcm9wYWdhdGlvbiIsIm5hdGl2ZUV2ZW50IiwiZGF0YVRyYW5zZmVyIiwicGF0aCIsImNiIiwic2V0U3RhdGUiLCJvbiIsInJlZnJlc2hSZWNlbnRMaXN0Iiwid2luZG93IiwibG9jYXRpb24iLCJzZWFyY2giLCJwYXJzZSIsInNsaWNlIiwic3RhcnRzV2l0aCIsImludGVydmFsIiwic2V0SW50ZXJ2YWwiLCJjbGVhckludGVydmFsIiwiY2xvc2UiLCJ3YXRjaGVyIiwicmVtb3ZlRXZlbnRMaXN0ZW5lciIsInJlYWRGaWxlIiwic3JjIiwib3B0aW9ucyIsIndlYnBhY2tpZnkiLCJwcmFnbWFzIiwid2F0Y2giLCJ1cGRhdGUiLCJmaWx0ZXIiLCJ4Iiwic2V0VGltZW91dCIsIl9sb2FkRmlsZSIsImZvbnRXZWlnaHQiLCJmb250U2l6ZSIsImJhc2VuYW1lIiwibWFwIiwiY2xlYXJSZWNlbnRMaXN0IiwiQ29tcG9uZW50IiwiZGV2dG9vbCIsInByb2R1Y3Rpb24iLCJlbnRyeSIsInJlbG9hZCIsInJlc29sdmUiLCJzdGF0cyIsIm9mZmxpbmUiLCJvdXRwdXQiLCJfX2Rpcm5hbWUiLCJwYXRoaW5mbyIsInBlcmZvcm1hbmNlIiwiaGludHMiLCJtb2R1bGUiLCJydWxlcyIsImxvYWRlciIsInRlc3QiLCJlbmZvcmNlIiwiZXhjbHVkZSIsImNvbmZpZ0ZpbGUiLCJxdWVyeSIsImxpbWl0IiwibW9kdWxlcyIsImJhYmVsIiwicHJlc2V0cyIsImhlbHBlcnMiLCJwb2x5ZmlsbCIsInJlZ2VuZXJhdG9yIiwianN4IiwiZGVmYXVsdCIsInBsdWdpbnMiLCJjYWNoZURpcmVjdG9yeSIsInVzZSIsImltcG9ydExvYWRlcnMiLCJhbGlhcyIsImV4dGVuc2lvbnMiLCJEZWZpbmVQbHVnaW4iLCJwcm9jZXNzIiwiZW52IiwiTk9ERV9FTlYiLCJPYmplY3QiLCJrZXlzIiwiZGVmaW5lIiwicmVkdWNlIiwibyIsImtleSIsIlByb3ZpZGVQbHVnaW4iLCJwcm92aWRlIiwiTG9hZGVyT3B0aW9uc1BsdWdpbiIsImRlYnVnIiwicG9zdGNzcyIsImJyb3dzZXJzIiwibm9kZSIsImZzIiwibmV0IiwidGxzIiwiY29udGVudEJhc2UiLCJwdWJsaWMiLCJkaXJuYW1lIiwiaGlzdG9yeUFwaUZhbGxiYWNrIiwiY29tcHJlc3MiLCJwcm94eSIsInF1aWV0IiwiY29sb3JzIiwiaCIsInBhcnNlSW50Iiwic3Vic3RyIiwibGlzdGVuIiwiZG9jdW1lbnQiLCJnZXRFbGVtZW50QnlJZCJdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQ0E7Ozs7QUFDQTs7OztBQUNBOzs7O0FBQ0E7Ozs7QUFDQTs7QUFD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QUEsS0FBbkssQ0FEMkM7QUFFeERtRSx3QkFBb0IsSUFGb0M7QUFHeERDLGNBQVUsSUFIOEM7QUFJeERDLFdBQU8zRSxRQUFRMkUsS0FBUixJQUFpQixFQUpnQztBQUtwRDtBQUNBOztBQUVKQyxXQUFPLElBUmlEO0FBU3hEeEQsV0FBTyxFQUFFeUQsUUFBUSxLQUFWO0FBVGlELEdBQXRDLENBQXBCO0FBV0U7QUFDQTtBQUNGLE1BQUlDLElBQUksb0JBQUtqSCxRQUFMLEVBQWVBLFNBQVNwQyxNQUF4QixJQUFpQyxFQUF6QztBQUNBLE1BQUkwQyxPQUFPNkIsUUFBUTdCLElBQVIsSUFBaUIsT0FBTzRHLFNBQVNELEVBQUVFLE1BQUYsQ0FBU0YsRUFBRXJKLE1BQUYsR0FBVyxDQUFwQixDQUFULEVBQWlDLEVBQWpDLENBQW5DO0FBQ0F1QyxnQkFBY2lILE1BQWQsQ0FBcUI5RyxJQUFyQjtBQUNBLDZCQUFZLHNCQUFzQkEsSUFBbEM7QUFDQSxTQUFPLEVBQUVILDRCQUFGLEVBQWlCRCxnQ0FBakIsRUFBa0NJLFVBQWxDLEVBQVA7QUFFRDs7QUFFRCxzQkFBTyxzQ0FBQyxHQUFELE9BQVAsRUFBZStHLFNBQVNDLGNBQVQsQ0FBd0IsTUFBeEIsQ0FBZiIsImZpbGUiOiJhcHAuanMiLCJzb3VyY2VzQ29udGVudCI6WyJcbmltcG9ydCBxcyBmcm9tICdxdWVyeXN0cmluZydcbmltcG9ydCBhdXRvcHJlZml4ZXIgZnJvbSAnYXV0b3ByZWZpeGVyJ1xuaW1wb3J0IFJlYWN0IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHBhdGggZnJvbSAncGF0aCdcbmltcG9ydCB7IHJlbmRlciB9IGZyb20gJ3JlYWN0LWRvbSdcbmltcG9ydCAnZ2xhbW9yL3Jlc2V0J1xuaW1wb3J0IGhhc2ggZnJvbSAnZ2xhbW9yL2xpYi9oYXNoJ1xuaW1wb3J0IHByYWdtYXMgZnJvbSAnLi9wcmFnbWFzJ1xuaW1wb3J0IGdsb2IycmVnZXhwIGZyb20gJ2dsb2ItdG8tcmVnZXhwJ1xuaW1wb3J0IG9wZW5Ccm93c2VyIGZyb20gJ3JlYWN0LWRldi11dGlscy9vcGVuQnJvd3NlcidcbmltcG9ydCBPZmZsaW5lUGx1Z2luIGZyb20gJ29mZmxpbmUtcGx1Z2luJ1xuXG5jb25zdCBlbGVjdHJvbiA9IHJlcXVpcmUoJ2VsZWN0cm9uJylcbmNvbnN0IGFwcCA9IGVsZWN0cm9uLmFwcCB8fCBlbGVjdHJvbi5yZW1vdGUuYXBwXG5cblxuaW1wb3J0IFdlYnBhY2tEZXZTZXJ2ZXIgZnJvbSAnd2VicGFjay1kZXYtc2VydmVyJ1xuaW1wb3J0IHdlYnBhY2sgZnJvbSAnd2VicGFjaydcblxuaW1wb3J0IHsgY3NzLCBwcmVzZXRzIH0gZnJvbSAnZ2xhbW9yJ1xuY29uc3QgeWVsbG93ID0gJyNmN2RmMWUnXG5cblxuaW1wb3J0IERhdGFTdG9yZSBmcm9tICduZWRiJ1xubGV0IGRiID0gbmV3IERhdGFTdG9yZSh7XG4gIGZpbGVuYW1lOiBwYXRoLmpvaW4oYXBwLmdldFBhdGgoJ3VzZXJEYXRhJyksICdzdG9yZS5kYicpLFxuICBhdXRvbG9hZDogdHJ1ZVxufSlcbmRiLmZpbmQoeyBfaWQ6ICdyZWNlbnRseScgfSwgKGVyciwgZG9jcykgPT4ge1xuICBpZihkb2NzLmxlbmd0aCA9PT0gMCkge1xuICAgIGRiLmluc2VydCh7IF9pZDogJ3JlY2VudGx5JywgZmlsZXM6IFtdIH0sIGVyciA9PiB7XG4gICAgICBpZihlcnIpIHJldHVybiBjb25zb2xlLmVycm9yKGVycikgLy9lc2xpbnQtZGlzYWJsZS1saW5lIG5vLWNvbnNvbGVcbiAgICAgIGNvbnNvbGUubG9nKCdkYiBpbml0aWFsaXplZCcpIC8vZXNsaW50LWRpc2FibGUtbGluZSBuby1jb25zb2xlXG4gICAgfSlcbiAgfVxuICBlbHNlIGNvbnNvbGUubG9nKCdkYiByZXN0YXJ0ZWQnKSAgLy9lc2xpbnQtZGlzYWJsZS1saW5lIG5vLWNvbnNvbGVcbn0pXG5cbi8vIHRvZG8gLSBtb3ZlIHRoaXMgdG8gbWFpbi5qcyBcbmltcG9ydCBta2RpcnAgZnJvbSAnbWtkaXJwJ1xuaW1wb3J0IHRvdWNoIGZyb20gJ3RvdWNoJ1xuaW1wb3J0IGZzIGZyb20gJ2ZzJ1xuXG5cbi8vIHRvZG8gLSB3aW5kb3dzXG5ta2RpcnAocGF0aC5qb2luKGFwcC5nZXRQYXRoKCdob21lJyksICcucmF0cGFjaycpLCBlcnIgPT4ge1xuICBpZihlcnIpIHtcbiAgICB0aHJvdyBlcnJcbiAgfVxuICBsZXQgcGtqc29uID0gcGF0aC5qb2luKGFwcC5nZXRQYXRoKCdob21lJyksICcucmF0cGFjay9wYWNrYWdlLmpzb24nKVxuICBpZighZnMuZXhpc3RzU3luYyhwa2pzb24pKSB7XG4gICAgdG91Y2guc3luYyhwa2pzb24pXG4gICAgZnMud3JpdGVGaWxlU3luYyhwa2pzb24sIEpTT04uc3RyaW5naWZ5KHtcbiAgICAgIG5hbWU6ICdyYXRwYWNrLWxvY2FsJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAndGhlc2UgbW9kdWxlcyBhcmUgYXZhaWxhYmxlIHRvIGFsbCBzY3JpcHRzIGxhdW5jaGVkIGJ5IHJhdHBhY2snXG4gICAgfSkpICBcbiAgfVxuICAvLyBhbW9uZyBvdGhlciB0aGluZ3MsIHRoaXMgbWFrZXMgbG9hZGVycyBkZWZpbmVkIGluIHByYWdtYXMgdG8gd29yayBcbiAgcmVxdWlyZSgnbW9kdWxlJykuZ2xvYmFsUGF0aHMucHVzaChwYXRoLmpvaW4oYXBwLmdldFBhdGgoJ2hvbWUnKSwgJy5yYXRwYWNrL25vZGVfbW9kdWxlcycpKVxuICBcbn0pXG5cbmZ1bmN0aW9uIHRpbWVzKG4sIGZuKSB7XG4gIGxldCBhcnIgPSBbXVxuICBmb3IobGV0IGk9IDA7IGk8IG47IGkrKykge1xuICAgIGFyci5wdXNoKGZuKGkpKVxuICB9XG4gIHJldHVybiBhcnJcbn1cblxuY3NzLmdsb2JhbCgnaHRtbCwgYm9keSwgI3Jvb3QnLCB7IHBvc2l0aW9uOiAncmVsYXRpdmUnLCB3aWR0aDogJzEwMCUnLCBoZWlnaHQ6ICcxMDAlJywgZGlzcGxheTogJ2Jsb2NrJywgYmFja2dyb3VuZENvbG9yOiB5ZWxsb3cgfSlcblxuY29uc3QgTG9nbyA9ICgpID0+IDxkaXYgY3NzPXt7IHdpZHRoOiAxMDAsIGhlaWdodDogMTAwLCBwb3NpdGlvbjogJ2Fic29sdXRlJywgYm90dG9tOiAwLCByaWdodDogMCwgW3ByZXNldHMuUGhhYmxldF06IHsgd2lkdGg6IDIwMCwgaGVpZ2h0OiAyMDAgfSB9fT5cbiAgPHN2ZyB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCIgdmlld0JveD1cIjAgMCA2MzAgNjMwXCIgPlxuICAgIDxwYXRoIGQ9XCJtNDIzLjIgNDkyLjE5YzEyLjY5IDIwLjcyIDI5LjIgMzUuOTUgNTguNCAzNS45NSAyNC41MyAwIDQwLjItMTIuMjYgNDAuMi0yOS4yIDAtMjAuMy0xNi4xLTI3LjQ5LTQzLjEtMzkuM2wtMTQuOC02LjM1Yy00Mi43Mi0xOC4yLTcxLjEtNDEtNzEuMS04OS4yIDAtNDQuNCAzMy44My03OC4yIDg2LjctNzguMiAzNy42NCAwIDY0LjcgMTMuMSA4NC4yIDQ3LjRsLTQ2LjEgMjkuNmMtMTAuMTUtMTguMi0yMS4xLTI1LjM3LTM4LjEtMjUuMzctMTcuMzQgMC0yOC4zMyAxMS0yOC4zMyAyNS4zNyAwIDE3Ljc2IDExIDI0Ljk1IDM2LjQgMzUuOTVsMTQuOCA2LjM0YzUwLjMgMjEuNTcgNzguNyA0My41NiA3OC43IDkzIDAgNTMuMy00MS44NyA4Mi41LTk4LjEgODIuNS01NC45OCAwLTkwLjUtMjYuMi0xMDcuODgtNjAuNTR6bS0yMDkuMTMgNS4xM2M5LjMgMTYuNSAxNy43NiAzMC40NSAzOC4xIDMwLjQ1IDE5LjQ1IDAgMzEuNzItNy42MSAzMS43Mi0zNy4ydi0yMDEuM2g1OS4ydjIwMi4xYzAgNjEuMy0zNS45NCA4OS4yLTg4LjQgODkuMi00Ny40IDAtNzQuODUtMjQuNTMtODguODEtNTQuMDc1elwiIC8+XG4gIDwvc3ZnPlxuPC9kaXY+XG5cbmNsYXNzIEFwcCBleHRlbmRzIFJlYWN0LkNvbXBvbmVudCB7XG4gIHN0YXRlID0ge1xuICAgIHRpY2s6IDAsXG4gICAgZmlsZXBhdGg6IHVuZGVmaW5lZCxcbiAgICB3ZWJwYWNrQ29tcGlsZXI6IG51bGwsXG4gICAgd2VicGFja1NlcnZlcjogbnVsbCxcbiAgICByZWNlbnRseTogW10sXG4gICAgZXJyb3JzOiBbXSxcbiAgICBwb3J0OiAwLFxuICAgIHJ1bm5pbmc6IGZhbHNlXG4gIH1cbiAgb25PcGVuRmlsZSA9IChlLCBmaWxlcGF0aCkgPT4ge1xuICAgIHRoaXMubG9hZEZpbGUoZmlsZXBhdGgpXG4gIH1cbiAgcmVmcmVzaFJlY2VudExpc3QoY2IpIHtcbiAgICBkYi5maW5kKHsgX2lkOiAncmVjZW50bHknIH0sIChlcnIsIGRvY3MpID0+IHtcbiAgICAgIGlmKGVycikge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBlcnJvcnM6IFsgLi4udGhpcy5zdGF0ZS5lcnJvcnMsIGVyciBdXG4gICAgICAgIH0pXG4gICAgICAgIHJldHVybiBcbiAgICAgIH1cbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICByZWNlbnRseTogZG9jc1swXS5maWxlc1xuICAgICAgfSlcbiAgICAgIGlmKGNiKSBjYigpXG4gICAgfSlcbiAgfVxuICBjb21wb25lbnREaWRNb3VudCgpIHtcbiAgICBhcHAub24oJ29wZW4tZmlsZScsIHRoaXMub25PcGVuRmlsZSlcbiAgICB0aGlzLnJlZnJlc2hSZWNlbnRMaXN0KCgpID0+IHtcbiAgICAgIGlmKHdpbmRvdy5sb2NhdGlvbi5zZWFyY2gpIHtcbiAgICAgICAgbGV0IGZpbGVwYXRoID0gcXMucGFyc2Uod2luZG93LmxvY2F0aW9uLnNlYXJjaC5zbGljZSgxKSkuc3RhcnRzV2l0aFxuICAgICAgICBmaWxlcGF0aCAmJiB0aGlzLmxvYWRGaWxlKGZpbGVwYXRoKVxuICAgICAgfVxuICAgIH0pICAgXG4gICAgdGhpcy5pbnRlcnZhbCA9IHNldEludGVydmFsKCgpID0+IHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICB0aWNrOiAodGhpcy5zdGF0ZS50aWNrICsgMSkgJSA0IFxuICAgICAgfSkgICAgICBcbiAgICB9LCA0MDApXG4gXG4gIH1cbiAgY29tcG9uZW50V2lsbFVubW91bnQoKSB7XG4gICAgY2xlYXJJbnRlcnZhbCh0aGlzLmludGVydmFsKVxuICAgIHRoaXMuaW50ZXJ2YWwgPSBudWxsICAgIFxuXG4gICAgaWYodGhpcy5zdGF0ZS53ZWJwYWNrU2VydmVyKSB7XG4gICAgICB0aGlzLnN0YXRlLndlYnBhY2tTZXJ2ZXIuY2xvc2UoKSAgXG4gICAgfSAgIFxuICAgIGlmKHRoaXMud2F0Y2hlcikge1xuICAgICAgdGhpcy53YXRjaGVyLmNsb3NlKClcbiAgICAgIHRoaXMud2F0Y2hlciA9IG51bGxcbiAgICB9IFxuICAgIGFwcC5yZW1vdmVFdmVudExpc3RlbmVyKCdvcGVuLWZpbGUnLCB0aGlzLm9uT3BlbkZpbGUpXG4gIH1cbiAgX2xvYWRGaWxlKGZpbGVwYXRoKXtcbiAgICBmcy5yZWFkRmlsZShmaWxlcGF0aCwgJ3V0ZjgnLCAoZXJyLCBzcmMpID0+IHsgICAgICBcbiAgICAgIGlmKGVycikgdGhyb3cgZXJyXG4gICAgICBsZXQgb3B0aW9ucyA9IHByYWdtYXMoc3JjKVxuICAgICAgdGhpcy5zZXRTdGF0ZSh7IC4uLndlYnBhY2tpZnkoZmlsZXBhdGgsIG9wdGlvbnMpLCBmaWxlcGF0aCwgcnVubmluZzogdHJ1ZSwgcHJhZ21hczogb3B0aW9ucyB9KVxuXG4gICAgICAvLyBzaW11bHRhbmVvdXNseSBzdGFydCB3YXRjaGluZyB0aGUgZW50cnkgZmlsZSBcbiAgICAgIHRoaXMud2F0Y2hlciA9IGZzLndhdGNoKGZpbGVwYXRoLCBlID0+IHtcbiAgICAgICAgaWYoZSA9PT0gJ3JlbmFtZScpIHtcbiAgICAgICAgICAvLyA/Pz9cbiAgICAgICAgICByZXR1cm4gICAgICAgICAgXG4gICAgICAgIH0gICAgICAgIFxuICAgICAgICAvLyBpZiBhbnkgb2YgdGhlIHByYWdtYXMgY2hhbmdlLCByZWRvIHRoaXMgc2hpbmRpZyBcbiAgICAgICAgZnMucmVhZEZpbGUoZmlsZXBhdGgsICd1dGY4JywgKGVyciwgc3JjKSA9PiB7XG4gICAgICAgICAgbGV0IG9wdGlvbnMgPSBwcmFnbWFzKHNyYylcbiAgICAgICAgICBpZihKU09OLnN0cmluZ2lmeShvcHRpb25zKSAhPT0gSlNPTi5zdHJpbmdpZnkodGhpcy5zdGF0ZS5wcmFnbWFzKSkge1xuICAgICAgICAgICAgdGhpcy5sb2FkRmlsZShmaWxlcGF0aClcbiAgICAgICAgICB9XG4gICAgICAgICAgLy8gdG9kbyAtIHByZXZlbnQgZG91YmxlIHJlYWQgXG4gICAgICAgIH0pXG5cbiAgICAgIH0pXG4gICAgfSkgICAgXG4gIH1cbiAgbG9hZEZpbGUoZmlsZXBhdGgpIHtcblxuICAgIGRiLnVwZGF0ZSh7IF9pZDogJ3JlY2VudGx5JyB9LCB7IF9pZDogJ3JlY2VudGx5JywgZmlsZXM6IFsgeyBwYXRoOiBmaWxlcGF0aCB9LCAuLi50aGlzLnN0YXRlLnJlY2VudGx5LmZpbHRlcih4ID0+IHgucGF0aCAhPT0gZmlsZXBhdGgpIF0uc2xpY2UoMCwgMTApIH0sIHt9LCBlcnIgPT4ge1xuICAgICAgaWYoZXJyKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgIGVycm9yczogWyAuLi50aGlzLnN0YXRlLmVycm9ycywgZXJyIF1cbiAgICAgICAgfSlcbiAgICAgICAgcmV0dXJuICAgICAgICAgXG4gICAgICB9IFxuICAgICAgdGhpcy5yZWZyZXNoUmVjZW50TGlzdCgpICAgICAgICAgICBcbiAgICB9KVxuICAgIGlmKHRoaXMud2F0Y2hlcikge1xuICAgICAgdGhpcy53YXRjaGVyLmNsb3NlKClcbiAgICAgIHRoaXMud2F0Y2hlciA9IG51bGxcbiAgICB9XG4gICAgXG4gICAgaWYodGhpcy5zdGF0ZS53ZWJwYWNrU2VydmVyKSB7XG4gICAgICB0aGlzLnN0YXRlLndlYnBhY2tTZXJ2ZXIuY2xvc2UoKVxuICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIHRoaXMuX2xvYWRGaWxlKGZpbGVwYXRoKVxuICAgICAgfSwgNTAwKSAgICAgIFxuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgIHRoaXMuX2xvYWRGaWxlKGZpbGVwYXRoKVxuICAgIH1cbiAgICAgICAgICAgIFxuICB9XG4gIG9uRHJvcCA9IGUgPT4ge1xuICAgIGUucHJldmVudERlZmF1bHQoKVxuICAgIGUuc3RvcFByb3BhZ2F0aW9uKClcbiAgICBsZXQgZmlsZXBhdGggPSBlLm5hdGl2ZUV2ZW50LmRhdGFUcmFuc2Zlci5maWxlc1swXS5wYXRoXG4gICAgdGhpcy5sb2FkRmlsZShmaWxlcGF0aClcbiAgfVxuICBjbGVhclJlY2VudExpc3QoKSB7XG4gICAgZGIudXBkYXRlKHsgX2lkOiAncmVjZW50bHknIH0sIHsgX2lkOiAncmVjZW50bHknLCBmaWxlczogW10gfSwgKCkgPT4ge1xuICAgICAgdGhpcy5yZWZyZXNoUmVjZW50TGlzdCgpXG4gICAgfSlcbiAgfVxuICBcbiAgcmVuZGVyKCkge1xuICAgIHJldHVybiA8ZGl2IFxuICAgICAgY3NzPXt7IHdpZHRoOiAnMTAwJScsIGhlaWdodDogJzEwMCUnLCBmb250RmFtaWx5OiAnaGVsdmV0aWNhJyB9fSBcbiAgICAgIG9uRHJhZ092ZXI9e2UgPT4gZS5wcmV2ZW50RGVmYXVsdCgpfSAvLyBjaHJvbWUgYnVnIFxuICAgICAgb25Ecm9wPXt0aGlzLm9uRHJvcH0+ICAgICAgXG4gICAgICAgIFxuICAgICAgPGRpdiBjc3M9e3sgZm9udFdlaWdodDogJ2JvbGRlcicsIGZvbnRTaXplOiAzMiwgcGFkZGluZzogMjAsIFtwcmVzZXRzLlBoYWJsZXRdOiB7IGZvbnRTaXplOiA2NCB9IH19PlxuICAgICAgeyB0aGlzLnN0YXRlLnJ1bm5pbmcgPyBcbiAgICAgICAgYCR7cGF0aC5iYXNlbmFtZSh0aGlzLnN0YXRlLmZpbGVwYXRoKX0gcnVubmluZyBhdCBcbiAgICAgICAgbG9jYWxob3N0OiR7dGhpcy5zdGF0ZS5wb3J0fSR7dGltZXModGhpcy5zdGF0ZS50aWNrLCAoKSA9PiAnLicpLmpvaW4oJycpfWBcbiAgICAgICAgOiAnRHJvcCBhIC5qcyBmaWxlIGhlcmUgdG8gZ2V0IHN0YXJ0ZWQgJ31cbiAgICAgICAgXG4gICAgICBcbiAgICAgIDwvZGl2PiBcbiAgICAgIHsgdGhpcy5zdGF0ZS5yZWNlbnRseS5sZW5ndGggPiAwICYmIDxkaXYgY3NzPXt7IHBhZGRpbmc6IDIwIH19PlxuICAgICAgICA8aDE+cHJldmlvdXNseS4uLjwvaDE+XG4gICAgICAgIHt0aGlzLnN0YXRlLnJlY2VudGx5Lm1hcCh4ID0+IDxkaXYga2V5PXt4LnBhdGh9IG9uQ2xpY2s9eygpID0+IHRoaXMubG9hZEZpbGUoeC5wYXRoKX0+e3gucGF0aH08L2Rpdj4pfVxuICAgICAgICA8aDQgb25DbGljaz17KCkgPT4gdGhpcy5jbGVhclJlY2VudExpc3QoKX0+Y2xlYXIgbGlzdDwvaDQ+XG4gICAgICA8L2Rpdj59XG4gICAgICBcbiAgICAgIDxMb2dvLz5cbiAgICAgIFxuICAgIDwvZGl2PlxuICAgIFxuICB9XG59XG5cbmZ1bmN0aW9uIHdlYnBhY2tpZnkoZmlsZXBhdGgsIG9wdGlvbnMgPSB7fSkge1xuICBcbiAgbGV0IHdlYnBhY2tDb21waWxlciA9IHdlYnBhY2soe1xuICAgIGRldnRvb2w6IG9wdGlvbnMucHJvZHVjdGlvbiA/IGZhbHNlIDogKG9wdGlvbnMuZGV2dG9vbCB8fCAnY2hlYXAtbW9kdWxlLXNvdXJjZS1tYXAnKSxcbiAgICBlbnRyeTogWyBcbiAgICAgICgob3B0aW9ucy5yZWxvYWQgIT09IGZhbHNlKSB8fCAob3B0aW9ucy5wcm9kdWN0aW9uICE9PSB0cnVlKSApID8gXG4gICAgICAgIHJlcXVpcmUucmVzb2x2ZSgncmVhY3QtZGV2LXV0aWxzL3dlYnBhY2tIb3REZXZDbGllbnQuanMnKSA6IFxuICAgICAgICB1bmRlZmluZWQsIFxuICAgICAgb3B0aW9ucy5zdGF0cyA/IHJlcXVpcmUucmVzb2x2ZSgnLi9zdGF0cy5qcycpIDogdW5kZWZpbmVkLFxuICAgICAgcmVxdWlyZS5yZXNvbHZlKCcuL3BvbHlmaWxscycpLCBcbiAgICAgIG9wdGlvbnMub2ZmbGluZSA/IHJlcXVpcmUucmVzb2x2ZSgnLi9vZmZsaW5lLXBsdWdpbi1ydW50aW1lLmpzJykgOiB1bmRlZmluZWQsXG4gICAgICBmaWxlcGF0aCBcbiAgICBdLmZpbHRlcih4ID0+ICEheCksXG4gICAgb3V0cHV0OiB7XG4gICAgICBwYXRoOiBwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4vcHVibGljJyksXG4gICAgICBwYXRoaW5mbzogdHJ1ZSxcbiAgICAgIGZpbGVuYW1lOiAnYnVuZGxlLmpzJ1xuICAgIH0sXG4gICAgcGVyZm9ybWFuY2U6IHtcbiAgICAgIGhpbnRzOiBmYWxzZVxuICAgIH0sXG4gICAgbW9kdWxlOiB7XG4gICAgICBydWxlczogWyBcbiAgICAgICAgLi4uKG9wdGlvbnMucnVsZXMgfHwgW10pLm1hcCgoeyBsb2FkZXIsIGZpbGVzLCBvcHRpb25zIH0pID0+ICh7IGxvYWRlcjogcmVxdWlyZS5yZXNvbHZlKGxvYWRlciksIG9wdGlvbnMsIHRlc3Q6IGdsb2IycmVnZXhwKGZpbGVzIHx8ICcqJykgfSkpLCBcbiAgICAgICAge1xuICAgICAgICAgIGVuZm9yY2U6ICdwcmUnLFxuICAgICAgICAgIHRlc3Q6IC9cXC4oanN8anN4KSQvLFxuICAgICAgICAgIGxvYWRlcjogcmVxdWlyZS5yZXNvbHZlKCdlc2xpbnQtbG9hZGVyJyksXG4gICAgICAgICAgZXhjbHVkZTogL25vZGVfbW9kdWxlcy8sXG4gICAgICAgICAgb3B0aW9uczoge1xuICAgICAgICAgICAgY29uZmlnRmlsZTogcGF0aC5qb2luKF9fZGlybmFtZSwgJy4uL3Jlc291cmNlcy8uZXNsaW50cmMnKVxuICAgICAgICAgIH1cbiAgICAgICAgfSwgXG4gICAgICAgIHtcbiAgICAgICAgICBleGNsdWRlOiBbXG4gICAgICAgICAgICAvXFwuaHRtbCQvLFxuICAgICAgICAgICAgL1xcLihqc3xqc3gpJC8sXG4gICAgICAgICAgICAvXFwuY3NzJC8sXG4gICAgICAgICAgICAvXFwuanNvbiQvLFxuICAgICAgICAgICAgL1xcLnN2ZyQvXG4gICAgICAgICAgXSxcbiAgICAgICAgICBsb2FkZXI6IHJlcXVpcmUucmVzb2x2ZSgndXJsLWxvYWRlcicpLFxuICAgICAgICAgIHF1ZXJ5OiB7XG4gICAgICAgICAgICBsaW1pdDogMTAwMDAsXG4gICAgICAgICAgICBuYW1lOiAnc3RhdGljL21lZGlhL1tuYW1lXS5baGFzaDo4XS5bZXh0XSdcbiAgICAgICAgICB9XG4gICAgICAgIH0sIFxuICAgICAgICB7XG4gICAgICAgICAgdGVzdDogL1xcLmpzJC8sXG4gICAgICAgICAgZXhjbHVkZTogL25vZGVfbW9kdWxlcy8sXG4gICAgICAgICAgbG9hZGVyOiByZXF1aXJlLnJlc29sdmUoJ2JhYmVsLWxvYWRlcicpLFxuICAgICAgICAgIG9wdGlvbnM6IHtcbiAgICAgICAgICAgICdwcmVzZXRzJzogWyBcbiAgICAgICAgICAgICAgWyByZXF1aXJlKCdiYWJlbC1wcmVzZXQtZW52JyksIHsgXG4gICAgICAgICAgICAgICAgJ3RhcmdldHMnOiB7XG4gICAgICAgICAgICAgICAgICAnYnJvd3NlcnMnOiBbICdsYXN0IDIgdmVyc2lvbnMnLCAnc2FmYXJpID49IDcnIF1cbiAgICAgICAgICAgICAgICB9LCBcbiAgICAgICAgICAgICAgICBtb2R1bGVzOiBmYWxzZSBcbiAgICAgICAgICAgICAgfSBdLCBcbiAgICAgICAgICAgICAgcmVxdWlyZSgnYmFiZWwtcHJlc2V0LXN0YWdlLTAnKSwgXG4gICAgICAgICAgICAgIHJlcXVpcmUoJ2JhYmVsLXByZXNldC1yZWFjdCcpLCAgICAgICAgICAgICAgXG4gICAgICAgICAgICAgIC4uLihvcHRpb25zLmJhYmVsIHx8IHt9KS5wcmVzZXRzIHx8IFtdXG4gICAgICAgICAgICBdLFxuICAgICAgICAgICAgJ3BsdWdpbnMnOiBbXG4gICAgICAgICAgICAgIFsgcmVxdWlyZS5yZXNvbHZlKCdiYWJlbC1wbHVnaW4tdHJhbnNmb3JtLXJ1bnRpbWUnKSwge1xuICAgICAgICAgICAgICAgIGhlbHBlcnM6IGZhbHNlLFxuICAgICAgICAgICAgICAgIHBvbHlmaWxsOiBmYWxzZSxcbiAgICAgICAgICAgICAgICByZWdlbmVyYXRvcjogdHJ1ZVxuICAgICAgICAgICAgICAgIC8vIFJlc29sdmUgdGhlIEJhYmVsIHJ1bnRpbWUgcmVsYXRpdmUgdG8gdGhlIGNvbmZpZy5cbiAgICAgICAgICAgICAgICAvLyBtb2R1bGVOYW1lOiBwYXRoLmRpcm5hbWUocmVxdWlyZS5yZXNvbHZlKCdiYWJlbC1ydW50aW1lL3BhY2thZ2UnKSlcbiAgICAgICAgICAgICAgfSBdLFxuICAgICAgICAgICAgICBvcHRpb25zLmpzeCA/IFsgcmVxdWlyZSgnYmFiZWwtcGx1Z2luLXRyYW5zZm9ybS1yZWFjdC1qc3gnKSxcbiAgICAgICAgICAgICAgICB7ICdwcmFnbWEnOiBvcHRpb25zLmpzeCB9IF0gOiB1bmRlZmluZWQsXG4gICAgICAgICAgICAgIHJlcXVpcmUoJ2JhYmVsLXBsdWdpbi10cmFuc2Zvcm0tZGVjb3JhdG9ycy1sZWdhY3knKS5kZWZhdWx0LFxuICAgICAgICAgICAgICByZXF1aXJlKCdiYWJlbC1wbHVnaW4tdHJhbnNmb3JtLXJlYWN0LXJlcXVpcmUnKS5kZWZhdWx0LFxuICAgICAgICAgICAgICBcbiAgICAgICAgICAgICAgLi4uKG9wdGlvbnMuYmFiZWwgfHwge30pLnBsdWdpbnMgfHwgW11cbiAgICAgICAgICAgIF0uZmlsdGVyKHggPT4gISF4KSxcbiAgICAgICAgICAgIGNhY2hlRGlyZWN0b3J5OiBmYWxzZVxuICAgICAgICAgIH1cbiAgICAgICAgfSwgXG4gICAgICAgIHtcbiAgICAgICAgICB0ZXN0OiAvXFwuY3NzJC8sXG4gICAgICAgICAgdXNlOiBbXG4gICAgICAgICAgICByZXF1aXJlLnJlc29sdmUoJ3N0eWxlLWxvYWRlcicpLCBcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgbG9hZGVyOiByZXF1aXJlLnJlc29sdmUoJ2Nzcy1sb2FkZXInKSxcbiAgICAgICAgICAgICAgb3B0aW9uczogeyBpbXBvcnRMb2FkZXJzOiAxIH0gXG4gICAgICAgICAgICB9LCBcbiAgICAgICAgICAgIHJlcXVpcmUucmVzb2x2ZSgncG9zdGNzcy1sb2FkZXInKSAgLy8gb3B0aW9ucyBpbiB0aGUgcGx1Z2lucyBzZWN0aW9uIGJlbG93ICAgICAgICAgICAgIFxuICAgICAgICAgIF1cbiAgICAgICAgfSwgXG4gICAgICAgIC8vIHtcbiAgICAgICAgLy8gICB0ZXN0OiAvXFwuanNvbiQvLFxuICAgICAgICAvLyAgIGxvYWRlcjogcmVxdWlyZS5yZXNvbHZlKCdqc29uLWxvYWRlcicpXG4gICAgICAgIC8vIH0sXG4gICAgICAgICB7XG4gICAgICAgICAgdGVzdDogL1xcLnN2ZyQvLFxuICAgICAgICAgIGxvYWRlcjogcmVxdWlyZS5yZXNvbHZlKCdmaWxlLWxvYWRlcicpLFxuICAgICAgICAgIHF1ZXJ5OiB7XG4gICAgICAgICAgICBuYW1lOiAnc3RhdGljL21lZGlhL1tuYW1lXS5baGFzaDo4XS5bZXh0XSdcbiAgICAgICAgICB9XG4gICAgICAgIH0gXG4gICAgICBdXG4gICAgfSxcbiAgICByZXNvbHZlOiB7XG4gICAgICBhbGlhczogb3B0aW9ucy5hbGlhcyB8fCB7fSxcbiAgICAgIGV4dGVuc2lvbnM6IFsgJy5qcycsICcuanNvbicsICcuanN4JyBdLFxuICAgICAgbW9kdWxlczogWyAnbm9kZV9tb2R1bGVzJywgcGF0aC5qb2luKGFwcC5nZXRQYXRoKCdob21lJyksICcucmF0cGFjay9ub2RlX21vZHVsZXMnKSwgIHBhdGguam9pbihfX2Rpcm5hbWUsICcuLi9ub2RlX21vZHVsZXMnKSBdXG4gICAgfSxcbiAgICBwbHVnaW5zOiBbXG4gICAgICBuZXcgd2VicGFjay5EZWZpbmVQbHVnaW4oe1xuICAgICAgICAncHJvY2Vzcy5lbnYuTk9ERV9FTlYnOiBKU09OLnN0cmluZ2lmeSgob3B0aW9ucy5wcm9kdWN0aW9uICYmICdwcm9kdWN0aW9uJykgfHwgcHJvY2Vzcy5lbnYuTk9ERV9FTlYgfHwgJ2RldmVsb3BtZW50JyksXG4gICAgICAgIC4uLk9iamVjdC5rZXlzKG9wdGlvbnMuZGVmaW5lIHx8IHt9KS5yZWR1Y2UoKG8sIGtleSkgPT4gKHsgLi4ubywgW2tleV06IEpTT04uc3RyaW5naWZ5KG9wdGlvbnMuZGVmaW5lW2tleV0pIH0pLCB7fSlcbiAgICAgIH0pLFxuICAgICAgb3B0aW9ucy5vZmZsaW5lID8gbmV3IE9mZmxpbmVQbHVnaW4ob3B0aW9ucy5vZmZsaW5lID09PSB0cnVlID8ge30gOiBvcHRpb25zLm9mZmxpbmUpIDogdW5kZWZpbmVkLFxuICAgICAgbmV3IHdlYnBhY2suUHJvdmlkZVBsdWdpbihvcHRpb25zLnByb3ZpZGUgfHwge30pLFxuICAgICAgbmV3IHdlYnBhY2suTG9hZGVyT3B0aW9uc1BsdWdpbih7XG4gICAgICAgIHRlc3Q6IC9cXC5jc3MkLyxcbiAgICAgICAgZGVidWc6IHRydWUsXG4gICAgICAgIG9wdGlvbnM6IHtcbiAgICAgICAgICBwb3N0Y3NzOiBbXG4gICAgICAgICAgICBhdXRvcHJlZml4ZXIoe1xuICAgICAgICAgICAgICBicm93c2VyczogW1xuICAgICAgICAgICAgICAgICc+MSUnLFxuICAgICAgICAgICAgICAgICdsYXN0IDQgdmVyc2lvbnMnLFxuICAgICAgICAgICAgICAgICdGaXJlZm94IEVTUicsXG4gICAgICAgICAgICAgICAgJ25vdCBpZSA8IDknIC8vIFJlYWN0IGRvZXNuJ3Qgc3VwcG9ydCBJRTggYW55d2F5XG4gICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgXVxuICAgICAgICB9XG4gICAgICB9KVxuICAgIF0uZmlsdGVyKHggPT4gISF4KSxcbiAgICBzdGF0czogJ2Vycm9ycy1vbmx5JyxcbiAgICBub2RlOiB7XG4gICAgICBmczogJ2VtcHR5JyxcbiAgICAgIG5ldDogJ2VtcHR5JyxcbiAgICAgIHRsczogJ2VtcHR5J1xuICAgIH1cbiAgfSlcbiAgXG4gIGxldCB3ZWJwYWNrU2VydmVyID0gbmV3IFdlYnBhY2tEZXZTZXJ2ZXIod2VicGFja0NvbXBpbGVyLCB7XG4gICAgY29udGVudEJhc2U6IFsgb3B0aW9ucy5wdWJsaWMgPyBwYXRoLmpvaW4ocGF0aC5kaXJuYW1lKGZpbGVwYXRoKSwgb3B0aW9ucy5wdWJsaWMpIDogJycsIHBhdGguam9pbihwYXRoLmRpcm5hbWUoZmlsZXBhdGgpLCAncHVibGljJyksIHBhdGguam9pbihfX2Rpcm5hbWUsICcuLi9wdWJsaWMnKSBdLmZpbHRlcih4ID0+ICEheCksXG4gICAgaGlzdG9yeUFwaUZhbGxiYWNrOiB0cnVlLFxuICAgIGNvbXByZXNzOiB0cnVlLFxuICAgIHByb3h5OiBvcHRpb25zLnByb3h5IHx8IHt9LFxuICAgICAgICAvLyBzZXR1cCgpXG4gICAgICAgIC8vIHN0YXRpY09wdGlvbnMgXG5cbiAgICBxdWlldDogdHJ1ZSwgICAgICBcbiAgICBzdGF0czogeyBjb2xvcnM6IGZhbHNlIH0gIFxuICB9KVxuICAgIC8vIHRoaXMgaXMgdG8gd29ya2Fyb3VuZCBzb21lIHdlaXJkIGJ1ZyB3aGVyZSB3ZWJwYWNrIGtlZXBzIHRoZSBmaXJzdCBsb2FkZWQgZmlsZSBcbiAgICAvLyBhbHNvIG1ha2VzIGl0IGxvb2sgY29vbCBoYVxuICBsZXQgaCA9IGhhc2goZmlsZXBhdGgsIGZpbGVwYXRoLmxlbmd0aCkrICcnXG4gIGxldCBwb3J0ID0gb3B0aW9ucy5wb3J0IHx8ICgzMDAwICsgcGFyc2VJbnQoaC5zdWJzdHIoaC5sZW5ndGggLSA0KSwgMTApKVxuICB3ZWJwYWNrU2VydmVyLmxpc3Rlbihwb3J0KVxuICBvcGVuQnJvd3NlcignaHR0cDovL2xvY2FsaG9zdDonICsgcG9ydClcbiAgcmV0dXJuIHsgd2VicGFja1NlcnZlciwgd2VicGFja0NvbXBpbGVyLCBwb3J0IH1cblxufVxuIFxucmVuZGVyKDxBcHAvPiwgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3Jvb3QnKSlcbiJdfQ=="
  },
  {
    "path": "lib/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <title>ratpack</title>\n   \n</head>\n<body>\n  <div id='root'/>\n  <script>\n    require('./app')    \n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "lib/main.js",
    "content": "'use strict';\n\nvar _electron = require('electron');\n\nvar _path = require('path');\n\nvar _path2 = _interopRequireDefault(_path);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\n// import installExtension, { REACT_DEVELOPER_TOOLS } from 'electron-devtools-installer'\n\n// app: control application file.\n// BrowserWindow: create native browser window.\n\nvar isProd = _path2.default.basename(process.argv[0]).indexOf('ratpack') === 0;\n\nvar startsWith = require('minimist')(process.argv.slice(1))._[isProd ? 0 : 1];\nvar startedOnce = false;\nvar mainWindow = void 0;\n\n_electron.app.on('open-file', function (e, filepath) {\n  if (!mainWindow) {\n    startsWith = filepath;\n    if (!startedOnce) {\n      return;\n    }\n    createWindow();\n    return;\n  }\n});\n\n// Keep a global reference of the window object, if you don't, the window will\n// be closed automatically when the JavaScript object is garbage collected.\n\n\nfunction createWindow() {\n  // Create the browser window.\n  // installExtension(REACT_DEVELOPER_TOOLS)\n  //   .then((name) => console.log(`Added Extension:  ${name}`))\n  //   .catch((err) => console.log('An error occurred: ', err))\n\n  mainWindow = new _electron.BrowserWindow({ width: 800, height: 600, icon: _path2.default.join(__dirname, '../resources/icon.png'), backgroundColor: '#f7df1e', show: false });\n  mainWindow.once('ready-to-show', function () {\n    mainWindow.show();\n  });\n  startedOnce = true;\n  // and load the index.html of the app.\n  mainWindow.loadURL('file://' + __dirname + '/index.html' + (startsWith ? '?startsWith=' + encodeURIComponent(startsWith) : ''));\n  startsWith = undefined;\n  // Open the DevTools.\n  mainWindow.webContents.openDevTools();\n\n  // Emitted when the window is closed.\n  mainWindow.on('closed', function () {\n    // Dereference the window object, usually you would store windows\n    // in an array if your app supports multi windows, this is the time\n    // when you should delete the corresponding element.\n    mainWindow = null;\n  });\n}\n\n// This method will be called when Electron has finished\n// initialization and is ready to create browser windows.\n// Some APIs can only be used after this event occurs.\n_electron.app.on('ready', createWindow);\n\n// Quit when all windows are closed.\n_electron.app.on('window-all-closed', function () {\n  // On OS X it is common for applications and their menu bar\n  // to stay active until the user quits explicitly with Cmd + Q\n  if (process.platform !== 'darwin') {\n    _electron.app.quit();\n  }\n});\n\n_electron.app.on('activate', function () {\n  // On OS X it's common to re-create a window in the app when the\n  // dock icon is clicked and there are no other windows open.\n  if (mainWindow === null) {\n    createWindow();\n  }\n});\n\n// In this file you can include the rest of your app's specific main process\n// code. You can also put them in separate files and require them here.\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9tYWluLmpzIl0sIm5hbWVzIjpbImlzUHJvZCIsImJhc2VuYW1lIiwicHJvY2VzcyIsImFyZ3YiLCJpbmRleE9mIiwic3RhcnRzV2l0aCIsInJlcXVpcmUiLCJzbGljZSIsIl8iLCJzdGFydGVkT25jZSIsIm1haW5XaW5kb3ciLCJvbiIsImUiLCJmaWxlcGF0aCIsImNyZWF0ZVdpbmRvdyIsIndpZHRoIiwiaGVpZ2h0IiwiaWNvbiIsImpvaW4iLCJfX2Rpcm5hbWUiLCJiYWNrZ3JvdW5kQ29sb3IiLCJzaG93Iiwib25jZSIsImxvYWRVUkwiLCJlbmNvZGVVUklDb21wb25lbnQiLCJ1bmRlZmluZWQiLCJ3ZWJDb250ZW50cyIsIm9wZW5EZXZUb29scyIsInBsYXRmb3JtIiwicXVpdCJdLCJtYXBwaW5ncyI6Ijs7QUFLQTs7QUFDQTs7Ozs7O0FBTkE7O0FBRUE7QUFDQTs7QUFLQSxJQUFJQSxTQUFTLGVBQUtDLFFBQUwsQ0FBY0MsUUFBUUMsSUFBUixDQUFhLENBQWIsQ0FBZCxFQUErQkMsT0FBL0IsQ0FBdUMsU0FBdkMsTUFBc0QsQ0FBbkU7O0FBRUEsSUFBSUMsYUFBYUMsUUFBUSxVQUFSLEVBQW9CSixRQUFRQyxJQUFSLENBQWFJLEtBQWIsQ0FBbUIsQ0FBbkIsQ0FBcEIsRUFBMkNDLENBQTNDLENBQThDUixTQUFTLENBQVQsR0FBYSxDQUEzRCxDQUFqQjtBQUNBLElBQUlTLGNBQWMsS0FBbEI7QUFDQSxJQUFJQyxtQkFBSjs7QUFFQSxjQUFJQyxFQUFKLENBQU8sV0FBUCxFQUFvQixVQUFDQyxDQUFELEVBQUlDLFFBQUosRUFBaUI7QUFDbkMsTUFBRyxDQUFDSCxVQUFKLEVBQWlCO0FBQ2ZMLGlCQUFhUSxRQUFiO0FBQ0EsUUFBRyxDQUFDSixXQUFKLEVBQWlCO0FBQ2Y7QUFDRDtBQUNESztBQUNBO0FBQ0Q7QUFDRixDQVREOztBQVdBO0FBQ0E7OztBQUdBLFNBQVNBLFlBQVQsR0FBd0I7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7O0FBRUFKLGVBQWEsNEJBQWtCLEVBQUVLLE9BQU8sR0FBVCxFQUFjQyxRQUFRLEdBQXRCLEVBQTJCQyxNQUFNLGVBQUtDLElBQUwsQ0FBVUMsU0FBVixFQUFxQix1QkFBckIsQ0FBakMsRUFBZ0ZDLGlCQUFpQixTQUFqRyxFQUE0R0MsTUFBTSxLQUFsSCxFQUFsQixDQUFiO0FBQ0FYLGFBQVdZLElBQVgsQ0FBZ0IsZUFBaEIsRUFBaUMsWUFBTTtBQUNyQ1osZUFBV1csSUFBWDtBQUNELEdBRkQ7QUFHQVosZ0JBQWMsSUFBZDtBQUNBO0FBQ0FDLGFBQVdhLE9BQVgsYUFBNkJKLFNBQTdCLG9CQUFvRGQsOEJBQTRCbUIsbUJBQW1CbkIsVUFBbkIsQ0FBNUIsR0FBK0QsRUFBbkg7QUFDQUEsZUFBYW9CLFNBQWI7QUFDQTtBQUNBZixhQUFXZ0IsV0FBWCxDQUF1QkMsWUFBdkI7O0FBRUE7QUFDQWpCLGFBQVdDLEVBQVgsQ0FBYyxRQUFkLEVBQXdCLFlBQVk7QUFDbEM7QUFDQTtBQUNBO0FBQ0FELGlCQUFhLElBQWI7QUFDRCxHQUxEO0FBTUQ7O0FBRUQ7QUFDQTtBQUNBO0FBQ0EsY0FBSUMsRUFBSixDQUFPLE9BQVAsRUFBZ0JHLFlBQWhCOztBQUVBO0FBQ0EsY0FBSUgsRUFBSixDQUFPLG1CQUFQLEVBQTRCLFlBQVk7QUFDdEM7QUFDQTtBQUNBLE1BQUlULFFBQVEwQixRQUFSLEtBQXFCLFFBQXpCLEVBQW1DO0FBQ2pDLGtCQUFJQyxJQUFKO0FBQ0Q7QUFDRixDQU5EOztBQVNBLGNBQUlsQixFQUFKLENBQU8sVUFBUCxFQUFtQixZQUFZO0FBQzdCO0FBQ0E7QUFDQSxNQUFJRCxlQUFlLElBQW5CLEVBQXlCO0FBQ3ZCSTtBQUNEO0FBQ0YsQ0FORDs7QUFRQTtBQUNBIiwiZmlsZSI6Im1haW4uanMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBpbXBvcnQgaW5zdGFsbEV4dGVuc2lvbiwgeyBSRUFDVF9ERVZFTE9QRVJfVE9PTFMgfSBmcm9tICdlbGVjdHJvbi1kZXZ0b29scy1pbnN0YWxsZXInXG5cbi8vIGFwcDogY29udHJvbCBhcHBsaWNhdGlvbiBmaWxlLlxuLy8gQnJvd3NlcldpbmRvdzogY3JlYXRlIG5hdGl2ZSBicm93c2VyIHdpbmRvdy5cblxuaW1wb3J0IHsgYXBwLCBCcm93c2VyV2luZG93IH0gIGZyb20gJ2VsZWN0cm9uJ1xuaW1wb3J0IHBhdGggZnJvbSAncGF0aCdcblxubGV0IGlzUHJvZCA9IHBhdGguYmFzZW5hbWUocHJvY2Vzcy5hcmd2WzBdKS5pbmRleE9mKCdyYXRwYWNrJykgPT09IDBcblxubGV0IHN0YXJ0c1dpdGggPSByZXF1aXJlKCdtaW5pbWlzdCcpKHByb2Nlc3MuYXJndi5zbGljZSgxKSkuX1sgaXNQcm9kID8gMCA6IDFdXG5sZXQgc3RhcnRlZE9uY2UgPSBmYWxzZVxubGV0IG1haW5XaW5kb3dcblxuYXBwLm9uKCdvcGVuLWZpbGUnLCAoZSwgZmlsZXBhdGgpID0+IHtcbiAgaWYoIW1haW5XaW5kb3cgKSB7XG4gICAgc3RhcnRzV2l0aCA9IGZpbGVwYXRoXG4gICAgaWYoIXN0YXJ0ZWRPbmNlKSB7ICAgICAgXG4gICAgICByZXR1cm5cbiAgICB9ICAgIFxuICAgIGNyZWF0ZVdpbmRvdygpICAgIFxuICAgIHJldHVybiBcbiAgfSAgICBcbn0pXG4gXG4vLyBLZWVwIGEgZ2xvYmFsIHJlZmVyZW5jZSBvZiB0aGUgd2luZG93IG9iamVjdCwgaWYgeW91IGRvbid0LCB0aGUgd2luZG93IHdpbGxcbi8vIGJlIGNsb3NlZCBhdXRvbWF0aWNhbGx5IHdoZW4gdGhlIEphdmFTY3JpcHQgb2JqZWN0IGlzIGdhcmJhZ2UgY29sbGVjdGVkLlxuXG5cbmZ1bmN0aW9uIGNyZWF0ZVdpbmRvdygpIHtcbiAgLy8gQ3JlYXRlIHRoZSBicm93c2VyIHdpbmRvdy5cbiAgLy8gaW5zdGFsbEV4dGVuc2lvbihSRUFDVF9ERVZFTE9QRVJfVE9PTFMpXG4gIC8vICAgLnRoZW4oKG5hbWUpID0+IGNvbnNvbGUubG9nKGBBZGRlZCBFeHRlbnNpb246ICAke25hbWV9YCkpXG4gIC8vICAgLmNhdGNoKChlcnIpID0+IGNvbnNvbGUubG9nKCdBbiBlcnJvciBvY2N1cnJlZDogJywgZXJyKSlcblxuICBtYWluV2luZG93ID0gbmV3IEJyb3dzZXJXaW5kb3coeyB3aWR0aDogODAwLCBoZWlnaHQ6IDYwMCwgaWNvbjogcGF0aC5qb2luKF9fZGlybmFtZSwgJy4uL3Jlc291cmNlcy9pY29uLnBuZycpLCBiYWNrZ3JvdW5kQ29sb3I6ICcjZjdkZjFlJywgc2hvdzogZmFsc2UgfSlcbiAgbWFpbldpbmRvdy5vbmNlKCdyZWFkeS10by1zaG93JywgKCkgPT4ge1xuICAgIG1haW5XaW5kb3cuc2hvdygpXG4gIH0pXG4gIHN0YXJ0ZWRPbmNlID0gdHJ1ZVxuICAvLyBhbmQgbG9hZCB0aGUgaW5kZXguaHRtbCBvZiB0aGUgYXBwLlxuICBtYWluV2luZG93LmxvYWRVUkwoYGZpbGU6Ly8ke19fZGlybmFtZX0vaW5kZXguaHRtbCR7c3RhcnRzV2l0aCA/IGA/c3RhcnRzV2l0aD0ke2VuY29kZVVSSUNvbXBvbmVudChzdGFydHNXaXRoKX1gIDogJyd9YCApXG4gIHN0YXJ0c1dpdGggPSB1bmRlZmluZWRcbiAgLy8gT3BlbiB0aGUgRGV2VG9vbHMuXG4gIG1haW5XaW5kb3cud2ViQ29udGVudHMub3BlbkRldlRvb2xzKClcblxuICAvLyBFbWl0dGVkIHdoZW4gdGhlIHdpbmRvdyBpcyBjbG9zZWQuXG4gIG1haW5XaW5kb3cub24oJ2Nsb3NlZCcsIGZ1bmN0aW9uICgpIHtcbiAgICAvLyBEZXJlZmVyZW5jZSB0aGUgd2luZG93IG9iamVjdCwgdXN1YWxseSB5b3Ugd291bGQgc3RvcmUgd2luZG93c1xuICAgIC8vIGluIGFuIGFycmF5IGlmIHlvdXIgYXBwIHN1cHBvcnRzIG11bHRpIHdpbmRvd3MsIHRoaXMgaXMgdGhlIHRpbWVcbiAgICAvLyB3aGVuIHlvdSBzaG91bGQgZGVsZXRlIHRoZSBjb3JyZXNwb25kaW5nIGVsZW1lbnQuXG4gICAgbWFpbldpbmRvdyA9IG51bGxcbiAgfSlcbn1cblxuLy8gVGhpcyBtZXRob2Qgd2lsbCBiZSBjYWxsZWQgd2hlbiBFbGVjdHJvbiBoYXMgZmluaXNoZWRcbi8vIGluaXRpYWxpemF0aW9uIGFuZCBpcyByZWFkeSB0byBjcmVhdGUgYnJvd3NlciB3aW5kb3dzLlxuLy8gU29tZSBBUElzIGNhbiBvbmx5IGJlIHVzZWQgYWZ0ZXIgdGhpcyBldmVudCBvY2N1cnMuXG5hcHAub24oJ3JlYWR5JywgY3JlYXRlV2luZG93KVxuXG4vLyBRdWl0IHdoZW4gYWxsIHdpbmRvd3MgYXJlIGNsb3NlZC5cbmFwcC5vbignd2luZG93LWFsbC1jbG9zZWQnLCBmdW5jdGlvbiAoKSB7XG4gIC8vIE9uIE9TIFggaXQgaXMgY29tbW9uIGZvciBhcHBsaWNhdGlvbnMgYW5kIHRoZWlyIG1lbnUgYmFyXG4gIC8vIHRvIHN0YXkgYWN0aXZlIHVudGlsIHRoZSB1c2VyIHF1aXRzIGV4cGxpY2l0bHkgd2l0aCBDbWQgKyBRXG4gIGlmIChwcm9jZXNzLnBsYXRmb3JtICE9PSAnZGFyd2luJykge1xuICAgIGFwcC5xdWl0KClcbiAgfVxufSlcblxuXG5hcHAub24oJ2FjdGl2YXRlJywgZnVuY3Rpb24gKCkge1xuICAvLyBPbiBPUyBYIGl0J3MgY29tbW9uIHRvIHJlLWNyZWF0ZSBhIHdpbmRvdyBpbiB0aGUgYXBwIHdoZW4gdGhlXG4gIC8vIGRvY2sgaWNvbiBpcyBjbGlja2VkIGFuZCB0aGVyZSBhcmUgbm8gb3RoZXIgd2luZG93cyBvcGVuLlxuICBpZiAobWFpbldpbmRvdyA9PT0gbnVsbCkge1xuICAgIGNyZWF0ZVdpbmRvdygpXG4gIH1cbn0pXG5cbi8vIEluIHRoaXMgZmlsZSB5b3UgY2FuIGluY2x1ZGUgdGhlIHJlc3Qgb2YgeW91ciBhcHAncyBzcGVjaWZpYyBtYWluIHByb2Nlc3Ncbi8vIGNvZGUuIFlvdSBjYW4gYWxzbyBwdXQgdGhlbSBpbiBzZXBhcmF0ZSBmaWxlcyBhbmQgcmVxdWlyZSB0aGVtIGhlcmUuXG4iXX0="
  },
  {
    "path": "lib/offline-plugin-runtime.js",
    "content": "'use strict';\n\nrequire('offline-plugin/runtime').install();\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9vZmZsaW5lLXBsdWdpbi1ydW50aW1lLmpzIl0sIm5hbWVzIjpbInJlcXVpcmUiLCJpbnN0YWxsIl0sIm1hcHBpbmdzIjoiOztBQUFBQSxRQUFRLHdCQUFSLEVBQWtDQyxPQUFsQyIsImZpbGUiOiJvZmZsaW5lLXBsdWdpbi1ydW50aW1lLmpzIiwic291cmNlc0NvbnRlbnQiOlsicmVxdWlyZSgnb2ZmbGluZS1wbHVnaW4vcnVudGltZScpLmluc3RhbGwoKVxuIl19"
  },
  {
    "path": "lib/polyfills.js",
    "content": "'use strict';\n\n// @remove-on-eject-begin\n/**\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n// @remove-on-eject-end\n\nif (typeof Promise === 'undefined') {\n  // Rejection tracking prevents a common issue where React gets into an\n  // inconsistent state due to an error, but it gets swallowed by a Promise,\n  // and the user has no idea what causes React's erratic future behavior.\n  require('promise/lib/rejection-tracking').enable();\n  window.Promise = require('promise/lib/es6-extensions.js');\n}\n\n// fetch() polyfill for making API calls.\nrequire('whatwg-fetch');\n\n// Object.assign() is commonly used with React.\n// It will use the native implementation if it's present and isn't buggy.\nObject.assign = require('object-assign');\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9wb2x5ZmlsbHMuanMiXSwibmFtZXMiOlsiUHJvbWlzZSIsInJlcXVpcmUiLCJlbmFibGUiLCJ3aW5kb3ciLCJPYmplY3QiLCJhc3NpZ24iXSwibWFwcGluZ3MiOiI7O0FBQUE7QUFDQTs7Ozs7Ozs7QUFRQTs7QUFFQSxJQUFJLE9BQU9BLE9BQVAsS0FBbUIsV0FBdkIsRUFBb0M7QUFDbEM7QUFDQTtBQUNBO0FBQ0FDLFVBQVEsZ0NBQVIsRUFBMENDLE1BQTFDO0FBQ0FDLFNBQU9ILE9BQVAsR0FBaUJDLFFBQVEsK0JBQVIsQ0FBakI7QUFDRDs7QUFFRDtBQUNBQSxRQUFRLGNBQVI7O0FBRUE7QUFDQTtBQUNBRyxPQUFPQyxNQUFQLEdBQWdCSixRQUFRLGVBQVIsQ0FBaEIiLCJmaWxlIjoicG9seWZpbGxzLmpzIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHJlbW92ZS1vbi1lamVjdC1iZWdpblxuLyoqXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTUtcHJlc2VudCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICovXG4vLyBAcmVtb3ZlLW9uLWVqZWN0LWVuZFxuXG5pZiAodHlwZW9mIFByb21pc2UgPT09ICd1bmRlZmluZWQnKSB7XG4gIC8vIFJlamVjdGlvbiB0cmFja2luZyBwcmV2ZW50cyBhIGNvbW1vbiBpc3N1ZSB3aGVyZSBSZWFjdCBnZXRzIGludG8gYW5cbiAgLy8gaW5jb25zaXN0ZW50IHN0YXRlIGR1ZSB0byBhbiBlcnJvciwgYnV0IGl0IGdldHMgc3dhbGxvd2VkIGJ5IGEgUHJvbWlzZSxcbiAgLy8gYW5kIHRoZSB1c2VyIGhhcyBubyBpZGVhIHdoYXQgY2F1c2VzIFJlYWN0J3MgZXJyYXRpYyBmdXR1cmUgYmVoYXZpb3IuXG4gIHJlcXVpcmUoJ3Byb21pc2UvbGliL3JlamVjdGlvbi10cmFja2luZycpLmVuYWJsZSgpXG4gIHdpbmRvdy5Qcm9taXNlID0gcmVxdWlyZSgncHJvbWlzZS9saWIvZXM2LWV4dGVuc2lvbnMuanMnKVxufVxuXG4vLyBmZXRjaCgpIHBvbHlmaWxsIGZvciBtYWtpbmcgQVBJIGNhbGxzLlxucmVxdWlyZSgnd2hhdHdnLWZldGNoJylcblxuLy8gT2JqZWN0LmFzc2lnbigpIGlzIGNvbW1vbmx5IHVzZWQgd2l0aCBSZWFjdC5cbi8vIEl0IHdpbGwgdXNlIHRoZSBuYXRpdmUgaW1wbGVtZW50YXRpb24gaWYgaXQncyBwcmVzZW50IGFuZCBpc24ndCBidWdneS5cbk9iamVjdC5hc3NpZ24gPSByZXF1aXJlKCdvYmplY3QtYXNzaWduJylcbiJdfQ=="
  },
  {
    "path": "lib/pragmas.js",
    "content": "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n  value: true\n});\nexports.default = parse;\n\nvar _babylon = require('babylon');\n\nvar babylon = _interopRequireWildcard(_babylon);\n\nvar _json = require('json5');\n\nvar _json2 = _interopRequireDefault(_json);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nfunction _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }\n\nfunction parse(src) {\n  var ast = babylon.parse(src, { plugins: ['*'], sourceType: 'module' });\n\n  var config = ast.tokens.filter(function (x) {\n    return ['CommentLine', 'CommentBlock'].indexOf(x.type) >= 0;\n  }).map(function (x) {\n    return x.value;\n  }).filter(function (x) {\n    return (/^\\s*@ratpack/gim.test(x)\n    );\n  });\n\n  if (config.length > 1) {\n    throw new Error('cannot have multiple ratpack configs in one file');\n  }\n  config = config[0];\n\n  if (!config) return;\n\n  config = _json2.default.parse(config.substr(config.indexOf('@ratpack') + 8));\n\n  Object.keys(config).forEach(function (key) {\n    var value = config[key];\n    switch (key) {\n      case 'devtool':\n        {\n          var possibles = ['eval', 'cheap-eval-source-map', 'cheap-source-map', 'cheap-module-eval-source-map', 'cheap-module-source-map', 'eval-source-map', 'source-map', 'nosources-source-map'];\n          if (!(possibles.indexOf(value) >= 0)) {\n            throw new Error('@devtool ' + value + ' needs to be one of ' + possibles.join(', '));\n          }\n          break;\n        }\n\n      case 'target':\n        {\n          var _possibles = ['async-node', 'electron', 'electron-renderer', 'node', 'node-webkit', 'web', 'webworker'];\n          if (!(_possibles.indexOf(value) >= 0)) {\n            throw new Error('@target ' + value + ' needs to be one of ' + _possibles.join(', '));\n          }\n          console.warn('target doesn\\'t work yet'); //eslint-disable-line no-console\n          break;\n        }\n\n      case 'public':\n        break; // todo - test if valid dir \n\n      case 'jsx':\n        {\n          if (typeof value !== 'string') {\n            throw new Error('jsx pragma needs to be a valid string');\n          }\n          break;\n        } // test if string\n\n      case 'offline': // vvv      \n      case 'autoinstall':\n        {\n          if (value !== true && value !== false) {\n            throw new Error('@' + key + ' ' + value + ' needs to be true or false');\n          }\n          console.warn(key + ' doesn\\'t work yet'); //eslint-disable-line no-console\n          break;\n        }\n      case 'stats':\n      case 'reload':\n        {\n          if (value !== true && value !== false) {\n            throw new Error('@' + key + ' ' + value + ' needs to be true or false');\n          }\n          break;\n        }\n      case 'port':\n        {\n          if (!(value >= 0)) {\n            throw new Error('port ' + value + ' needs to be a valid number');\n          }\n          break;\n        }\n      case 'proxy':\n        break; // vvv    // test shape\n      case 'provide':\n        break; // vvv  // test shape \n      case 'alias':\n        break; // vvv    // test shape\n      case 'define':\n        break; // test shape\n      case 'rules':\n        break; // test shape\n\n      case 'plugins':\n        {\n          console.warn('plugins don\\'t work yet'); //eslint-disable-line no-console\n          break;\n        }\n      case 'babel':\n        {\n          // test shape    \n          break;\n        }\n      default:\n        console.warn('not implemented', key, value); //eslint-disable-line no-console\n    }\n  });\n  return config;\n}\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9wcmFnbWFzLmpzIl0sIm5hbWVzIjpbInBhcnNlIiwiYmFieWxvbiIsInNyYyIsImFzdCIsInBsdWdpbnMiLCJzb3VyY2VUeXBlIiwiY29uZmlnIiwidG9rZW5zIiwiZmlsdGVyIiwiaW5kZXhPZiIsIngiLCJ0eXBlIiwibWFwIiwidmFsdWUiLCJ0ZXN0IiwibGVuZ3RoIiwiRXJyb3IiLCJzdWJzdHIiLCJPYmplY3QiLCJrZXlzIiwiZm9yRWFjaCIsImtleSIsInBvc3NpYmxlcyIsImpvaW4iLCJjb25zb2xlIiwid2FybiJdLCJtYXBwaW5ncyI6Ijs7Ozs7a0JBR3dCQSxLOztBQUh4Qjs7SUFBWUMsTzs7QUFDWjs7Ozs7Ozs7QUFFZSxTQUFTRCxLQUFULENBQWVFLEdBQWYsRUFBb0I7QUFDakMsTUFBSUMsTUFBTUYsUUFBUUQsS0FBUixDQUFjRSxHQUFkLEVBQW1CLEVBQUVFLFNBQVMsQ0FBRSxHQUFGLENBQVgsRUFBb0JDLFlBQVksUUFBaEMsRUFBbkIsQ0FBVjs7QUFFQSxNQUFJQyxTQUFTSCxJQUFJSSxNQUFKLENBQ1ZDLE1BRFUsQ0FDSDtBQUFBLFdBQUssQ0FBRSxhQUFGLEVBQWlCLGNBQWpCLEVBQWtDQyxPQUFsQyxDQUEwQ0MsRUFBRUMsSUFBNUMsS0FBb0QsQ0FBekQ7QUFBQSxHQURHLEVBRVZDLEdBRlUsQ0FFTjtBQUFBLFdBQUtGLEVBQUVHLEtBQVA7QUFBQSxHQUZNLEVBR1ZMLE1BSFUsQ0FHSDtBQUFBLFdBQUssbUJBQWtCTSxJQUFsQixDQUF1QkosQ0FBdkI7QUFBTDtBQUFBLEdBSEcsQ0FBYjs7QUFLQSxNQUFHSixPQUFPUyxNQUFQLEdBQWdCLENBQW5CLEVBQXNCO0FBQUUsVUFBTSxJQUFJQyxLQUFKLENBQVUsa0RBQVYsQ0FBTjtBQUFxRTtBQUM3RlYsV0FBU0EsT0FBTyxDQUFQLENBQVQ7O0FBRUEsTUFBRyxDQUFDQSxNQUFKLEVBQVk7O0FBRVpBLFdBQVMsZUFBTU4sS0FBTixDQUFZTSxPQUFPVyxNQUFQLENBQWNYLE9B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ZSI6InByYWdtYXMuanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBiYWJ5bG9uIGZyb20gJ2JhYnlsb24nXG5pbXBvcnQganNvbjUgZnJvbSAnanNvbjUnXG5cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHBhcnNlKHNyYykge1xuICBsZXQgYXN0ID0gYmFieWxvbi5wYXJzZShzcmMsIHsgcGx1Z2luczogWyAnKicgXSwgc291cmNlVHlwZTogJ21vZHVsZScgfSlcblxuICBsZXQgY29uZmlnID0gYXN0LnRva2Vuc1xuICAgIC5maWx0ZXIoeCA9PiBbICdDb21tZW50TGluZScsICdDb21tZW50QmxvY2snIF0uaW5kZXhPZih4LnR5cGUpID49MClcbiAgICAubWFwKHggPT4geC52YWx1ZSlcbiAgICAuZmlsdGVyKHggPT4gL15cXHMqQHJhdHBhY2svZ2ltLnRlc3QoeCkpXG5cbiAgaWYoY29uZmlnLmxlbmd0aCA+IDEpIHsgdGhyb3cgbmV3IEVycm9yKCdjYW5ub3QgaGF2ZSBtdWx0aXBsZSByYXRwYWNrIGNvbmZpZ3MgaW4gb25lIGZpbGUnKSB9XG4gIGNvbmZpZyA9IGNvbmZpZ1swXVxuXG4gIGlmKCFjb25maWcpIHJldHVyblxuXG4gIGNvbmZpZyA9IGpzb241LnBhcnNlKGNvbmZpZy5zdWJzdHIoY29uZmlnLmluZGV4T2YoJ0ByYXRwYWNrJykgKyA4KSlcblxuXG4gIE9iamVjdC5rZXlzKGNvbmZpZykuZm9yRWFjaChrZXkgPT4ge1xuICAgIGxldCB2YWx1ZSA9IGNvbmZpZ1trZXldXG4gICAgc3dpdGNoKGtleSkge1xuICAgICAgY2FzZSAnZGV2dG9vbCc6IHtcbiAgICAgICAgbGV0IHBvc3NpYmxlcyA9IFsgJ2V2YWwnLCAnY2hlYXAtZXZhbC1zb3VyY2UtbWFwJywgJ2NoZWFwLXNvdXJjZS1tYXAnLCAnY2hlYXAtbW9kdWxlLWV2YWwtc291cmNlLW1hcCcsXG4gICAgICAgICAgJ2NoZWFwLW1vZHVsZS1zb3VyY2UtbWFwJywgJ2V2YWwtc291cmNlLW1hcCcsICdzb3VyY2UtbWFwJywgJ25vc291cmNlcy1zb3VyY2UtbWFwJyBdXG4gICAgICAgIGlmKCEocG9zc2libGVzLmluZGV4T2YodmFsdWUpID49IDApKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBAZGV2dG9vbCAke3ZhbHVlfSBuZWVkcyB0byBiZSBvbmUgb2YgYCArIHBvc3NpYmxlcy5qb2luKCcsICcpKVxuICAgICAgICB9XG4gICAgICAgIGJyZWFrXG4gICAgICB9XG5cbiAgICAgIGNhc2UgJ3RhcmdldCc6IHtcbiAgICAgICAgbGV0IHBvc3NpYmxlcyA9IFsgJ2FzeW5jLW5vZGUnLCAnZWxlY3Ryb24nLCAnZWxlY3Ryb24tcmVuZGVyZXInLCAnbm9kZScsICdub2RlLXdlYmtpdCcsICd3ZWInLCAnd2Vid29ya2VyJyBdIFxuICAgICAgICBpZighKHBvc3NpYmxlcy5pbmRleE9mKHZhbHVlKSA+PSAwKSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgQHRhcmdldCAke3ZhbHVlfSBuZWVkcyB0byBiZSBvbmUgb2YgYCArIHBvc3NpYmxlcy5qb2luKCcsICcpKVxuICAgICAgICB9XG4gICAgICAgIGNvbnNvbGUud2FybigndGFyZ2V0IGRvZXNuXFwndCB3b3JrIHlldCcpIC8vZXNsaW50LWRpc2FibGUtbGluZSBuby1jb25zb2xlXG4gICAgICAgIGJyZWFrXG4gICAgICB9XG5cbiAgICAgIGNhc2UgJ3B1YmxpYyc6IGJyZWFrIC8vIHRvZG8gLSB0ZXN0IGlmIHZhbGlkIGRpciBcbiAgICAgIFxuICAgICAgY2FzZSAnanN4Jzoge1xuICAgICAgICBpZih0eXBlb2YgdmFsdWUgIT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdqc3ggcHJhZ21hIG5lZWRzIHRvIGJlIGEgdmFsaWQgc3RyaW5nJylcbiAgICAgICAgfVxuICAgICAgICBicmVhayBcbiAgICAgIH0vLyB0ZXN0IGlmIHN0cmluZ1xuICAgICAgXG4gICAgICBjYXNlICdvZmZsaW5lJzogLy8gdnZ2ICAgICAgXG4gICAgICBjYXNlICdhdXRvaW5zdGFsbCc6IHsgICAgICAgIFxuICAgICAgICBpZigodmFsdWUgIT09IHRydWUpICYmICh2YWx1ZSAhPT0gZmFsc2UpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBAJHtrZXl9ICR7dmFsdWV9IG5lZWRzIHRvIGJlIHRydWUgb3IgZmFsc2VgKVxuICAgICAgICB9XG4gICAgICAgIGNvbnNvbGUud2FybihgJHtrZXl9IGRvZXNuJ3Qgd29yayB5ZXRgKSAvL2VzbGludC1kaXNhYmxlLWxpbmUgbm8tY29uc29sZVxuICAgICAgICBicmVha1xuICAgICAgfSBcbiAgICAgIGNhc2UgJ3N0YXRzJzogXG4gICAgICBjYXNlICdyZWxvYWQnOiB7XG4gICAgICAgIGlmKCh2YWx1ZSAhPT0gdHJ1ZSkgJiYgKHZhbHVlICE9PSBmYWxzZSkpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEAke2tleX0gJHt2YWx1ZX0gbmVlZHMgdG8gYmUgdHJ1ZSBvciBmYWxzZWApXG4gICAgICAgIH1cbiAgICAgICAgYnJlYWsgXG4gICAgICB9XG4gICAgICBjYXNlICdwb3J0Jzoge1xuICAgICAgICBpZighKHZhbHVlID49IDApKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBwb3J0ICR7dmFsdWV9IG5lZWRzIHRvIGJlIGEgdmFsaWQgbnVtYmVyYClcbiAgICAgICAgfVxuICAgICAgICBicmVha1xuICAgICAgfVxuICAgICAgY2FzZSAncHJveHknOiBicmVhayAvLyB2dnYgICAgLy8gdGVzdCBzaGFwZVxuICAgICAgY2FzZSAncHJvdmlkZSc6IGJyZWFrIC8vIHZ2diAgLy8gdGVzdCBzaGFwZSBcbiAgICAgIGNhc2UgJ2FsaWFzJzogYnJlYWsgLy8gdnZ2ICAgIC8vIHRlc3Qgc2hhcGVcbiAgICAgIGNhc2UgJ2RlZmluZSc6IGJyZWFrICAgICAgICAgIC8vIHRlc3Qgc2hhcGVcbiAgICAgIGNhc2UgJ3J1bGVzJzogYnJlYWsgICAgICAgICAgIC8vIHRlc3Qgc2hhcGVcbiAgICAgIFxuICAgICAgY2FzZSAncGx1Z2lucyc6IHsgICAgICAgIFxuICAgICAgICBjb25zb2xlLndhcm4oJ3BsdWdpbnMgZG9uXFwndCB3b3JrIHlldCcpIC8vZXNsaW50LWRpc2FibGUtbGluZSBuby1jb25zb2xlXG4gICAgICAgIGJyZWFrXG4gICAgICB9XG4gICAgICBjYXNlICdiYWJlbCc6IHsgICAgIC8vIHRlc3Qgc2hhcGUgICAgXG4gICAgICAgIGJyZWFrXG4gICAgICB9ICAgICAgXG4gICAgICBkZWZhdWx0OiBjb25zb2xlLndhcm4oJ25vdCBpbXBsZW1lbnRlZCcsIGtleSwgdmFsdWUpICAvL2VzbGludC1kaXNhYmxlLWxpbmUgbm8tY29uc29sZVxuICAgIH1cbiAgfSlcbiAgcmV0dXJuIGNvbmZpZ1xufVxuXG4iXX0="
  },
  {
    "path": "lib/stats.js",
    "content": "'use strict';\n\nvar _stats = require('stats.js');\n\nvar _stats2 = _interopRequireDefault(_stats);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nvar stats = new _stats2.default();\ndocument.body.appendChild(stats.dom);\n\nrequestAnimationFrame(function loop() {\n  stats.update();\n  requestAnimationFrame(loop);\n});\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9zdGF0cy5qcyJdLCJuYW1lcyI6WyJzdGF0cyIsImRvY3VtZW50IiwiYm9keSIsImFwcGVuZENoaWxkIiwiZG9tIiwicmVxdWVzdEFuaW1hdGlvbkZyYW1lIiwibG9vcCIsInVwZGF0ZSJdLCJtYXBwaW5ncyI6Ijs7QUFBQTs7Ozs7O0FBQ0EsSUFBSUEsUUFBUSxxQkFBWjtBQUNBQyxTQUFTQyxJQUFULENBQWNDLFdBQWQsQ0FBMEJILE1BQU1JLEdBQWhDOztBQUVBQyxzQkFBc0IsU0FBU0MsSUFBVCxHQUFlO0FBQ25DTixRQUFNTyxNQUFOO0FBQ0FGLHdCQUFzQkMsSUFBdEI7QUFDRCxDQUhEIiwiZmlsZSI6InN0YXRzLmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IFN0YXRzIGZyb20gJ3N0YXRzLmpzJ1xubGV0IHN0YXRzID0gbmV3IFN0YXRzKClcbmRvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQoc3RhdHMuZG9tKVxuXG5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoZnVuY3Rpb24gbG9vcCgpe1xuICBzdGF0cy51cGRhdGUoKVxuICByZXF1ZXN0QW5pbWF0aW9uRnJhbWUobG9vcClcbn0pIl19"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"ratpack\",\n  \"version\": \"1.0.6\",\n  \"description\": \"ready. set. go!\",\n  \"productName\": \"ratpack\",\n  \"main\": \"lib/main.js\",\n  \"scripts\": {\n    \"start\": \"electron .\",\n    \"package-app\": \"npm run build && node scripts/package-app.js\",\n    \"init\": \"mkdirp lib && cp src/index.html lib\",\n    \"build\": \"npm run init && babel src -d lib -s inline\",\n    \"dev\": \"npm run build && concurrently \\\"babel src -d lib --watch -s inline\\\" \\\"electron .\\\" -k\",\n    \"icons\": \"png2icns resources/icon.png -o resources/icon.icns && png-to-ico resources/icon.png > resources/icon.ico && png-to-ico resources/favicon.png > resources/favicon.ico\",\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"postinstall\": \"npm run package-app\"\n  },\n  \"bin\": {\n    \"ratpack\": \"./bin/ratpack\"\n  },\n  \"author\": \"Sunil Pai <threepointone@gmail.com>\",\n  \"license\": \"ISC\",\n  \"dependencies\": {\n    \"autoprefixer\": \"^6.6.1\",\n    \"babel-cli\": \"^6.18.0\",\n    \"babel-core\": \"^6.21.0\",\n    \"babel-eslint\": \"^7.1.1\",\n    \"babel-loader\": \"^6.2.10\",\n    \"babel-plugin-transform-decorators-legacy\": \"^1.3.4\",\n    \"babel-plugin-transform-react-jsx\": \"^6.8.0\",\n    \"babel-plugin-transform-react-require\": \"^1.0.1\",\n    \"babel-plugin-transform-runtime\": \"^6.15.0\",\n    \"babel-preset-env\": \"^1.1.8\",\n    \"babel-preset-es2015\": \"^6.18.0\",\n    \"babel-preset-react\": \"^6.16.0\",\n    \"babel-preset-stage-0\": \"^6.16.0\",\n    \"babel-runtime\": \"^6.20.0\",\n    \"case-sensitive-paths-webpack-plugin\": \"^1.1.4\",\n    \"concurrently\": \"^3.1.0\",\n    \"create-react-app\": \"^1.0.3\",\n    \"css-loader\": \"^0.26.1\",\n    \"electron\": \"^1.4.14\",\n    \"electron-devtools-installer\": \"^2.0.1\",\n    \"electron-packager\": \"^8.5.0\",\n    \"eslint\": \"^3.13.1\",\n    \"eslint-config-rackt\": \"^1.1.1\",\n    \"eslint-config-react-app\": \"^0.5.0\",\n    \"eslint-loader\": \"^1.6.1\",\n    \"eslint-plugin-flowtype\": \"^2.29.2\",\n    \"eslint-plugin-import\": \"^2.2.0\",\n    \"eslint-plugin-jsx-a11y\": \"^3.0.2\",\n    \"eslint-plugin-react\": \"^6.9.0\",\n    \"file-loader\": \"^0.9.0\",\n    \"glamor\": \"^2.20.20\",\n    \"glob-to-regexp\": \"^0.3.0\",\n    \"json-loader\": \"^0.5.4\",\n    \"json5\": \"^0.5.1\",\n    \"minimist\": \"^1.2.0\",\n    \"mkdirp\": \"^0.5.1\",\n    \"nedb\": \"^1.8.0\",\n    \"object-assign\": \"^4.1.0\",\n    \"offline-plugin\": \"^4.5.4\",\n    \"opn\": \"^4.0.2\",\n    \"postcss-loader\": \"^1.2.2\",\n    \"promise\": \"^7.1.1\",\n    \"react\": \"^15.4.2\",\n    \"react-dev-utils\": \"^0.4.2\",\n    \"react-dom\": \"^15.4.2\",\n    \"react-router\": \"^4.0.0-2\",\n    \"stats.js\": \"^0.17.0\",\n    \"style-loader\": \"^0.13.1\",\n    \"touch\": \"^1.0.0\",\n    \"url-loader\": \"^0.5.7\",\n    \"webpack\": \"2.2.0-rc.4\",\n    \"webpack-dev-server\": \"2.2.0-rc.0\",\n    \"whatwg-fetch\": \"^2.0.1\"\n  },\n  \"eslintConfig\": {\n    \"extends\": [\n      \"eslint-config-react-app\"\n    ],\n    \"plugins\": [\n      \"react\"\n    ],\n    \"rules\": {\n      \"react/jsx-uses-vars\": \"error\",\n      \"react/jsx-uses-react\": \"error\",\n      \"react/react-in-jsx-scope\": 0,\n      \"jsx-quotes\": 0\n    }\n  },\n  \"devDependencies\": {}\n}\n"
  },
  {
    "path": "public/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <title></title>\n  <link rel=\"icon\" href=\"/favicon.ico\" type=\"image/x-icon\"/>\n</head>\n<body>\n  <div id='root'></div>\n  <script src='/bundle.js'></script>\n</body>\n</html>"
  },
  {
    "path": "readme.md",
    "content": "ratpack\n---\n\n[work in progress]\n```\nnpm install ratpack -g\n```\nor [download the latest release](https://github.com/threepointone/ratpack/releases)\n\n![ratpack](https://i.imgur.com/eEtI35w.png)\n\nratpack is for beginners, tinkerers, ents, cylons.\n\nquickstart\n---\n\n- write a javascript file, say `script.js`, and save it somewhere. maybe it looks like this - \n  \n  ```jsx\n    require('react-dom').render(\n      <div>hello world</div>, \n      document.getElementById('root'))\n  ```\n- drag it on to the app, or run `ratpack script.js`\n- *magic*\n\n\nmore \n---\n\nratpack gets rid of all the starting boilerplate for building and running the so-called\n'modern' javascript stack, letting you immediately jump into the core of your problem. \n\n- steals a bunch of code/tools from create-react-app for live reloading, in-browser error messaging, \nfile loaders for css, images, etc, and you can load your own loaders with js pragmas\n- comes with liberal babel defaults, including future facing extensions (and decorators!). You can also use a \nlocal `.babelrc` file (experimental).\n- preloads libraries like react, react-router@4, and glamor. It'll also use modules from \nyour own `node_modules` folder, *and* you can add your own 'globally' by installing with npm/yarn to `~/.ratpack`\n- use a local `public` folder to serve static assets that can't be imported (todo - and / or to serve a custom `index.html`)\n- use [pragmas](https://github.com/threepointone/ratpack/blob/master/docs/pragmas.md) at the top of your file to configure ratpack\n- todo - will autoupdate itself whenever I make a 'release', so you're using the latest versions of presets and packaged libs almost as soon they're out\n- todo - a preferences pane to edit 'global' settings; toggle presets, add libs, etc\n\n\n\nlong, rambly rationale\n---\n\ntl;dr - old school flow, new age ride.\n\nSo, you're reading a tutorial on requestIdleCallback / render callbacks with react / javascript thoughtlording. Or you've just had an idea for a new algorithm for reversing a binary tree. Or maybe you need to write a shitty benchmark to convince your boss that yes, immutable data is fast enough. In any case, you need to quickly write and run some code. What do you do?\n\nThese first 2 minutes are critical. The idea you've just had is ephemeral, and needs to be written down fast. It'll be dirty, and you might just throw it away later. At this point, you don't care about the framework wars and modularity shaming and whatever. This is all about you. \n\nBack in my day, I would write a javascript file (and a dumb html holder), and just run it in a browser. Sure, I had a bajillion other problems, but I liked the brutal efficiency of being seconds away from taking a random idea and turning it into pixels. Bikeshedding over 'build systems' was never the first step.\n\nMind you, we still had build systems, and we bikeshedded a lot over them and how we built our apps, but those 'apps' were a different context; built for teams and stability. Indeed, deep inside those app folders it wasn't uncommon to find 'demo' pages and `.md` scratchpads for ideas. \n\nBut 'personal' coding? Totally different rules. For one, you'd usually want the latest versions of libs. You want as little boilerplate as possible, to jump into the meat of the problem immediately. Maybe you'd have a little `/code` folder with all your commonly used libs and personal experiments. Even in the context of a larger project, maybe you want to work on a component in isolation, but don't want / need to use the project's main infrastructure.\n\nTimes change.\n\nTranspiled languages rose as a way of papering over some javascript's problems, and to use and experiment with future features in browsers that don't support it yet. And it's been absolutely *fantastic*. The pipeline of new features should keep us busy for a couple of years, if not more. Extensions like JSX and TypeScript make writing code an absolute joy (...well, mostly). I'll be blunt - I can't do UI programming without JSX anymore; having a first class UI construct in your programming language makes soooo much sense. Further, having a React dialect at arm's length means I'm not spending any mindspace on dom mutations. It's the small things, y'know?\n\nThe setup process to use transpiled languages though... not so great. You need to install and configure a pipeline of tools, usually cli + node based, in a terminal, and pay this cost almost every time you need to run a new file. nwb, create-react-app, etc get *so* close, but by nature of their being designed for 'apps', don't achieve the lightweight, experimental feel I'm looking for. Also, CLIs, ick.\n\nWe're UI developers. We can do better. By building beginner/tinkerer friendly tooling, we can automate some of our own pain away, and increase how inclusive we are as a community and as a technology. Here's my attempt. \n\nFirst, some of my 'requirements' - \n- I'd like to be able to write a javascript file, with es6 and jsx and whatnot, and just run it in a browser. This could be on my desktop, my downloads folder, wherever.\n- I do *not* want to have to install or configure anything 'build' related every time.\n- I'd like some liberal defaults, and include some prepackaged libraries like react, react-router, glamor, polyfills for fetch etc.\n- *maybe* I'll have a local node_modules, or in a folder higher up my path \n- *perhaps* I'll have a local `public` folder too, with images and css or whatever I'll need \n- *perchance* if I need to, I'd like a custom babel config to mess with a plugin or preset \n\n\nLet's imagine the core experience - I'd like to have an app (like a legit, macOS/windows/linux desktop app), and I'd like to drag and drop my `.js` file into it / onto its dock icon, and it would \"just work\". It could open a browser tab to that file running in a simple html page, and reload whenever I make file changes. A list of previously opened files would be nice.\n\nHence... *drum roll*... ratpack. Hope you like it. Lemme know what I could do better, and what you'd like to see!\n\n\nfeature wishlist \n---\n\n- better design\n- frictionless mobile web dev\n- build / deploy to now / surge / etc\n- the service worker treatment \n- end to end encrypted share ala ngrok\n- multiple languages; flow, reason, node, whatevs \n- eject config, for carrying on a 'real' project\n- a smaller package\n\nthe shoulders of giants\n---\n\nthis couldn't exist without the work of thousands of people in the OSS world. Some projects specifically -\n\n- nwb, create-react-app, and the whole family of CLI apps to bootstrap, run and build your javascript apps\n- webpack2, the giant swiss army knife of javascript bundlers \n- babel, for all your javascript transformation needs\n- electron, giving a truly desirable target for building javascript tooling \n- and of course, react and its entire ecosystem.\n\n\nproject status\n---\n\nThis is stil *very* early work, with a large number of todos to get through before it's 'production ready'. \nThat said, this is already pretty useful. If you'd like to try it out, either try out the \nprototype mac release, or clone this repo and run `npm run && npm run package-app` to generate the binary for \nyour computer. Have fun!\n\n"
  },
  {
    "path": "resources/.eslintrc",
    "content": "{\n  \"extends\": [\n    \"eslint-config-react-app\"\n  ],\n  \"plugins\": [\n    \"react\"\n  ],\n  \"rules\": {\n    \"react/jsx-uses-vars\": \"error\",\n    \"react/jsx-uses-react\": \"error\",\n    \"react/react-in-jsx-scope\": 0,\n    \"jsx-quotes\": 0\n  }\n}"
  },
  {
    "path": "resources/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n  <dict>\n    <key>CFBundleDocumentTypes</key>\n    <array>\n        <dict>\n            <key>CFBundleTypeExtensions</key>\n            <array>\n                <string>js</string>\n                <string>jsx</string>\n            </array>\n            <key>CFBundleTypeName</key>\n            <string>JS</string>\n            <key>CFBundleTypeRole</key>\n            <string>Editor</string>\n            <key>LSHandlerRank</key>\n            <string>Alternate</string>\n        </dict>\n    </array>\n  </dict>\n</plist>"
  },
  {
    "path": "scripts/package-app.js",
    "content": "let packager = require('electron-packager')\nlet path = require('path')\n\nprocess.chdir(path.join(__dirname, '../'))\n\npackager({\n  dir: path.join(__dirname, '../'),\n  // afterCopy: [ function () {\n  //   console.log('afterCopy', ...arguments)\n  // } ],\n  // afterExtract: [ function () {\n  //   console.log('afterExtract', ...arguments)\n  // } ],\n  prune: false, // todo - fix\n  // mac \n  'app-copyright': 'copyright 2017 Sunil Pai',\n  'app-version': require('../package').version,\n  asar: false,\n  'build-version': require('../package').version,\n  icon: path.join(__dirname, '../resources/', process.platform === 'darwin' ? 'icon.icns': 'icon.ico'),\n  'out': path.join(__dirname, '../out'),\n  overwrite: true,\n  'app-bundle-id': 'com.threepointone.ratpack',\n  'app-category-type': 'public.app-category.developer-tools',\n  'extend-info': path.join(__dirname, '../resources/Info.plist'),\n  'helper-bundle-id': 'com.threepointone.ratpack.helper',\n  // protocol: 'ratpack'\n  // 'protocol-name': []\n  \n  // windows\n  win32metadata: {\n    CompanyName: 'threepointone',\n    FileDescription: 'ratpack, for justice',\n    // OriginalFilename\n    ProductName: 'ratpack'\n    // InternalName: \n  }\n\n   // nothing for linux? \n}, (err, appPaths) => {\n  if(err) {\n    console.error(err) //eslint-disable-line no-console\n    return\n  }\n  console.log('done') //eslint-disable-line no-console\n  console.log(appPaths) //eslint-disable-line no-console\n})\n"
  },
  {
    "path": "spiel.md",
    "content": "[this has moved to the main readme](readme.md)"
  },
  {
    "path": "src/app.js",
    "content": "\nimport qs from 'querystring'\nimport autoprefixer from 'autoprefixer'\nimport React from 'react'\nimport path from 'path'\nimport { render } from 'react-dom'\nimport 'glamor/reset'\nimport hash from 'glamor/lib/hash'\nimport pragmas from './pragmas'\nimport glob2regexp from 'glob-to-regexp'\nimport openBrowser from 'react-dev-utils/openBrowser'\nimport OfflinePlugin from 'offline-plugin'\n\nconst electron = require('electron')\nconst app = electron.app || electron.remote.app\n\n\nimport WebpackDevServer from 'webpack-dev-server'\nimport webpack from 'webpack'\n\nimport { css, presets } from 'glamor'\nconst yellow = '#f7df1e'\n\n\nimport DataStore from 'nedb'\nlet db = new DataStore({\n  filename: path.join(app.getPath('userData'), 'store.db'),\n  autoload: true\n})\ndb.find({ _id: 'recently' }, (err, docs) => {\n  if(docs.length === 0) {\n    db.insert({ _id: 'recently', files: [] }, err => {\n      if(err) return console.error(err) //eslint-disable-line no-console\n      console.log('db initialized') //eslint-disable-line no-console\n    })\n  }\n  else console.log('db restarted')  //eslint-disable-line no-console\n})\n\n// todo - move this to main.js \nimport mkdirp from 'mkdirp'\nimport touch from 'touch'\nimport fs from 'fs'\n\n\n// todo - windows\nmkdirp(path.join(app.getPath('home'), '.ratpack'), err => {\n  if(err) {\n    throw err\n  }\n  let pkjson = path.join(app.getPath('home'), '.ratpack/package.json')\n  if(!fs.existsSync(pkjson)) {\n    touch.sync(pkjson)\n    fs.writeFileSync(pkjson, JSON.stringify({\n      name: 'ratpack-local',\n      description: 'these modules are available to all scripts launched by ratpack'\n    }))  \n  }\n  // among other things, this makes loaders defined in pragmas to work \n  require('module').globalPaths.push(path.join(app.getPath('home'), '.ratpack/node_modules'))\n  \n})\n\nfunction times(n, fn) {\n  let arr = []\n  for(let i= 0; i< n; i++) {\n    arr.push(fn(i))\n  }\n  return arr\n}\n\ncss.global('html, body, #root', { position: 'relative', width: '100%', height: '100%', display: 'block', backgroundColor: yellow })\n\nconst Logo = () => <div css={{ width: 100, height: 100, position: 'absolute', bottom: 0, right: 0, [presets.Phablet]: { width: 200, height: 200 } }}>\n  <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 630 630\" >\n    <path d=\"m423.2 492.19c12.69 20.72 29.2 35.95 58.4 35.95 24.53 0 40.2-12.26 40.2-29.2 0-20.3-16.1-27.49-43.1-39.3l-14.8-6.35c-42.72-18.2-71.1-41-71.1-89.2 0-44.4 33.83-78.2 86.7-78.2 37.64 0 64.7 13.1 84.2 47.4l-46.1 29.6c-10.15-18.2-21.1-25.37-38.1-25.37-17.34 0-28.33 11-28.33 25.37 0 17.76 11 24.95 36.4 35.95l14.8 6.34c50.3 21.57 78.7 43.56 78.7 93 0 53.3-41.87 82.5-98.1 82.5-54.98 0-90.5-26.2-107.88-60.54zm-209.13 5.13c9.3 16.5 17.76 30.45 38.1 30.45 19.45 0 31.72-7.61 31.72-37.2v-201.3h59.2v202.1c0 61.3-35.94 89.2-88.4 89.2-47.4 0-74.85-24.53-88.81-54.075z\" />\n  </svg>\n</div>\n\nclass App extends React.Component {\n  state = {\n    tick: 0,\n    filepath: undefined,\n    webpackCompiler: null,\n    webpackServer: null,\n    recently: [],\n    errors: [],\n    port: 0,\n    running: false\n  }\n  onOpenFile = (e, filepath) => {\n    this.loadFile(filepath)\n  }\n  refreshRecentList(cb) {\n    db.find({ _id: 'recently' }, (err, docs) => {\n      if(err) {\n        this.setState({\n          errors: [ ...this.state.errors, err ]\n        })\n        return \n      }\n      this.setState({\n        recently: docs[0].files\n      })\n      if(cb) cb()\n    })\n  }\n  componentDidMount() {\n    app.on('open-file', this.onOpenFile)\n    this.refreshRecentList(() => {\n      if(window.location.search) {\n        let filepath = qs.parse(window.location.search.slice(1)).startsWith\n        filepath && this.loadFile(filepath)\n      }\n    })   \n    this.interval = setInterval(() => {\n      this.setState({\n        tick: (this.state.tick + 1) % 4 \n      })      \n    }, 400)\n \n  }\n  componentWillUnmount() {\n    clearInterval(this.interval)\n    this.interval = null    \n\n    if(this.state.webpackServer) {\n      this.state.webpackServer.close()  \n    }   \n    if(this.watcher) {\n      this.watcher.close()\n      this.watcher = null\n    } \n    app.removeEventListener('open-file', this.onOpenFile)\n  }\n  _loadFile(filepath){\n    fs.readFile(filepath, 'utf8', (err, src) => {      \n      if(err) throw err\n      let options = pragmas(src)\n      this.setState({ ...webpackify(filepath, options), filepath, running: true, pragmas: options })\n\n      // simultaneously start watching the entry file \n      this.watcher = fs.watch(filepath, e => {\n        if(e === 'rename') {\n          // ???\n          return          \n        }        \n        // if any of the pragmas change, redo this shindig \n        fs.readFile(filepath, 'utf8', (err, src) => {\n          let options = pragmas(src)\n          if(JSON.stringify(options) !== JSON.stringify(this.state.pragmas)) {\n            this.loadFile(filepath)\n          }\n          // todo - prevent double read \n        })\n\n      })\n    })    \n  }\n  loadFile(filepath) {\n\n    db.update({ _id: 'recently' }, { _id: 'recently', files: [ { path: filepath }, ...this.state.recently.filter(x => x.path !== filepath) ].slice(0, 10) }, {}, err => {\n      if(err) {\n        this.setState({\n          errors: [ ...this.state.errors, err ]\n        })\n        return         \n      } \n      this.refreshRecentList()           \n    })\n    if(this.watcher) {\n      this.watcher.close()\n      this.watcher = null\n    }\n    \n    if(this.state.webpackServer) {\n      this.state.webpackServer.close()\n      setTimeout(() => {\n        this._loadFile(filepath)\n      }, 500)      \n    }\n    else {\n      this._loadFile(filepath)\n    }\n            \n  }\n  onDrop = e => {\n    e.preventDefault()\n    e.stopPropagation()\n    let filepath = e.nativeEvent.dataTransfer.files[0].path\n    this.loadFile(filepath)\n  }\n  clearRecentList() {\n    db.update({ _id: 'recently' }, { _id: 'recently', files: [] }, () => {\n      this.refreshRecentList()\n    })\n  }\n  \n  render() {\n    return <div \n      css={{ width: '100%', height: '100%', fontFamily: 'helvetica' }} \n      onDragOver={e => e.preventDefault()} // chrome bug \n      onDrop={this.onDrop}>      \n        \n      <div css={{ fontWeight: 'bolder', fontSize: 32, padding: 20, [presets.Phablet]: { fontSize: 64 } }}>\n      { this.state.running ? \n        `${path.basename(this.state.filepath)} running at \n        localhost:${this.state.port}${times(this.state.tick, () => '.').join('')}`\n        : 'Drop a .js file here to get started '}\n        \n      \n      </div> \n      { this.state.recently.length > 0 && <div css={{ padding: 20 }}>\n        <h1>previously...</h1>\n        {this.state.recently.map(x => <div key={x.path} onClick={() => this.loadFile(x.path)}>{x.path}</div>)}\n        <h4 onClick={() => this.clearRecentList()}>clear list</h4>\n      </div>}\n      \n      <Logo/>\n      \n    </div>\n    \n  }\n}\n\nfunction webpackify(filepath, options = {}) {\n  \n  let webpackCompiler = webpack({\n    devtool: options.production ? false : (options.devtool || 'cheap-module-source-map'),\n    entry: [ \n      ((options.reload !== false) || (options.production !== true) ) ? \n        require.resolve('react-dev-utils/webpackHotDevClient.js') : \n        undefined, \n      options.stats ? require.resolve('./stats.js') : undefined,\n      require.resolve('./polyfills'), \n      options.offline ? require.resolve('./offline-plugin-runtime.js') : undefined,\n      filepath \n    ].filter(x => !!x),\n    output: {\n      path: path.join(__dirname, '../public'),\n      pathinfo: true,\n      filename: 'bundle.js'\n    },\n    performance: {\n      hints: false\n    },\n    module: {\n      rules: [ \n        ...(options.rules || []).map(({ loader, files, options }) => ({ loader: require.resolve(loader), options, test: glob2regexp(files || '*') })), \n        {\n          enforce: 'pre',\n          test: /\\.(js|jsx)$/,\n          loader: require.resolve('eslint-loader'),\n          exclude: /node_modules/,\n          options: {\n            configFile: path.join(__dirname, '../resources/.eslintrc')\n          }\n        }, \n        {\n          exclude: [\n            /\\.html$/,\n            /\\.(js|jsx)$/,\n            /\\.css$/,\n            /\\.json$/,\n            /\\.svg$/\n          ],\n          loader: require.resolve('url-loader'),\n          query: {\n            limit: 10000,\n            name: 'static/media/[name].[hash:8].[ext]'\n          }\n        }, \n        {\n          test: /\\.js$/,\n          exclude: /node_modules/,\n          loader: require.resolve('babel-loader'),\n          options: {\n            'presets': [ \n              [ require('babel-preset-env'), { \n                'targets': {\n                  'browsers': [ 'last 2 versions', 'safari >= 7' ]\n                }, \n                modules: false \n              } ], \n              require('babel-preset-stage-0'), \n              require('babel-preset-react'),              \n              ...(options.babel || {}).presets || []\n            ],\n            'plugins': [\n              [ require.resolve('babel-plugin-transform-runtime'), {\n                helpers: false,\n                polyfill: false,\n                regenerator: true\n                // Resolve the Babel runtime relative to the config.\n                // moduleName: path.dirname(require.resolve('babel-runtime/package'))\n              } ],\n              options.jsx ? [ require('babel-plugin-transform-react-jsx'),\n                { 'pragma': options.jsx } ] : undefined,\n              require('babel-plugin-transform-decorators-legacy').default,\n              require('babel-plugin-transform-react-require').default,\n              \n              ...(options.babel || {}).plugins || []\n            ].filter(x => !!x),\n            cacheDirectory: false\n          }\n        }, \n        {\n          test: /\\.css$/,\n          use: [\n            require.resolve('style-loader'), \n            {\n              loader: require.resolve('css-loader'),\n              options: { importLoaders: 1 } \n            }, \n            require.resolve('postcss-loader')  // options in the plugins section below             \n          ]\n        }, \n        // {\n        //   test: /\\.json$/,\n        //   loader: require.resolve('json-loader')\n        // },\n         {\n          test: /\\.svg$/,\n          loader: require.resolve('file-loader'),\n          query: {\n            name: 'static/media/[name].[hash:8].[ext]'\n          }\n        } \n      ]\n    },\n    resolve: {\n      alias: options.alias || {},\n      extensions: [ '.js', '.json', '.jsx' ],\n      // todo - windows\n      modules: [ 'node_modules', path.join(app.getPath('home'), '.ratpack/node_modules'),  path.join(__dirname, '../node_modules') ]\n    },\n    plugins: [\n      new webpack.DefinePlugin({\n        'process.env.NODE_ENV': JSON.stringify((options.production && 'production') || process.env.NODE_ENV || 'development'),\n        ...Object.keys(options.define || {}).reduce((o, key) => ({ ...o, [key]: JSON.stringify(options.define[key]) }), {})\n      }),\n      options.offline ? new OfflinePlugin(options.offline === true ? {} : options.offline) : undefined,\n      new webpack.ProvidePlugin(options.provide || {}),\n      new webpack.LoaderOptionsPlugin({\n        test: /\\.css$/,\n        debug: true,\n        options: {\n          postcss: [\n            autoprefixer({\n              browsers: [\n                '>1%',\n                'last 4 versions',\n                'Firefox ESR',\n                'not ie < 9' // React doesn't support IE8 anyway\n              ]\n            })\n          ]\n        }\n      })\n    ].filter(x => !!x),\n    stats: 'errors-only',\n    node: {\n      fs: 'empty',\n      net: 'empty',\n      tls: 'empty'\n    }\n  })\n  \n  let webpackServer = new WebpackDevServer(webpackCompiler, {\n    // todo - windows\n    contentBase: [ options.public ? path.join(path.dirname(filepath), options.public) : '', path.join(path.dirname(filepath), 'public'), path.join(__dirname, '../public') ].filter(x => !!x),\n    historyApiFallback: true,\n    compress: true,\n    proxy: options.proxy || {},\n        // setup()\n        // staticOptions \n\n    quiet: true,      \n    stats: { colors: false }  \n  })\n    // this is to workaround some weird bug where webpack keeps the first loaded file \n    // also makes it look cool ha\n  let h = hash(filepath, filepath.length)+ ''\n  let port = options.port || (3000 + parseInt(h.substr(h.length - 4), 10))\n  webpackServer.listen(port)\n  openBrowser('http://localhost:' + port)\n  return { webpackServer, webpackCompiler, port }\n\n}\n \nrender(<App/>, document.getElementById('root'))\n"
  },
  {
    "path": "src/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <title>ratpack</title>\n   \n</head>\n<body>\n  <div id='root'/>\n  <script>\n    require('./app')    \n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "src/main.js",
    "content": "// import installExtension, { REACT_DEVELOPER_TOOLS } from 'electron-devtools-installer'\n\n// app: control application file.\n// BrowserWindow: create native browser window.\n\nimport { app, BrowserWindow }  from 'electron'\nimport path from 'path'\n\nlet isProd = path.basename(process.argv[0]).indexOf('ratpack') === 0\n\nlet startsWith = require('minimist')(process.argv.slice(1))._[ isProd ? 0 : 1]\nlet startedOnce = false\nlet mainWindow\n\napp.on('open-file', (e, filepath) => {\n  if(!mainWindow ) {\n    startsWith = filepath\n    if(!startedOnce) {      \n      return\n    }    \n    createWindow()    \n    return \n  }    \n})\n \n// Keep a global reference of the window object, if you don't, the window will\n// be closed automatically when the JavaScript object is garbage collected.\n\n\nfunction createWindow() {\n  // Create the browser window.\n  // installExtension(REACT_DEVELOPER_TOOLS)\n  //   .then((name) => console.log(`Added Extension:  ${name}`))\n  //   .catch((err) => console.log('An error occurred: ', err))\n\n  mainWindow = new BrowserWindow({ width: 800, height: 600, icon: path.join(__dirname, '../resources/icon.png'), backgroundColor: '#f7df1e', show: false })\n  mainWindow.once('ready-to-show', () => {\n    mainWindow.show()\n  })\n  startedOnce = true\n  // and load the index.html of the app.\n  mainWindow.loadURL(`file://${__dirname}/index.html${startsWith ? `?startsWith=${encodeURIComponent(startsWith)}` : ''}` )\n  startsWith = undefined\n  // Open the DevTools.\n  // mainWindow.webContents.openDevTools()\n\n  // Emitted when the window is closed.\n  mainWindow.on('closed', function () {\n    // Dereference the window object, usually you would store windows\n    // in an array if your app supports multi windows, this is the time\n    // when you should delete the corresponding element.\n    mainWindow = null\n  })\n}\n\n// This method will be called when Electron has finished\n// initialization and is ready to create browser windows.\n// Some APIs can only be used after this event occurs.\napp.on('ready', createWindow)\n\n// Quit when all windows are closed.\napp.on('window-all-closed', function () {\n  // On OS X it is common for applications and their menu bar\n  // to stay active until the user quits explicitly with Cmd + Q\n  if (process.platform !== 'darwin') {\n    app.quit()\n  }\n})\n\n\napp.on('activate', function () {\n  // On OS X it's common to re-create a window in the app when the\n  // dock icon is clicked and there are no other windows open.\n  if (mainWindow === null) {\n    createWindow()\n  }\n})\n\n// In this file you can include the rest of your app's specific main process\n// code. You can also put them in separate files and require them here.\n"
  },
  {
    "path": "src/offline-plugin-runtime.js",
    "content": "require('offline-plugin/runtime').install()\n"
  },
  {
    "path": "src/polyfills.js",
    "content": "// @remove-on-eject-begin\n/**\n * Copyright (c) 2015-present, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n */\n// @remove-on-eject-end\n\nif (typeof Promise === 'undefined') {\n  // Rejection tracking prevents a common issue where React gets into an\n  // inconsistent state due to an error, but it gets swallowed by a Promise,\n  // and the user has no idea what causes React's erratic future behavior.\n  require('promise/lib/rejection-tracking').enable()\n  window.Promise = require('promise/lib/es6-extensions.js')\n}\n\n// fetch() polyfill for making API calls.\nrequire('whatwg-fetch')\n\n// Object.assign() is commonly used with React.\n// It will use the native implementation if it's present and isn't buggy.\nObject.assign = require('object-assign')\n"
  },
  {
    "path": "src/pragmas.js",
    "content": "import * as babylon from 'babylon'\nimport json5 from 'json5'\n\nexport default function parse(src) {\n  let ast = babylon.parse(src, { plugins: [ '*' ], sourceType: 'module' })\n\n  let config = ast.tokens\n    .filter(x => [ 'CommentLine', 'CommentBlock' ].indexOf(x.type) >=0)\n    .map(x => x.value)\n    .filter(x => /^\\s*@ratpack/gim.test(x))\n\n  if(config.length > 1) { throw new Error('cannot have multiple ratpack configs in one file') }\n  config = config[0]\n\n  if(!config) return\n\n  config = json5.parse(config.substr(config.indexOf('@ratpack') + 8))\n\n\n  Object.keys(config).forEach(key => {\n    let value = config[key]\n    switch(key) {\n      case 'devtool': {\n        let possibles = [ 'eval', 'cheap-eval-source-map', 'cheap-source-map', 'cheap-module-eval-source-map',\n          'cheap-module-source-map', 'eval-source-map', 'source-map', 'nosources-source-map' ]\n        if(!(possibles.indexOf(value) >= 0)) {\n          throw new Error(`@devtool ${value} needs to be one of ` + possibles.join(', '))\n        }\n        break\n      }\n\n      case 'target': {\n        let possibles = [ 'async-node', 'electron', 'electron-renderer', 'node', 'node-webkit', 'web', 'webworker' ] \n        if(!(possibles.indexOf(value) >= 0)) {\n          throw new Error(`@target ${value} needs to be one of ` + possibles.join(', '))\n        }\n        console.warn('target doesn\\'t work yet') //eslint-disable-line no-console\n        break\n      }\n\n      case 'public': break // todo - test if valid dir \n      \n      case 'jsx': {\n        if(typeof value !== 'string') {\n          throw new Error('jsx pragma needs to be a valid string')\n        }\n        break \n      }// test if string\n      \n      case 'offline': // vvv      \n      case 'autoinstall': {        \n        if((value !== true) && (value !== false)) {\n          throw new Error(`@${key} ${value} needs to be true or false`)\n        }\n        console.warn(`${key} doesn't work yet`) //eslint-disable-line no-console\n        break\n      } \n      case 'stats': \n      case 'reload': {\n        if((value !== true) && (value !== false)) {\n          throw new Error(`@${key} ${value} needs to be true or false`)\n        }\n        break \n      }\n      case 'port': {\n        if(!(value >= 0)) {\n          throw new Error(`port ${value} needs to be a valid number`)\n        }\n        break\n      }\n      case 'proxy': break // vvv    // test shape\n      case 'provide': break // vvv  // test shape \n      case 'alias': break // vvv    // test shape\n      case 'define': break          // test shape\n      case 'rules': break           // test shape\n      \n      case 'plugins': {        \n        console.warn('plugins don\\'t work yet') //eslint-disable-line no-console\n        break\n      }\n      case 'babel': {     // test shape    \n        break\n      }      \n      default: console.warn('not implemented', key, value)  //eslint-disable-line no-console\n    }\n  })\n  return config\n}\n\n"
  },
  {
    "path": "src/stats.js",
    "content": "import Stats from 'stats.js'\nlet stats = new Stats()\ndocument.body.appendChild(stats.dom)\n\nrequestAnimationFrame(function loop(){\n  stats.update()\n  requestAnimationFrame(loop)\n})"
  },
  {
    "path": "todo.md",
    "content": "- x - start webpack, babel shindig \n- x - expose react, react-dom, react-router, glamor\n- x - open a browser window \n- x - hot reloading\n- x - compilation error overlay\n- x - local .babelrc override\n- x - implicit react require\n- x - drop another file to load that instead \n- x - recently opened files\n- x - 'running on port...'\n- x - css, image, etc loaders \n- x - special pragmas \n- x - proxy\n- x - cli experience\n- x - favicon\n- x - linting (setup helper?)\n- x - open with / dbl click experiencec\n- x - dock experience\n- x - stats \n\n- menubar experience\n- messaging on webpack error \n- ~ - polyfills\n- preferences pane\n- configurations / presets \n- ~ - packaged app  \n- updates for main app?\n\n\n- perf / stats / fps measurement helpers \n- do a 'prod build' \n- node?\n- offline?\n- auto install?\n- any language?\n- windows?\n- redbox?\n- flow / typescript / etc \n- implicit React.render for default/App export?\n- performance hints \n"
  }
]