aboutsummaryrefslogtreecommitdiff
path: root/diplomacy/web
diff options
context:
space:
mode:
Diffstat (limited to 'diplomacy/web')
-rw-r--r--diplomacy/web/.eslintignore1
-rw-r--r--diplomacy/web/.eslintrc25
-rw-r--r--diplomacy/web/.gitignore21
-rw-r--r--diplomacy/web/package-lock.json11509
-rw-r--r--diplomacy/web/package.json29
-rw-r--r--diplomacy/web/public/favicon.icobin0 -> 3870 bytes
-rw-r--r--diplomacy/web/public/index.html40
-rw-r--r--diplomacy/web/public/manifest.json15
-rw-r--r--diplomacy/web/src/diplomacy/client/channel.js256
-rw-r--r--diplomacy/web/src/diplomacy/client/connection.js340
-rw-r--r--diplomacy/web/src/diplomacy/client/game_instance_set.js76
-rw-r--r--diplomacy/web/src/diplomacy/client/network_game.js297
-rw-r--r--diplomacy/web/src/diplomacy/client/notification_managers.js127
-rw-r--r--diplomacy/web/src/diplomacy/client/request_future_context.js63
-rw-r--r--diplomacy/web/src/diplomacy/client/response_managers.js118
-rw-r--r--diplomacy/web/src/diplomacy/communication/notifications.js56
-rw-r--r--diplomacy/web/src/diplomacy/communication/requests.js120
-rw-r--r--diplomacy/web/src/diplomacy/communication/responses.js42
-rw-r--r--diplomacy/web/src/diplomacy/engine/game.js507
-rw-r--r--diplomacy/web/src/diplomacy/engine/message.js34
-rw-r--r--diplomacy/web/src/diplomacy/engine/power.js129
-rw-r--r--diplomacy/web/src/diplomacy/utils/diplog.js45
-rw-r--r--diplomacy/web/src/diplomacy/utils/future.js55
-rw-r--r--diplomacy/web/src/diplomacy/utils/future_event.js41
-rw-r--r--diplomacy/web/src/diplomacy/utils/sorted_dict.js109
-rw-r--r--diplomacy/web/src/diplomacy/utils/strings.js86
-rw-r--r--diplomacy/web/src/diplomacy/utils/utils.js188
-rw-r--r--diplomacy/web/src/gui/core/content.jsx51
-rw-r--r--diplomacy/web/src/gui/core/fancybox.jsx59
-rw-r--r--diplomacy/web/src/gui/core/forms.jsx116
-rw-r--r--diplomacy/web/src/gui/core/layouts.jsx55
-rw-r--r--diplomacy/web/src/gui/core/page.jsx434
-rw-r--r--diplomacy/web/src/gui/core/table.jsx112
-rw-r--r--diplomacy/web/src/gui/core/tabs.jsx96
-rw-r--r--diplomacy/web/src/gui/core/widgets.jsx102
-rw-r--r--diplomacy/web/src/gui/diplomacy/contents/content_connection.jsx91
-rw-r--r--diplomacy/web/src/gui/diplomacy/contents/content_game.jsx1235
-rw-r--r--diplomacy/web/src/gui/diplomacy/contents/content_games.jsx140
-rw-r--r--diplomacy/web/src/gui/diplomacy/forms/connection_form.jsx123
-rw-r--r--diplomacy/web/src/gui/diplomacy/forms/create_form.jsx95
-rw-r--r--diplomacy/web/src/gui/diplomacy/forms/find_form.jsx70
-rw-r--r--diplomacy/web/src/gui/diplomacy/forms/join_form.jsx77
-rw-r--r--diplomacy/web/src/gui/diplomacy/forms/message_form.jsx53
-rw-r--r--diplomacy/web/src/gui/diplomacy/forms/power_actions_form.jsx120
-rw-r--r--diplomacy/web/src/gui/diplomacy/forms/select_location_form.jsx36
-rw-r--r--diplomacy/web/src/gui/diplomacy/forms/select_via_form.jsx35
-rw-r--r--diplomacy/web/src/gui/diplomacy/map/dom_order_builder.js278
-rw-r--r--diplomacy/web/src/gui/diplomacy/map/dom_past_map.js112
-rw-r--r--diplomacy/web/src/gui/diplomacy/map/map.jsx94
-rw-r--r--diplomacy/web/src/gui/diplomacy/map/renderer.js615
-rw-r--r--diplomacy/web/src/gui/diplomacy/utils/dipStorage.jsx140
-rw-r--r--diplomacy/web/src/gui/diplomacy/utils/inline_game_view.jsx129
-rw-r--r--diplomacy/web/src/gui/diplomacy/utils/map_data.js98
-rw-r--r--diplomacy/web/src/gui/diplomacy/utils/order.js24
-rw-r--r--diplomacy/web/src/gui/diplomacy/utils/order_building.js211
-rw-r--r--diplomacy/web/src/gui/diplomacy/utils/power_view.jsx59
-rw-r--r--diplomacy/web/src/gui/diplomacy/utils/province.js117
-rw-r--r--diplomacy/web/src/gui/diplomacy/widgets/message_view.jsx57
-rw-r--r--diplomacy/web/src/gui/diplomacy/widgets/power_order.jsx79
-rw-r--r--diplomacy/web/src/index.css401
-rw-r--r--diplomacy/web/src/index.js28
l---------diplomacy/web/src/standard.svg1
62 files changed, 19872 insertions, 0 deletions
diff --git a/diplomacy/web/.eslintignore b/diplomacy/web/.eslintignore
new file mode 100644
index 0000000..378eac2
--- /dev/null
+++ b/diplomacy/web/.eslintignore
@@ -0,0 +1 @@
+build
diff --git a/diplomacy/web/.eslintrc b/diplomacy/web/.eslintrc
new file mode 100644
index 0000000..85a4876
--- /dev/null
+++ b/diplomacy/web/.eslintrc
@@ -0,0 +1,25 @@
+{
+ "plugins": [
+ "react"
+ ],
+ "parserOptions": {
+ "ecmaVersion": 6,
+ "sourceType": "module",
+ "ecmaFeatures": {
+ "jsx": true
+ }
+ },
+ "env": {
+ "es6": true,
+ "browser": true,
+ "node": true,
+ "mocha": true
+ },
+ "extends": [
+ "eslint:recommended",
+ "plugin:react/recommended"
+ ],
+ "rules": {
+ "semi": [2, "always", { "omitLastInOneLineBlock": true}]
+ }
+}
diff --git a/diplomacy/web/.gitignore b/diplomacy/web/.gitignore
new file mode 100644
index 0000000..d30f40e
--- /dev/null
+++ b/diplomacy/web/.gitignore
@@ -0,0 +1,21 @@
+# See https://help.github.com/ignore-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+
+# testing
+/coverage
+
+# production
+/build
+
+# misc
+.DS_Store
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
diff --git a/diplomacy/web/package-lock.json b/diplomacy/web/package-lock.json
new file mode 100644
index 0000000..bbb290a
--- /dev/null
+++ b/diplomacy/web/package-lock.json
@@ -0,0 +1,11509 @@
+{
+ "name": "web",
+ "version": "0.1.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@githubprimer/octicons-react": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@githubprimer/octicons-react/-/octicons-react-8.0.0.tgz",
+ "integrity": "sha512-0dBJ8Pxe94g1RzULybp0zDWiFpZISAIaRY4LP8ZZnweJgyIoLGXy/6bGycJnPHfmk5sbhcuzzNDufLLDA2vxWA==",
+ "requires": {
+ "prop-types": "^15.6.1"
+ }
+ },
+ "abab": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz",
+ "integrity": "sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4="
+ },
+ "accepts": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz",
+ "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=",
+ "requires": {
+ "mime-types": "~2.1.18",
+ "negotiator": "0.6.1"
+ }
+ },
+ "acorn": {
+ "version": "5.6.2",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.6.2.tgz",
+ "integrity": "sha512-zUzo1E5dI2Ey8+82egfnttyMlMZ2y0D8xOCO3PNPPlYXpl8NZvF6Qk9L9BEtJs+43FqEmfBViDqc5d1ckRDguw=="
+ },
+ "acorn-dynamic-import": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz",
+ "integrity": "sha1-x1K9IQvvZ5UBtsbLf8hPj0cVjMQ=",
+ "requires": {
+ "acorn": "^4.0.3"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "4.0.13",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz",
+ "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c="
+ }
+ }
+ },
+ "acorn-globals": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz",
+ "integrity": "sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=",
+ "requires": {
+ "acorn": "^4.0.4"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "4.0.13",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz",
+ "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c="
+ }
+ }
+ },
+ "acorn-jsx": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz",
+ "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=",
+ "requires": {
+ "acorn": "^3.0.4"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz",
+ "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo="
+ }
+ }
+ },
+ "address": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/address/-/address-1.0.3.tgz",
+ "integrity": "sha512-z55ocwKBRLryBs394Sm3ushTtBeg6VAeuku7utSoSnsJKvKcnXFIyC6vh27n3rXyxSgkJBBCAvyOn7gSUcTYjg=="
+ },
+ "ajv": {
+ "version": "5.5.2",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
+ "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
+ "requires": {
+ "co": "^4.6.0",
+ "fast-deep-equal": "^1.0.0",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.3.0"
+ }
+ },
+ "ajv-keywords": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz",
+ "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I="
+ },
+ "align-text": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
+ "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
+ "requires": {
+ "kind-of": "^3.0.2",
+ "longest": "^1.0.1",
+ "repeat-string": "^1.5.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "alphanum-sort": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz",
+ "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM="
+ },
+ "amdefine": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
+ "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU="
+ },
+ "ansi-align": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz",
+ "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=",
+ "requires": {
+ "string-width": "^2.0.0"
+ }
+ },
+ "ansi-escapes": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz",
+ "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw=="
+ },
+ "ansi-html": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz",
+ "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4="
+ },
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+ },
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "anymatch": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
+ "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==",
+ "requires": {
+ "micromatch": "^2.1.5",
+ "normalize-path": "^2.0.0"
+ },
+ "dependencies": {
+ "arr-diff": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
+ "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
+ "requires": {
+ "arr-flatten": "^1.0.1"
+ }
+ },
+ "array-unique": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
+ "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM="
+ },
+ "braces": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
+ "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
+ "requires": {
+ "expand-range": "^1.8.1",
+ "preserve": "^0.2.0",
+ "repeat-element": "^1.1.2"
+ }
+ },
+ "expand-brackets": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
+ "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
+ "requires": {
+ "is-posix-bracket": "^0.1.0"
+ }
+ },
+ "extglob": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
+ "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
+ "requires": {
+ "is-extglob": "^1.0.0"
+ }
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ },
+ "micromatch": {
+ "version": "2.3.11",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
+ "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
+ "requires": {
+ "arr-diff": "^2.0.0",
+ "array-unique": "^0.2.1",
+ "braces": "^1.8.2",
+ "expand-brackets": "^0.1.4",
+ "extglob": "^0.3.1",
+ "filename-regex": "^2.0.0",
+ "is-extglob": "^1.0.0",
+ "is-glob": "^2.0.1",
+ "kind-of": "^3.0.2",
+ "normalize-path": "^2.0.1",
+ "object.omit": "^2.0.0",
+ "parse-glob": "^3.0.4",
+ "regex-cache": "^0.4.2"
+ }
+ }
+ }
+ },
+ "append-transform": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz",
+ "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==",
+ "requires": {
+ "default-require-extensions": "^2.0.0"
+ }
+ },
+ "argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "requires": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "aria-query": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-0.7.1.tgz",
+ "integrity": "sha1-Jsu1r/ZBRLCoJb4YRuCxbPoAsR4=",
+ "requires": {
+ "ast-types-flow": "0.0.7",
+ "commander": "^2.11.0"
+ }
+ },
+ "arr-diff": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+ "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA="
+ },
+ "arr-flatten": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+ "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg=="
+ },
+ "arr-union": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ="
+ },
+ "array-equal": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
+ "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM="
+ },
+ "array-filter": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz",
+ "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw="
+ },
+ "array-find-index": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
+ "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E="
+ },
+ "array-flatten": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.1.tgz",
+ "integrity": "sha1-Qmu52oQJDBg42BLIFQryCoMx4pY="
+ },
+ "array-includes": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz",
+ "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=",
+ "requires": {
+ "define-properties": "^1.1.2",
+ "es-abstract": "^1.7.0"
+ }
+ },
+ "array-map": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz",
+ "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI="
+ },
+ "array-reduce": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz",
+ "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys="
+ },
+ "array-union": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
+ "requires": {
+ "array-uniq": "^1.0.1"
+ }
+ },
+ "array-uniq": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
+ "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY="
+ },
+ "array-unique": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg="
+ },
+ "arrify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+ "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0="
+ },
+ "asap": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
+ "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
+ },
+ "asn1": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
+ "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y="
+ },
+ "asn1.js": {
+ "version": "4.10.1",
+ "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz",
+ "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==",
+ "requires": {
+ "bn.js": "^4.0.0",
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0"
+ }
+ },
+ "assert": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz",
+ "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=",
+ "requires": {
+ "util": "0.10.3"
+ },
+ "dependencies": {
+ "inherits": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+ "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
+ },
+ "util": {
+ "version": "0.10.3",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
+ "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
+ "requires": {
+ "inherits": "2.0.1"
+ }
+ }
+ }
+ },
+ "assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+ },
+ "assign-symbols": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c="
+ },
+ "ast-types-flow": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
+ "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0="
+ },
+ "async": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz",
+ "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==",
+ "requires": {
+ "lodash": "^4.17.10"
+ }
+ },
+ "async-each": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz",
+ "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0="
+ },
+ "asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
+ },
+ "atob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz",
+ "integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio="
+ },
+ "autoprefixer": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-7.1.6.tgz",
+ "integrity": "sha512-C9yv/UF3X+eJTi/zvfxuyfxmLibYrntpF3qoJYrMeQwgUJOZrZvpJiMG2FMQ3qnhWtF/be4pYONBBw95ZGe3vA==",
+ "requires": {
+ "browserslist": "^2.5.1",
+ "caniuse-lite": "^1.0.30000748",
+ "normalize-range": "^0.1.2",
+ "num2fraction": "^1.2.2",
+ "postcss": "^6.0.13",
+ "postcss-value-parser": "^3.2.3"
+ }
+ },
+ "aws-sign2": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
+ },
+ "aws4": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz",
+ "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w=="
+ },
+ "axobject-query": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-0.1.0.tgz",
+ "integrity": "sha1-YvWdvFnJ+SQnWco0mWDnov48NsA=",
+ "requires": {
+ "ast-types-flow": "0.0.7"
+ }
+ },
+ "babel-code-frame": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
+ "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
+ "requires": {
+ "chalk": "^1.1.3",
+ "esutils": "^2.0.2",
+ "js-tokens": "^3.0.2"
+ }
+ },
+ "babel-core": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz",
+ "integrity": "sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g=",
+ "requires": {
+ "babel-code-frame": "^6.26.0",
+ "babel-generator": "^6.26.0",
+ "babel-helpers": "^6.24.1",
+ "babel-messages": "^6.23.0",
+ "babel-register": "^6.26.0",
+ "babel-runtime": "^6.26.0",
+ "babel-template": "^6.26.0",
+ "babel-traverse": "^6.26.0",
+ "babel-types": "^6.26.0",
+ "babylon": "^6.18.0",
+ "convert-source-map": "^1.5.0",
+ "debug": "^2.6.8",
+ "json5": "^0.5.1",
+ "lodash": "^4.17.4",
+ "minimatch": "^3.0.4",
+ "path-is-absolute": "^1.0.1",
+ "private": "^0.1.7",
+ "slash": "^1.0.0",
+ "source-map": "^0.5.6"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ }
+ }
+ },
+ "babel-eslint": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-7.2.3.tgz",
+ "integrity": "sha1-sv4tgBJkcPXBlELcdXJTqJdxCCc=",
+ "requires": {
+ "babel-code-frame": "^6.22.0",
+ "babel-traverse": "^6.23.1",
+ "babel-types": "^6.23.0",
+ "babylon": "^6.17.0"
+ }
+ },
+ "babel-generator": {
+ "version": "6.26.1",
+ "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz",
+ "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==",
+ "requires": {
+ "babel-messages": "^6.23.0",
+ "babel-runtime": "^6.26.0",
+ "babel-types": "^6.26.0",
+ "detect-indent": "^4.0.0",
+ "jsesc": "^1.3.0",
+ "lodash": "^4.17.4",
+ "source-map": "^0.5.7",
+ "trim-right": "^1.0.1"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ }
+ }
+ },
+ "babel-helper-builder-binary-assignment-operator-visitor": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz",
+ "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=",
+ "requires": {
+ "babel-helper-explode-assignable-expression": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "babel-helper-builder-react-jsx": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz",
+ "integrity": "sha1-Of+DE7dci2Xc7/HzHTg+D/KkCKA=",
+ "requires": {
+ "babel-runtime": "^6.26.0",
+ "babel-types": "^6.26.0",
+ "esutils": "^2.0.2"
+ }
+ },
+ "babel-helper-call-delegate": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz",
+ "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=",
+ "requires": {
+ "babel-helper-hoist-variables": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-traverse": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "babel-helper-define-map": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz",
+ "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=",
+ "requires": {
+ "babel-helper-function-name": "^6.24.1",
+ "babel-runtime": "^6.26.0",
+ "babel-types": "^6.26.0",
+ "lodash": "^4.17.4"
+ }
+ },
+ "babel-helper-explode-assignable-expression": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz",
+ "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=",
+ "requires": {
+ "babel-runtime": "^6.22.0",
+ "babel-traverse": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "babel-helper-function-name": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz",
+ "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=",
+ "requires": {
+ "babel-helper-get-function-arity": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1",
+ "babel-traverse": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "babel-helper-get-function-arity": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz",
+ "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=",
+ "requires": {
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "babel-helper-hoist-variables": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz",
+ "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=",
+ "requires": {
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "babel-helper-optimise-call-expression": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz",
+ "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=",
+ "requires": {
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "babel-helper-regex": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz",
+ "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=",
+ "requires": {
+ "babel-runtime": "^6.26.0",
+ "babel-types": "^6.26.0",
+ "lodash": "^4.17.4"
+ }
+ },
+ "babel-helper-remap-async-to-generator": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz",
+ "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=",
+ "requires": {
+ "babel-helper-function-name": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1",
+ "babel-traverse": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "babel-helper-replace-supers": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz",
+ "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=",
+ "requires": {
+ "babel-helper-optimise-call-expression": "^6.24.1",
+ "babel-messages": "^6.23.0",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1",
+ "babel-traverse": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "babel-helpers": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz",
+ "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=",
+ "requires": {
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1"
+ }
+ },
+ "babel-jest": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-20.0.3.tgz",
+ "integrity": "sha1-5KA7E9wQOJ4UD8ZF0J/8TO0wFnE=",
+ "requires": {
+ "babel-core": "^6.0.0",
+ "babel-plugin-istanbul": "^4.0.0",
+ "babel-preset-jest": "^20.0.3"
+ }
+ },
+ "babel-loader": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-7.1.2.tgz",
+ "integrity": "sha512-jRwlFbINAeyDStqK6Dd5YuY0k5YuzQUvlz2ZamuXrXmxav3pNqe9vfJ402+2G+OmlJSXxCOpB6Uz0INM7RQe2A==",
+ "requires": {
+ "find-cache-dir": "^1.0.0",
+ "loader-utils": "^1.0.2",
+ "mkdirp": "^0.5.1"
+ }
+ },
+ "babel-messages": {
+ "version": "6.23.0",
+ "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
+ "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=",
+ "requires": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "babel-plugin-check-es2015-constants": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz",
+ "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=",
+ "requires": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "babel-plugin-dynamic-import-node": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-1.1.0.tgz",
+ "integrity": "sha512-tTfZbM9Ecwj3GK50mnPrUpinTwA4xXmDiQGCk/aBYbvl1+X8YqldK86wZ1owVJ4u3mrKbRlXMma80J18qwiaTQ==",
+ "requires": {
+ "babel-plugin-syntax-dynamic-import": "^6.18.0",
+ "babel-template": "^6.26.0",
+ "babel-types": "^6.26.0"
+ }
+ },
+ "babel-plugin-istanbul": {
+ "version": "4.1.6",
+ "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz",
+ "integrity": "sha512-PWP9FQ1AhZhS01T/4qLSKoHGY/xvkZdVBGlKM/HuxxS3+sC66HhTNR7+MpbO/so/cz/wY94MeSWJuP1hXIPfwQ==",
+ "requires": {
+ "babel-plugin-syntax-object-rest-spread": "^6.13.0",
+ "find-up": "^2.1.0",
+ "istanbul-lib-instrument": "^1.10.1",
+ "test-exclude": "^4.2.1"
+ }
+ },
+ "babel-plugin-jest-hoist": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-20.0.3.tgz",
+ "integrity": "sha1-r+3IU70/jcNUjqZx++adA8wsF2c="
+ },
+ "babel-plugin-syntax-async-functions": {
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz",
+ "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU="
+ },
+ "babel-plugin-syntax-class-properties": {
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz",
+ "integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94="
+ },
+ "babel-plugin-syntax-dynamic-import": {
+ "version": "6.18.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz",
+ "integrity": "sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo="
+ },
+ "babel-plugin-syntax-exponentiation-operator": {
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz",
+ "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4="
+ },
+ "babel-plugin-syntax-flow": {
+ "version": "6.18.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz",
+ "integrity": "sha1-TDqyCiryaqIM0lmVw5jE63AxDI0="
+ },
+ "babel-plugin-syntax-jsx": {
+ "version": "6.18.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz",
+ "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY="
+ },
+ "babel-plugin-syntax-object-rest-spread": {
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
+ "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U="
+ },
+ "babel-plugin-syntax-trailing-function-commas": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz",
+ "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM="
+ },
+ "babel-plugin-transform-async-to-generator": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz",
+ "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=",
+ "requires": {
+ "babel-helper-remap-async-to-generator": "^6.24.1",
+ "babel-plugin-syntax-async-functions": "^6.8.0",
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "babel-plugin-transform-class-properties": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz",
+ "integrity": "sha1-anl2PqYdM9NvN7YRqp3vgagbRqw=",
+ "requires": {
+ "babel-helper-function-name": "^6.24.1",
+ "babel-plugin-syntax-class-properties": "^6.8.0",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1"
+ }
+ },
+ "babel-plugin-transform-es2015-arrow-functions": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz",
+ "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=",
+ "requires": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "babel-plugin-transform-es2015-block-scoped-functions": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz",
+ "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=",
+ "requires": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "babel-plugin-transform-es2015-block-scoping": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz",
+ "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=",
+ "requires": {
+ "babel-runtime": "^6.26.0",
+ "babel-template": "^6.26.0",
+ "babel-traverse": "^6.26.0",
+ "babel-types": "^6.26.0",
+ "lodash": "^4.17.4"
+ }
+ },
+ "babel-plugin-transform-es2015-classes": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz",
+ "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=",
+ "requires": {
+ "babel-helper-define-map": "^6.24.1",
+ "babel-helper-function-name": "^6.24.1",
+ "babel-helper-optimise-call-expression": "^6.24.1",
+ "babel-helper-replace-supers": "^6.24.1",
+ "babel-messages": "^6.23.0",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1",
+ "babel-traverse": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "babel-plugin-transform-es2015-computed-properties": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz",
+ "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=",
+ "requires": {
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1"
+ }
+ },
+ "babel-plugin-transform-es2015-destructuring": {
+ "version": "6.23.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz",
+ "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=",
+ "requires": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "babel-plugin-transform-es2015-duplicate-keys": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz",
+ "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=",
+ "requires": {
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "babel-plugin-transform-es2015-for-of": {
+ "version": "6.23.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz",
+ "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=",
+ "requires": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "babel-plugin-transform-es2015-function-name": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz",
+ "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=",
+ "requires": {
+ "babel-helper-function-name": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "babel-plugin-transform-es2015-literals": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz",
+ "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=",
+ "requires": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "babel-plugin-transform-es2015-modules-amd": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz",
+ "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=",
+ "requires": {
+ "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1"
+ }
+ },
+ "babel-plugin-transform-es2015-modules-commonjs": {
+ "version": "6.26.2",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz",
+ "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==",
+ "requires": {
+ "babel-plugin-transform-strict-mode": "^6.24.1",
+ "babel-runtime": "^6.26.0",
+ "babel-template": "^6.26.0",
+ "babel-types": "^6.26.0"
+ }
+ },
+ "babel-plugin-transform-es2015-modules-systemjs": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz",
+ "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=",
+ "requires": {
+ "babel-helper-hoist-variables": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1"
+ }
+ },
+ "babel-plugin-transform-es2015-modules-umd": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz",
+ "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=",
+ "requires": {
+ "babel-plugin-transform-es2015-modules-amd": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1"
+ }
+ },
+ "babel-plugin-transform-es2015-object-super": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz",
+ "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=",
+ "requires": {
+ "babel-helper-replace-supers": "^6.24.1",
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "babel-plugin-transform-es2015-parameters": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz",
+ "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=",
+ "requires": {
+ "babel-helper-call-delegate": "^6.24.1",
+ "babel-helper-get-function-arity": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1",
+ "babel-traverse": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "babel-plugin-transform-es2015-shorthand-properties": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz",
+ "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=",
+ "requires": {
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "babel-plugin-transform-es2015-spread": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz",
+ "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=",
+ "requires": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "babel-plugin-transform-es2015-sticky-regex": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz",
+ "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=",
+ "requires": {
+ "babel-helper-regex": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "babel-plugin-transform-es2015-template-literals": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz",
+ "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=",
+ "requires": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "babel-plugin-transform-es2015-typeof-symbol": {
+ "version": "6.23.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz",
+ "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=",
+ "requires": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "babel-plugin-transform-es2015-unicode-regex": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz",
+ "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=",
+ "requires": {
+ "babel-helper-regex": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "regexpu-core": "^2.0.0"
+ }
+ },
+ "babel-plugin-transform-exponentiation-operator": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz",
+ "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=",
+ "requires": {
+ "babel-helper-builder-binary-assignment-operator-visitor": "^6.24.1",
+ "babel-plugin-syntax-exponentiation-operator": "^6.8.0",
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "babel-plugin-transform-flow-strip-types": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz",
+ "integrity": "sha1-hMtnKTXUNxT9wyvOhFaNh0Qc988=",
+ "requires": {
+ "babel-plugin-syntax-flow": "^6.18.0",
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "babel-plugin-transform-object-rest-spread": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz",
+ "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=",
+ "requires": {
+ "babel-plugin-syntax-object-rest-spread": "^6.8.0",
+ "babel-runtime": "^6.26.0"
+ }
+ },
+ "babel-plugin-transform-react-constant-elements": {
+ "version": "6.23.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-constant-elements/-/babel-plugin-transform-react-constant-elements-6.23.0.tgz",
+ "integrity": "sha1-LxGb9NLN1F65uqrldAU8YE9hR90=",
+ "requires": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "babel-plugin-transform-react-display-name": {
+ "version": "6.25.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz",
+ "integrity": "sha1-Z+K/Hx6ck6sI25Z5LgU5K/LMKNE=",
+ "requires": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "babel-plugin-transform-react-jsx": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz",
+ "integrity": "sha1-hAoCjn30YN/DotKfDA2R9jduZqM=",
+ "requires": {
+ "babel-helper-builder-react-jsx": "^6.24.1",
+ "babel-plugin-syntax-jsx": "^6.8.0",
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "babel-plugin-transform-react-jsx-self": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz",
+ "integrity": "sha1-322AqdomEqEh5t3XVYvL7PBuY24=",
+ "requires": {
+ "babel-plugin-syntax-jsx": "^6.8.0",
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "babel-plugin-transform-react-jsx-source": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz",
+ "integrity": "sha1-ZqwSFT9c0tF7PBkmj0vwGX9E7NY=",
+ "requires": {
+ "babel-plugin-syntax-jsx": "^6.8.0",
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "babel-plugin-transform-regenerator": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz",
+ "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=",
+ "requires": {
+ "regenerator-transform": "^0.10.0"
+ }
+ },
+ "babel-plugin-transform-runtime": {
+ "version": "6.23.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.23.0.tgz",
+ "integrity": "sha1-iEkNRGUC6puOfvsP4J7E2ZR5se4=",
+ "requires": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "babel-plugin-transform-strict-mode": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz",
+ "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=",
+ "requires": {
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "babel-preset-env": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.6.1.tgz",
+ "integrity": "sha512-W6VIyA6Ch9ePMI7VptNn2wBM6dbG0eSz25HEiL40nQXCsXGTGZSTZu1Iap+cj3Q0S5a7T9+529l/5Bkvd+afNA==",
+ "requires": {
+ "babel-plugin-check-es2015-constants": "^6.22.0",
+ "babel-plugin-syntax-trailing-function-commas": "^6.22.0",
+ "babel-plugin-transform-async-to-generator": "^6.22.0",
+ "babel-plugin-transform-es2015-arrow-functions": "^6.22.0",
+ "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0",
+ "babel-plugin-transform-es2015-block-scoping": "^6.23.0",
+ "babel-plugin-transform-es2015-classes": "^6.23.0",
+ "babel-plugin-transform-es2015-computed-properties": "^6.22.0",
+ "babel-plugin-transform-es2015-destructuring": "^6.23.0",
+ "babel-plugin-transform-es2015-duplicate-keys": "^6.22.0",
+ "babel-plugin-transform-es2015-for-of": "^6.23.0",
+ "babel-plugin-transform-es2015-function-name": "^6.22.0",
+ "babel-plugin-transform-es2015-literals": "^6.22.0",
+ "babel-plugin-transform-es2015-modules-amd": "^6.22.0",
+ "babel-plugin-transform-es2015-modules-commonjs": "^6.23.0",
+ "babel-plugin-transform-es2015-modules-systemjs": "^6.23.0",
+ "babel-plugin-transform-es2015-modules-umd": "^6.23.0",
+ "babel-plugin-transform-es2015-object-super": "^6.22.0",
+ "babel-plugin-transform-es2015-parameters": "^6.23.0",
+ "babel-plugin-transform-es2015-shorthand-properties": "^6.22.0",
+ "babel-plugin-transform-es2015-spread": "^6.22.0",
+ "babel-plugin-transform-es2015-sticky-regex": "^6.22.0",
+ "babel-plugin-transform-es2015-template-literals": "^6.22.0",
+ "babel-plugin-transform-es2015-typeof-symbol": "^6.23.0",
+ "babel-plugin-transform-es2015-unicode-regex": "^6.22.0",
+ "babel-plugin-transform-exponentiation-operator": "^6.22.0",
+ "babel-plugin-transform-regenerator": "^6.22.0",
+ "browserslist": "^2.1.2",
+ "invariant": "^2.2.2",
+ "semver": "^5.3.0"
+ }
+ },
+ "babel-preset-flow": {
+ "version": "6.23.0",
+ "resolved": "https://registry.npmjs.org/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz",
+ "integrity": "sha1-5xIYiHCFrpoktb5Baa/7WZgWxJ0=",
+ "requires": {
+ "babel-plugin-transform-flow-strip-types": "^6.22.0"
+ }
+ },
+ "babel-preset-jest": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-20.0.3.tgz",
+ "integrity": "sha1-y6yq3stdaJyh4d4TYOv8ZoYsF4o=",
+ "requires": {
+ "babel-plugin-jest-hoist": "^20.0.3"
+ }
+ },
+ "babel-preset-react": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-preset-react/-/babel-preset-react-6.24.1.tgz",
+ "integrity": "sha1-umnfrqRfw+xjm2pOzqbhdwLJE4A=",
+ "requires": {
+ "babel-plugin-syntax-jsx": "^6.3.13",
+ "babel-plugin-transform-react-display-name": "^6.23.0",
+ "babel-plugin-transform-react-jsx": "^6.24.1",
+ "babel-plugin-transform-react-jsx-self": "^6.22.0",
+ "babel-plugin-transform-react-jsx-source": "^6.22.0",
+ "babel-preset-flow": "^6.23.0"
+ }
+ },
+ "babel-preset-react-app": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-3.1.1.tgz",
+ "integrity": "sha512-9fRHopNaGL5ScRZdPSoyxRaABKmkS2fx0HUJ5Yphan5G8QDFD7lETsPyY7El6b7YPT3sNrw9gfrWzl4/LsJcfA==",
+ "requires": {
+ "babel-plugin-dynamic-import-node": "1.1.0",
+ "babel-plugin-syntax-dynamic-import": "6.18.0",
+ "babel-plugin-transform-class-properties": "6.24.1",
+ "babel-plugin-transform-es2015-destructuring": "6.23.0",
+ "babel-plugin-transform-object-rest-spread": "6.26.0",
+ "babel-plugin-transform-react-constant-elements": "6.23.0",
+ "babel-plugin-transform-react-jsx": "6.24.1",
+ "babel-plugin-transform-react-jsx-self": "6.22.0",
+ "babel-plugin-transform-react-jsx-source": "6.22.0",
+ "babel-plugin-transform-regenerator": "6.26.0",
+ "babel-plugin-transform-runtime": "6.23.0",
+ "babel-preset-env": "1.6.1",
+ "babel-preset-react": "6.24.1"
+ }
+ },
+ "babel-register": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz",
+ "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=",
+ "requires": {
+ "babel-core": "^6.26.0",
+ "babel-runtime": "^6.26.0",
+ "core-js": "^2.5.0",
+ "home-or-tmp": "^2.0.0",
+ "lodash": "^4.17.4",
+ "mkdirp": "^0.5.1",
+ "source-map-support": "^0.4.15"
+ },
+ "dependencies": {
+ "core-js": {
+ "version": "2.5.7",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz",
+ "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw=="
+ }
+ }
+ },
+ "babel-runtime": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+ "requires": {
+ "core-js": "^2.4.0",
+ "regenerator-runtime": "^0.11.0"
+ },
+ "dependencies": {
+ "core-js": {
+ "version": "2.5.7",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz",
+ "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw=="
+ }
+ }
+ },
+ "babel-template": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz",
+ "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=",
+ "requires": {
+ "babel-runtime": "^6.26.0",
+ "babel-traverse": "^6.26.0",
+ "babel-types": "^6.26.0",
+ "babylon": "^6.18.0",
+ "lodash": "^4.17.4"
+ }
+ },
+ "babel-traverse": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
+ "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=",
+ "requires": {
+ "babel-code-frame": "^6.26.0",
+ "babel-messages": "^6.23.0",
+ "babel-runtime": "^6.26.0",
+ "babel-types": "^6.26.0",
+ "babylon": "^6.18.0",
+ "debug": "^2.6.8",
+ "globals": "^9.18.0",
+ "invariant": "^2.2.2",
+ "lodash": "^4.17.4"
+ }
+ },
+ "babel-types": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
+ "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=",
+ "requires": {
+ "babel-runtime": "^6.26.0",
+ "esutils": "^2.0.2",
+ "lodash": "^4.17.4",
+ "to-fast-properties": "^1.0.3"
+ }
+ },
+ "babylon": {
+ "version": "6.18.0",
+ "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
+ "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ=="
+ },
+ "balanced-match": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+ },
+ "base": {
+ "version": "0.11.2",
+ "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+ "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+ "requires": {
+ "cache-base": "^1.0.1",
+ "class-utils": "^0.3.5",
+ "component-emitter": "^1.2.1",
+ "define-property": "^1.0.0",
+ "isobject": "^3.0.1",
+ "mixin-deep": "^1.2.0",
+ "pascalcase": "^0.1.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "base64-js": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz",
+ "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw=="
+ },
+ "batch": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
+ "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY="
+ },
+ "bcrypt-pbkdf": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
+ "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=",
+ "optional": true,
+ "requires": {
+ "tweetnacl": "^0.14.3"
+ }
+ },
+ "big.js": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz",
+ "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q=="
+ },
+ "binary-extensions": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz",
+ "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU="
+ },
+ "bluebird": {
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
+ "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA=="
+ },
+ "bn.js": {
+ "version": "4.11.8",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
+ "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA=="
+ },
+ "body-parser": {
+ "version": "1.18.2",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz",
+ "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=",
+ "requires": {
+ "bytes": "3.0.0",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "~1.1.1",
+ "http-errors": "~1.6.2",
+ "iconv-lite": "0.4.19",
+ "on-finished": "~2.3.0",
+ "qs": "6.5.1",
+ "raw-body": "2.3.2",
+ "type-is": "~1.6.15"
+ },
+ "dependencies": {
+ "iconv-lite": {
+ "version": "0.4.19",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
+ "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ=="
+ },
+ "qs": {
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
+ "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A=="
+ }
+ }
+ },
+ "bonjour": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz",
+ "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=",
+ "requires": {
+ "array-flatten": "^2.1.0",
+ "deep-equal": "^1.0.1",
+ "dns-equal": "^1.0.0",
+ "dns-txt": "^2.0.2",
+ "multicast-dns": "^6.0.1",
+ "multicast-dns-service-types": "^1.1.0"
+ }
+ },
+ "boolbase": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+ "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
+ },
+ "bootstrap": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.1.3.tgz",
+ "integrity": "sha512-rDFIzgXcof0jDyjNosjv4Sno77X4KuPeFxG2XZZv1/Kc8DRVGVADdoQyyOVDwPqL36DDmtCQbrpMCqvpPLJQ0w=="
+ },
+ "boxen": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz",
+ "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==",
+ "requires": {
+ "ansi-align": "^2.0.0",
+ "camelcase": "^4.0.0",
+ "chalk": "^2.0.1",
+ "cli-boxes": "^1.0.0",
+ "string-width": "^2.0.0",
+ "term-size": "^1.2.0",
+ "widest-line": "^2.0.0"
+ },
+ "dependencies": {
+ "camelcase": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
+ "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0="
+ },
+ "chalk": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
+ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
+ }
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "braces": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+ "requires": {
+ "arr-flatten": "^1.1.0",
+ "array-unique": "^0.3.2",
+ "extend-shallow": "^2.0.1",
+ "fill-range": "^4.0.0",
+ "isobject": "^3.0.1",
+ "repeat-element": "^1.1.2",
+ "snapdragon": "^0.8.1",
+ "snapdragon-node": "^2.0.1",
+ "split-string": "^3.0.2",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "brorand": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
+ "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8="
+ },
+ "browser-resolve": {
+ "version": "1.11.2",
+ "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz",
+ "integrity": "sha1-j/CbCixCFxihBRwmCzLkj0QpOM4=",
+ "requires": {
+ "resolve": "1.1.7"
+ },
+ "dependencies": {
+ "resolve": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
+ "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs="
+ }
+ }
+ },
+ "browserify-aes": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
+ "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
+ "requires": {
+ "buffer-xor": "^1.0.3",
+ "cipher-base": "^1.0.0",
+ "create-hash": "^1.1.0",
+ "evp_bytestokey": "^1.0.3",
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "browserify-cipher": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz",
+ "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==",
+ "requires": {
+ "browserify-aes": "^1.0.4",
+ "browserify-des": "^1.0.0",
+ "evp_bytestokey": "^1.0.0"
+ }
+ },
+ "browserify-des": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.1.tgz",
+ "integrity": "sha512-zy0Cobe3hhgpiOM32Tj7KQ3Vl91m0njwsjzZQK1L+JDf11dzP9qIvjreVinsvXrgfjhStXwUWAEpB9D7Gwmayw==",
+ "requires": {
+ "cipher-base": "^1.0.1",
+ "des.js": "^1.0.0",
+ "inherits": "^2.0.1"
+ }
+ },
+ "browserify-rsa": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
+ "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
+ "requires": {
+ "bn.js": "^4.1.0",
+ "randombytes": "^2.0.1"
+ }
+ },
+ "browserify-sign": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz",
+ "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=",
+ "requires": {
+ "bn.js": "^4.1.1",
+ "browserify-rsa": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "create-hmac": "^1.1.2",
+ "elliptic": "^6.0.0",
+ "inherits": "^2.0.1",
+ "parse-asn1": "^5.0.0"
+ }
+ },
+ "browserify-zlib": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
+ "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
+ "requires": {
+ "pako": "~1.0.5"
+ }
+ },
+ "browserslist": {
+ "version": "2.11.3",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-2.11.3.tgz",
+ "integrity": "sha512-yWu5cXT7Av6mVwzWc8lMsJMHWn4xyjSuGYi4IozbVTLUOEYPSagUB8kiMDUHA1fS3zjr8nkxkn9jdvug4BBRmA==",
+ "requires": {
+ "caniuse-lite": "^1.0.30000792",
+ "electron-to-chromium": "^1.3.30"
+ }
+ },
+ "bser": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz",
+ "integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=",
+ "requires": {
+ "node-int64": "^0.4.0"
+ }
+ },
+ "buffer": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
+ "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
+ "requires": {
+ "base64-js": "^1.0.2",
+ "ieee754": "^1.1.4",
+ "isarray": "^1.0.0"
+ }
+ },
+ "buffer-from": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz",
+ "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ=="
+ },
+ "buffer-indexof": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz",
+ "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g=="
+ },
+ "buffer-xor": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
+ "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk="
+ },
+ "builtin-modules": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
+ "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8="
+ },
+ "builtin-status-codes": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
+ "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug="
+ },
+ "bytes": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
+ "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
+ },
+ "cache-base": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+ "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+ "requires": {
+ "collection-visit": "^1.0.0",
+ "component-emitter": "^1.2.1",
+ "get-value": "^2.0.6",
+ "has-value": "^1.0.0",
+ "isobject": "^3.0.1",
+ "set-value": "^2.0.0",
+ "to-object-path": "^0.3.0",
+ "union-value": "^1.0.0",
+ "unset-value": "^1.0.0"
+ }
+ },
+ "caller-path": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz",
+ "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=",
+ "requires": {
+ "callsites": "^0.2.0"
+ }
+ },
+ "callsites": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz",
+ "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo="
+ },
+ "camel-case": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz",
+ "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=",
+ "requires": {
+ "no-case": "^2.2.0",
+ "upper-case": "^1.1.1"
+ }
+ },
+ "camelcase": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
+ "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk="
+ },
+ "camelcase-keys": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
+ "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
+ "requires": {
+ "camelcase": "^2.0.0",
+ "map-obj": "^1.0.0"
+ },
+ "dependencies": {
+ "camelcase": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
+ "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8="
+ }
+ }
+ },
+ "caniuse-api": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.6.1.tgz",
+ "integrity": "sha1-tTTnxzTE+B7F++isoq0kNUuWLGw=",
+ "requires": {
+ "browserslist": "^1.3.6",
+ "caniuse-db": "^1.0.30000529",
+ "lodash.memoize": "^4.1.2",
+ "lodash.uniq": "^4.5.0"
+ },
+ "dependencies": {
+ "browserslist": {
+ "version": "1.7.7",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz",
+ "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=",
+ "requires": {
+ "caniuse-db": "^1.0.30000639",
+ "electron-to-chromium": "^1.2.7"
+ }
+ }
+ }
+ },
+ "caniuse-db": {
+ "version": "1.0.30000853",
+ "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000853.tgz",
+ "integrity": "sha1-MpAafWuTqH1Z8Iqu5H6o/27JD98="
+ },
+ "caniuse-lite": {
+ "version": "1.0.30000853",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000853.tgz",
+ "integrity": "sha512-vMrE8BED4MJC9IhDJKP8ok6bJUfn5+YHvxwXMYfiPqQOJ3r2B9ihcArlUnXu6yPWf7b3jHqiEBwXZEbrbiFUqg=="
+ },
+ "capture-stack-trace": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz",
+ "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0="
+ },
+ "case-sensitive-paths-webpack-plugin": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.1.1.tgz",
+ "integrity": "sha1-PSnO2MHxJL9vU4Rvs/WJRzH9yQk="
+ },
+ "caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
+ },
+ "center-align": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
+ "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=",
+ "requires": {
+ "align-text": "^0.1.3",
+ "lazy-cache": "^1.0.3"
+ }
+ },
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
+ },
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
+ }
+ }
+ },
+ "chardet": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz",
+ "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I="
+ },
+ "chokidar": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.3.tgz",
+ "integrity": "sha512-zW8iXYZtXMx4kux/nuZVXjkLP+CyIK5Al5FHnj1OgTKGZfp4Oy6/ymtMSKFv3GD8DviEmUPmJg9eFdJ/JzudMg==",
+ "requires": {
+ "anymatch": "^2.0.0",
+ "async-each": "^1.0.0",
+ "braces": "^2.3.0",
+ "fsevents": "^1.1.2",
+ "glob-parent": "^3.1.0",
+ "inherits": "^2.0.1",
+ "is-binary-path": "^1.0.0",
+ "is-glob": "^4.0.0",
+ "normalize-path": "^2.1.1",
+ "path-is-absolute": "^1.0.0",
+ "readdirp": "^2.0.0",
+ "upath": "^1.0.0"
+ },
+ "dependencies": {
+ "anymatch": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
+ "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
+ "requires": {
+ "micromatch": "^3.1.4",
+ "normalize-path": "^2.1.1"
+ }
+ },
+ "glob-parent": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
+ "requires": {
+ "is-glob": "^3.1.0",
+ "path-dirname": "^1.0.0"
+ },
+ "dependencies": {
+ "is-glob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+ "requires": {
+ "is-extglob": "^2.1.0"
+ }
+ }
+ }
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
+ },
+ "is-glob": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz",
+ "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=",
+ "requires": {
+ "is-extglob": "^2.1.1"
+ }
+ }
+ }
+ },
+ "ci-info": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.1.3.tgz",
+ "integrity": "sha512-SK/846h/Rcy8q9Z9CAwGBLfCJ6EkjJWdpelWDufQpqVDYq2Wnnv8zlSO6AMQap02jvhVruKKpEtQOufo3pFhLg=="
+ },
+ "cipher-base": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
+ "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
+ "requires": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "circular-json": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
+ "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A=="
+ },
+ "clap": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz",
+ "integrity": "sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==",
+ "requires": {
+ "chalk": "^1.1.3"
+ }
+ },
+ "class-utils": {
+ "version": "0.3.6",
+ "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+ "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+ "requires": {
+ "arr-union": "^3.1.0",
+ "define-property": "^0.2.5",
+ "isobject": "^3.0.0",
+ "static-extend": "^0.1.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ }
+ }
+ },
+ "clean-css": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.1.11.tgz",
+ "integrity": "sha1-Ls3xRaujj1R0DybO/Q/z4D4SXWo=",
+ "requires": {
+ "source-map": "0.5.x"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ }
+ }
+ },
+ "cli-boxes": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz",
+ "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM="
+ },
+ "cli-cursor": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
+ "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
+ "requires": {
+ "restore-cursor": "^2.0.0"
+ }
+ },
+ "cli-width": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
+ "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk="
+ },
+ "cliui": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
+ "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=",
+ "requires": {
+ "center-align": "^0.1.1",
+ "right-align": "^0.1.1",
+ "wordwrap": "0.0.2"
+ },
+ "dependencies": {
+ "wordwrap": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
+ "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8="
+ }
+ }
+ },
+ "clone": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
+ "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4="
+ },
+ "co": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
+ "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
+ },
+ "coa": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/coa/-/coa-1.0.4.tgz",
+ "integrity": "sha1-qe8VNmDWqGqL3sAomlxoTSF0Mv0=",
+ "requires": {
+ "q": "^1.1.2"
+ }
+ },
+ "code-point-at": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
+ },
+ "collection-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
+ "requires": {
+ "map-visit": "^1.0.0",
+ "object-visit": "^1.0.0"
+ }
+ },
+ "color": {
+ "version": "0.11.4",
+ "resolved": "https://registry.npmjs.org/color/-/color-0.11.4.tgz",
+ "integrity": "sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q=",
+ "requires": {
+ "clone": "^1.0.2",
+ "color-convert": "^1.3.0",
+ "color-string": "^0.3.0"
+ }
+ },
+ "color-convert": {
+ "version": "1.9.2",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz",
+ "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==",
+ "requires": {
+ "color-name": "1.1.1"
+ }
+ },
+ "color-name": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz",
+ "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok="
+ },
+ "color-string": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz",
+ "integrity": "sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=",
+ "requires": {
+ "color-name": "^1.0.0"
+ }
+ },
+ "colormin": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/colormin/-/colormin-1.1.2.tgz",
+ "integrity": "sha1-6i90IKcrlogaOKrlnsEkpvcpgTM=",
+ "requires": {
+ "color": "^0.11.0",
+ "css-color-names": "0.0.4",
+ "has": "^1.0.1"
+ }
+ },
+ "colors": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
+ "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM="
+ },
+ "combined-stream": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
+ "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
+ "requires": {
+ "delayed-stream": "~1.0.0"
+ }
+ },
+ "commander": {
+ "version": "2.15.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
+ "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag=="
+ },
+ "commondir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs="
+ },
+ "compare-versions": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.3.0.tgz",
+ "integrity": "sha512-MAAAIOdi2s4Gl6rZ76PNcUa9IOYB+5ICdT41o5uMRf09aEu/F9RK+qhe8RjXNPwcTjGV7KU7h2P/fljThFVqyQ=="
+ },
+ "component-emitter": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
+ "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
+ },
+ "compressible": {
+ "version": "2.0.14",
+ "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.14.tgz",
+ "integrity": "sha1-MmxfUH+7BV9UEWeCuWmoG2einac=",
+ "requires": {
+ "mime-db": ">= 1.34.0 < 2"
+ },
+ "dependencies": {
+ "mime-db": {
+ "version": "1.34.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.34.0.tgz",
+ "integrity": "sha1-RS0Oz/XDA0am3B5kseruDTcZ/5o="
+ }
+ }
+ },
+ "compression": {
+ "version": "1.7.2",
+ "resolved": "http://registry.npmjs.org/compression/-/compression-1.7.2.tgz",
+ "integrity": "sha1-qv+81qr4VLROuygDU9WtFlH1mmk=",
+ "requires": {
+ "accepts": "~1.3.4",
+ "bytes": "3.0.0",
+ "compressible": "~2.0.13",
+ "debug": "2.6.9",
+ "on-headers": "~1.0.1",
+ "safe-buffer": "5.1.1",
+ "vary": "~1.1.2"
+ },
+ "dependencies": {
+ "safe-buffer": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
+ "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
+ }
+ }
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+ },
+ "concat-stream": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.2.2",
+ "typedarray": "^0.0.6"
+ }
+ },
+ "configstore": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz",
+ "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==",
+ "requires": {
+ "dot-prop": "^4.1.0",
+ "graceful-fs": "^4.1.2",
+ "make-dir": "^1.0.0",
+ "unique-string": "^1.0.0",
+ "write-file-atomic": "^2.0.0",
+ "xdg-basedir": "^3.0.0"
+ }
+ },
+ "connect-history-api-fallback": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz",
+ "integrity": "sha1-sGhzk0vF40T+9hGhlqb6rgruAVo="
+ },
+ "console-browserify": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
+ "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=",
+ "requires": {
+ "date-now": "^0.1.4"
+ }
+ },
+ "constants-browserify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
+ "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U="
+ },
+ "contains-path": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz",
+ "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo="
+ },
+ "content-disposition": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
+ "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ="
+ },
+ "content-type": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
+ },
+ "content-type-parser": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.2.tgz",
+ "integrity": "sha512-lM4l4CnMEwOLHAHr/P6MEZwZFPJFtAAKgL6pogbXmVZggIqXhdB6RbBtPOTsw2FcXwYhehRGERJmRrjOiIB8pQ=="
+ },
+ "convert-source-map": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz",
+ "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU="
+ },
+ "cookie": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
+ "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
+ },
+ "cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+ },
+ "copy-descriptor": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40="
+ },
+ "core-js": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
+ "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+ },
+ "cosmiconfig": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz",
+ "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==",
+ "requires": {
+ "is-directory": "^0.3.1",
+ "js-yaml": "^3.4.3",
+ "minimist": "^1.2.0",
+ "object-assign": "^4.1.0",
+ "os-homedir": "^1.0.1",
+ "parse-json": "^2.2.0",
+ "require-from-string": "^1.1.0"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+ }
+ }
+ },
+ "create-ecdh": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz",
+ "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==",
+ "requires": {
+ "bn.js": "^4.1.0",
+ "elliptic": "^6.0.0"
+ }
+ },
+ "create-error-class": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz",
+ "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=",
+ "requires": {
+ "capture-stack-trace": "^1.0.0"
+ }
+ },
+ "create-hash": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
+ "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
+ "requires": {
+ "cipher-base": "^1.0.1",
+ "inherits": "^2.0.1",
+ "md5.js": "^1.3.4",
+ "ripemd160": "^2.0.1",
+ "sha.js": "^2.4.0"
+ }
+ },
+ "create-hmac": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
+ "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
+ "requires": {
+ "cipher-base": "^1.0.3",
+ "create-hash": "^1.1.0",
+ "inherits": "^2.0.1",
+ "ripemd160": "^2.0.0",
+ "safe-buffer": "^5.0.1",
+ "sha.js": "^2.4.8"
+ }
+ },
+ "cross-spawn": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
+ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
+ "requires": {
+ "lru-cache": "^4.0.1",
+ "shebang-command": "^1.2.0",
+ "which": "^1.2.9"
+ }
+ },
+ "crypto-browserify": {
+ "version": "3.12.0",
+ "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
+ "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==",
+ "requires": {
+ "browserify-cipher": "^1.0.0",
+ "browserify-sign": "^4.0.0",
+ "create-ecdh": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "create-hmac": "^1.1.0",
+ "diffie-hellman": "^5.0.0",
+ "inherits": "^2.0.1",
+ "pbkdf2": "^3.0.3",
+ "public-encrypt": "^4.0.0",
+ "randombytes": "^2.0.0",
+ "randomfill": "^1.0.3"
+ }
+ },
+ "crypto-random-string": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz",
+ "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4="
+ },
+ "css-color-names": {
+ "version": "0.0.4",
+ "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
+ "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA="
+ },
+ "css-loader": {
+ "version": "0.28.7",
+ "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.28.7.tgz",
+ "integrity": "sha512-GxMpax8a/VgcfRrVy0gXD6yLd5ePYbXX/5zGgTVYp4wXtJklS8Z2VaUArJgc//f6/Dzil7BaJObdSv8eKKCPgg==",
+ "requires": {
+ "babel-code-frame": "^6.11.0",
+ "css-selector-tokenizer": "^0.7.0",
+ "cssnano": ">=2.6.1 <4",
+ "icss-utils": "^2.1.0",
+ "loader-utils": "^1.0.2",
+ "lodash.camelcase": "^4.3.0",
+ "object-assign": "^4.0.1",
+ "postcss": "^5.0.6",
+ "postcss-modules-extract-imports": "^1.0.0",
+ "postcss-modules-local-by-default": "^1.0.1",
+ "postcss-modules-scope": "^1.0.0",
+ "postcss-modules-values": "^1.1.0",
+ "postcss-value-parser": "^3.3.0",
+ "source-list-map": "^2.0.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "css-select": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
+ "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=",
+ "requires": {
+ "boolbase": "~1.0.0",
+ "css-what": "2.1",
+ "domutils": "1.5.1",
+ "nth-check": "~1.0.1"
+ }
+ },
+ "css-selector-tokenizer": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz",
+ "integrity": "sha1-5piEdK6MlTR3v15+/s/OzNnPTIY=",
+ "requires": {
+ "cssesc": "^0.1.0",
+ "fastparse": "^1.1.1",
+ "regexpu-core": "^1.0.0"
+ },
+ "dependencies": {
+ "regexpu-core": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz",
+ "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=",
+ "requires": {
+ "regenerate": "^1.2.1",
+ "regjsgen": "^0.2.0",
+ "regjsparser": "^0.1.4"
+ }
+ }
+ }
+ },
+ "css-what": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz",
+ "integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0="
+ },
+ "cssesc": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz",
+ "integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q="
+ },
+ "cssnano": {
+ "version": "3.10.0",
+ "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-3.10.0.tgz",
+ "integrity": "sha1-Tzj2zqK5sX+gFJDyPx3GjqZcHDg=",
+ "requires": {
+ "autoprefixer": "^6.3.1",
+ "decamelize": "^1.1.2",
+ "defined": "^1.0.0",
+ "has": "^1.0.1",
+ "object-assign": "^4.0.1",
+ "postcss": "^5.0.14",
+ "postcss-calc": "^5.2.0",
+ "postcss-colormin": "^2.1.8",
+ "postcss-convert-values": "^2.3.4",
+ "postcss-discard-comments": "^2.0.4",
+ "postcss-discard-duplicates": "^2.0.1",
+ "postcss-discard-empty": "^2.0.1",
+ "postcss-discard-overridden": "^0.1.1",
+ "postcss-discard-unused": "^2.2.1",
+ "postcss-filter-plugins": "^2.0.0",
+ "postcss-merge-idents": "^2.1.5",
+ "postcss-merge-longhand": "^2.0.1",
+ "postcss-merge-rules": "^2.0.3",
+ "postcss-minify-font-values": "^1.0.2",
+ "postcss-minify-gradients": "^1.0.1",
+ "postcss-minify-params": "^1.0.4",
+ "postcss-minify-selectors": "^2.0.4",
+ "postcss-normalize-charset": "^1.1.0",
+ "postcss-normalize-url": "^3.0.7",
+ "postcss-ordered-values": "^2.1.0",
+ "postcss-reduce-idents": "^2.2.2",
+ "postcss-reduce-initial": "^1.0.0",
+ "postcss-reduce-transforms": "^1.0.3",
+ "postcss-svgo": "^2.1.1",
+ "postcss-unique-selectors": "^2.0.2",
+ "postcss-value-parser": "^3.2.3",
+ "postcss-zindex": "^2.0.1"
+ },
+ "dependencies": {
+ "autoprefixer": {
+ "version": "6.7.7",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.7.7.tgz",
+ "integrity": "sha1-Hb0cg1ZY41zj+ZhAmdsAWFx4IBQ=",
+ "requires": {
+ "browserslist": "^1.7.6",
+ "caniuse-db": "^1.0.30000634",
+ "normalize-range": "^0.1.2",
+ "num2fraction": "^1.2.2",
+ "postcss": "^5.2.16",
+ "postcss-value-parser": "^3.2.3"
+ }
+ },
+ "browserslist": {
+ "version": "1.7.7",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz",
+ "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=",
+ "requires": {
+ "caniuse-db": "^1.0.30000639",
+ "electron-to-chromium": "^1.2.7"
+ }
+ },
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "csso": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/csso/-/csso-2.3.2.tgz",
+ "integrity": "sha1-3dUsWHAz9J6Utx/FVWnyUuj/X4U=",
+ "requires": {
+ "clap": "^1.0.9",
+ "source-map": "^0.5.3"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ }
+ }
+ },
+ "cssom": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.2.tgz",
+ "integrity": "sha1-uANhcMefB6kP8vFuIihAJ6JDhIs="
+ },
+ "cssstyle": {
+ "version": "0.2.37",
+ "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz",
+ "integrity": "sha1-VBCXI0yyUTyDzu06zdwn/yeYfVQ=",
+ "requires": {
+ "cssom": "0.3.x"
+ }
+ },
+ "currently-unhandled": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
+ "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
+ "requires": {
+ "array-find-index": "^1.0.1"
+ }
+ },
+ "d": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz",
+ "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",
+ "requires": {
+ "es5-ext": "^0.10.9"
+ }
+ },
+ "damerau-levenshtein": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz",
+ "integrity": "sha1-AxkcQyy27qFou3fzpV/9zLiXhRQ="
+ },
+ "dashdash": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "date-now": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",
+ "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs="
+ },
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
+ },
+ "decode-uri-component": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
+ },
+ "deep-equal": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
+ "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU="
+ },
+ "deep-extend": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
+ },
+ "deep-is": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ="
+ },
+ "default-require-extensions": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz",
+ "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=",
+ "requires": {
+ "strip-bom": "^3.0.0"
+ },
+ "dependencies": {
+ "strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM="
+ }
+ }
+ },
+ "define-properties": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz",
+ "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=",
+ "requires": {
+ "foreach": "^2.0.5",
+ "object-keys": "^1.0.8"
+ }
+ },
+ "define-property": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+ "requires": {
+ "is-descriptor": "^1.0.2",
+ "isobject": "^3.0.1"
+ },
+ "dependencies": {
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "defined": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
+ "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM="
+ },
+ "del": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz",
+ "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=",
+ "requires": {
+ "globby": "^5.0.0",
+ "is-path-cwd": "^1.0.0",
+ "is-path-in-cwd": "^1.0.0",
+ "object-assign": "^4.0.1",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0",
+ "rimraf": "^2.2.8"
+ }
+ },
+ "delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
+ },
+ "depd": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
+ },
+ "des.js": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz",
+ "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=",
+ "requires": {
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0"
+ }
+ },
+ "destroy": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
+ "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
+ },
+ "detect-indent": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz",
+ "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=",
+ "requires": {
+ "repeating": "^2.0.0"
+ }
+ },
+ "detect-node": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.3.tgz",
+ "integrity": "sha1-ogM8CcyOFY03dI+951B4Mr1s4Sc="
+ },
+ "detect-port-alt": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz",
+ "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==",
+ "requires": {
+ "address": "^1.0.1",
+ "debug": "^2.6.0"
+ }
+ },
+ "diff": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
+ "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA=="
+ },
+ "diffie-hellman": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
+ "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
+ "requires": {
+ "bn.js": "^4.1.0",
+ "miller-rabin": "^4.0.0",
+ "randombytes": "^2.0.0"
+ }
+ },
+ "dns-equal": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
+ "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0="
+ },
+ "dns-packet": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz",
+ "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==",
+ "requires": {
+ "ip": "^1.1.0",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "dns-txt": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz",
+ "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=",
+ "requires": {
+ "buffer-indexof": "^1.0.0"
+ }
+ },
+ "doctrine": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+ "requires": {
+ "esutils": "^2.0.2"
+ }
+ },
+ "dom-converter": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.1.4.tgz",
+ "integrity": "sha1-pF71cnuJDJv/5tfIduexnLDhfzs=",
+ "requires": {
+ "utila": "~0.3"
+ },
+ "dependencies": {
+ "utila": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/utila/-/utila-0.3.3.tgz",
+ "integrity": "sha1-1+jn1+MJEHCSsF+NloiCTWM6QiY="
+ }
+ }
+ },
+ "dom-serializer": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
+ "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=",
+ "requires": {
+ "domelementtype": "~1.1.1",
+ "entities": "~1.1.1"
+ },
+ "dependencies": {
+ "domelementtype": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz",
+ "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs="
+ }
+ }
+ },
+ "dom-urls": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/dom-urls/-/dom-urls-1.1.0.tgz",
+ "integrity": "sha1-AB3fgWKM0ecGElxxdvU8zsVdkY4=",
+ "requires": {
+ "urijs": "^1.16.1"
+ }
+ },
+ "domain-browser": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
+ "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA=="
+ },
+ "domelementtype": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz",
+ "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI="
+ },
+ "domhandler": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.1.0.tgz",
+ "integrity": "sha1-0mRvXlf2w7qxHPbLBdPArPdBJZQ=",
+ "requires": {
+ "domelementtype": "1"
+ }
+ },
+ "domutils": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
+ "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
+ "requires": {
+ "dom-serializer": "0",
+ "domelementtype": "1"
+ }
+ },
+ "dot-prop": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz",
+ "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==",
+ "requires": {
+ "is-obj": "^1.0.0"
+ }
+ },
+ "dotenv": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-4.0.0.tgz",
+ "integrity": "sha1-hk7xN5rO1Vzm+V3r7NzhefegzR0="
+ },
+ "dotenv-expand": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-4.2.0.tgz",
+ "integrity": "sha1-3vHxyl1gWdJKdm5YeULCEQbOEnU="
+ },
+ "duplexer": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
+ "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E="
+ },
+ "duplexer3": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
+ "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI="
+ },
+ "ecc-jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
+ "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
+ "optional": true,
+ "requires": {
+ "jsbn": "~0.1.0"
+ }
+ },
+ "ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+ },
+ "electron-to-chromium": {
+ "version": "1.3.48",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.48.tgz",
+ "integrity": "sha1-07DYWTgUBE4JLs4hCPw6ya6kuQA="
+ },
+ "elliptic": {
+ "version": "6.4.0",
+ "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz",
+ "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=",
+ "requires": {
+ "bn.js": "^4.4.0",
+ "brorand": "^1.0.1",
+ "hash.js": "^1.0.0",
+ "hmac-drbg": "^1.0.0",
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0",
+ "minimalistic-crypto-utils": "^1.0.0"
+ }
+ },
+ "emoji-regex": {
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.5.1.tgz",
+ "integrity": "sha512-PAHp6TxrCy7MGMFidro8uikr+zlJJKJ/Q6mm2ExZ7HwkyR9lSVFfE3kt36qcwa24BQL7y0G9axycGjK1A/0uNQ=="
+ },
+ "emojis-list": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",
+ "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k="
+ },
+ "encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
+ },
+ "encoding": {
+ "version": "0.1.12",
+ "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
+ "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
+ "requires": {
+ "iconv-lite": "~0.4.13"
+ }
+ },
+ "enhanced-resolve": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz",
+ "integrity": "sha1-BCHjOf1xQZs9oT0Smzl5BAIwR24=",
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "memory-fs": "^0.4.0",
+ "object-assign": "^4.0.1",
+ "tapable": "^0.2.7"
+ }
+ },
+ "entities": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz",
+ "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA="
+ },
+ "errno": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",
+ "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==",
+ "requires": {
+ "prr": "~1.0.1"
+ }
+ },
+ "error-ex": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz",
+ "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=",
+ "requires": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "es-abstract": {
+ "version": "1.12.0",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz",
+ "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==",
+ "requires": {
+ "es-to-primitive": "^1.1.1",
+ "function-bind": "^1.1.1",
+ "has": "^1.0.1",
+ "is-callable": "^1.1.3",
+ "is-regex": "^1.0.4"
+ }
+ },
+ "es-to-primitive": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz",
+ "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=",
+ "requires": {
+ "is-callable": "^1.1.1",
+ "is-date-object": "^1.0.1",
+ "is-symbol": "^1.0.1"
+ }
+ },
+ "es5-ext": {
+ "version": "0.10.45",
+ "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.45.tgz",
+ "integrity": "sha512-FkfM6Vxxfmztilbxxz5UKSD4ICMf5tSpRFtDNtkAhOxZ0EKtX6qwmXNyH/sFyIbX2P/nU5AMiA9jilWsUGJzCQ==",
+ "requires": {
+ "es6-iterator": "~2.0.3",
+ "es6-symbol": "~3.1.1",
+ "next-tick": "1"
+ }
+ },
+ "es6-iterator": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+ "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
+ "requires": {
+ "d": "1",
+ "es5-ext": "^0.10.35",
+ "es6-symbol": "^3.1.1"
+ }
+ },
+ "es6-map": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz",
+ "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=",
+ "requires": {
+ "d": "1",
+ "es5-ext": "~0.10.14",
+ "es6-iterator": "~2.0.1",
+ "es6-set": "~0.1.5",
+ "es6-symbol": "~3.1.1",
+ "event-emitter": "~0.3.5"
+ }
+ },
+ "es6-promise": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz",
+ "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ=="
+ },
+ "es6-set": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz",
+ "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=",
+ "requires": {
+ "d": "1",
+ "es5-ext": "~0.10.14",
+ "es6-iterator": "~2.0.1",
+ "es6-symbol": "3.1.1",
+ "event-emitter": "~0.3.5"
+ }
+ },
+ "es6-symbol": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz",
+ "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=",
+ "requires": {
+ "d": "1",
+ "es5-ext": "~0.10.14"
+ }
+ },
+ "es6-weak-map": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz",
+ "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=",
+ "requires": {
+ "d": "1",
+ "es5-ext": "^0.10.14",
+ "es6-iterator": "^2.0.1",
+ "es6-symbol": "^3.1.1"
+ }
+ },
+ "escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+ },
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
+ },
+ "escodegen": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.10.0.tgz",
+ "integrity": "sha512-fjUOf8johsv23WuIKdNQU4P9t9jhQ4Qzx6pC2uW890OloK3Zs1ZAoCNpg/2larNF501jLl3UNy0kIRcF6VI22g==",
+ "requires": {
+ "esprima": "^3.1.3",
+ "estraverse": "^4.2.0",
+ "esutils": "^2.0.2",
+ "optionator": "^0.8.1",
+ "source-map": "~0.6.1"
+ },
+ "dependencies": {
+ "esprima": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz",
+ "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM="
+ }
+ }
+ },
+ "escope": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz",
+ "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=",
+ "requires": {
+ "es6-map": "^0.1.3",
+ "es6-weak-map": "^2.0.1",
+ "esrecurse": "^4.1.0",
+ "estraverse": "^4.1.1"
+ }
+ },
+ "eslint": {
+ "version": "4.19.1",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz",
+ "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==",
+ "dev": true,
+ "requires": {
+ "ajv": "^5.3.0",
+ "babel-code-frame": "^6.22.0",
+ "chalk": "^2.1.0",
+ "concat-stream": "^1.6.0",
+ "cross-spawn": "^5.1.0",
+ "debug": "^3.1.0",
+ "doctrine": "^2.1.0",
+ "eslint-scope": "^3.7.1",
+ "eslint-visitor-keys": "^1.0.0",
+ "espree": "^3.5.4",
+ "esquery": "^1.0.0",
+ "esutils": "^2.0.2",
+ "file-entry-cache": "^2.0.0",
+ "functional-red-black-tree": "^1.0.1",
+ "glob": "^7.1.2",
+ "globals": "^11.0.1",
+ "ignore": "^3.3.3",
+ "imurmurhash": "^0.1.4",
+ "inquirer": "^3.0.6",
+ "is-resolvable": "^1.0.0",
+ "js-yaml": "^3.9.1",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.3.0",
+ "lodash": "^4.17.4",
+ "minimatch": "^3.0.2",
+ "mkdirp": "^0.5.1",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.8.2",
+ "path-is-inside": "^1.0.2",
+ "pluralize": "^7.0.0",
+ "progress": "^2.0.0",
+ "regexpp": "^1.0.1",
+ "require-uncached": "^1.0.3",
+ "semver": "^5.3.0",
+ "strip-ansi": "^4.0.0",
+ "strip-json-comments": "~2.0.1",
+ "table": "4.0.2",
+ "text-table": "~0.2.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+ "dev": true
+ },
+ "chalk": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
+ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
+ "debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "esprima": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz",
+ "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==",
+ "dev": true
+ },
+ "globals": {
+ "version": "11.5.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.5.0.tgz",
+ "integrity": "sha512-hYyf+kI8dm3nORsiiXUQigOU62hDLfJ9G01uyGMxhc6BKsircrUhC4uJPQPUSuq2GrTmiiEt7ewxlMdBewfmKQ==",
+ "dev": true
+ },
+ "js-yaml": {
+ "version": "3.12.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
+ "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==",
+ "dev": true,
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^3.0.0"
+ }
+ }
+ }
+ },
+ "eslint-config-react-app": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-2.1.0.tgz",
+ "integrity": "sha512-8QZrKWuHVC57Fmu+SsKAVxnI9LycZl7NFQ4H9L+oeISuCXhYdXqsOOIVSjQFW6JF5MXZLFE+21Syhd7mF1IRZQ=="
+ },
+ "eslint-import-resolver-node": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz",
+ "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==",
+ "requires": {
+ "debug": "^2.6.9",
+ "resolve": "^1.5.0"
+ }
+ },
+ "eslint-loader": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/eslint-loader/-/eslint-loader-1.9.0.tgz",
+ "integrity": "sha512-40aN976qSNPyb9ejTqjEthZITpls1SVKtwguahmH1dzGCwQU/vySE+xX33VZmD8csU0ahVNCtFlsPgKqRBiqgg==",
+ "requires": {
+ "loader-fs-cache": "^1.0.0",
+ "loader-utils": "^1.0.2",
+ "object-assign": "^4.0.1",
+ "object-hash": "^1.1.4",
+ "rimraf": "^2.6.1"
+ }
+ },
+ "eslint-module-utils": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz",
+ "integrity": "sha1-snA2LNiLGkitMIl2zn+lTphBF0Y=",
+ "requires": {
+ "debug": "^2.6.8",
+ "pkg-dir": "^1.0.0"
+ },
+ "dependencies": {
+ "find-up": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
+ "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
+ "requires": {
+ "path-exists": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ }
+ },
+ "path-exists": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
+ "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
+ "requires": {
+ "pinkie-promise": "^2.0.0"
+ }
+ },
+ "pkg-dir": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz",
+ "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=",
+ "requires": {
+ "find-up": "^1.0.0"
+ }
+ }
+ }
+ },
+ "eslint-plugin-flowtype": {
+ "version": "2.39.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.39.1.tgz",
+ "integrity": "sha512-RiQv+7Z9QDJuzt+NO8sYgkLGT+h+WeCrxP7y8lI7wpU41x3x/2o3PGtHk9ck8QnA9/mlbNcy/hG0eKvmd7npaA==",
+ "requires": {
+ "lodash": "^4.15.0"
+ }
+ },
+ "eslint-plugin-import": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.8.0.tgz",
+ "integrity": "sha512-Rf7dfKJxZ16QuTgVv1OYNxkZcsu/hULFnC+e+w0Gzi6jMC3guQoWQgxYxc54IDRinlb6/0v5z/PxxIKmVctN+g==",
+ "requires": {
+ "builtin-modules": "^1.1.1",
+ "contains-path": "^0.1.0",
+ "debug": "^2.6.8",
+ "doctrine": "1.5.0",
+ "eslint-import-resolver-node": "^0.3.1",
+ "eslint-module-utils": "^2.1.1",
+ "has": "^1.0.1",
+ "lodash.cond": "^4.3.0",
+ "minimatch": "^3.0.3",
+ "read-pkg-up": "^2.0.0"
+ },
+ "dependencies": {
+ "doctrine": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz",
+ "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=",
+ "requires": {
+ "esutils": "^2.0.2",
+ "isarray": "^1.0.0"
+ }
+ },
+ "load-json-file": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
+ "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "parse-json": "^2.2.0",
+ "pify": "^2.0.0",
+ "strip-bom": "^3.0.0"
+ }
+ },
+ "path-type": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz",
+ "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=",
+ "requires": {
+ "pify": "^2.0.0"
+ }
+ },
+ "read-pkg": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",
+ "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=",
+ "requires": {
+ "load-json-file": "^2.0.0",
+ "normalize-package-data": "^2.3.2",
+ "path-type": "^2.0.0"
+ }
+ },
+ "read-pkg-up": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz",
+ "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=",
+ "requires": {
+ "find-up": "^2.0.0",
+ "read-pkg": "^2.0.0"
+ }
+ },
+ "strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM="
+ }
+ }
+ },
+ "eslint-plugin-jsx-a11y": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-5.1.1.tgz",
+ "integrity": "sha512-5I9SpoP7gT4wBFOtXT8/tXNPYohHBVfyVfO17vkbC7r9kEIxYJF12D3pKqhk8+xnk12rfxKClS3WCFpVckFTPQ==",
+ "requires": {
+ "aria-query": "^0.7.0",
+ "array-includes": "^3.0.3",
+ "ast-types-flow": "0.0.7",
+ "axobject-query": "^0.1.0",
+ "damerau-levenshtein": "^1.0.0",
+ "emoji-regex": "^6.1.0",
+ "jsx-ast-utils": "^1.4.0"
+ }
+ },
+ "eslint-plugin-react": {
+ "version": "7.10.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.10.0.tgz",
+ "integrity": "sha512-18rzWn4AtbSUxFKKM7aCVcj5LXOhOKdwBino3KKWy4psxfPW0YtIbE8WNRDUdyHFL50BeLb6qFd4vpvNYyp7hw==",
+ "dev": true,
+ "requires": {
+ "doctrine": "^2.1.0",
+ "has": "^1.0.3",
+ "jsx-ast-utils": "^2.0.1",
+ "prop-types": "^15.6.2"
+ },
+ "dependencies": {
+ "jsx-ast-utils": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz",
+ "integrity": "sha1-6AGxs5mF4g//yHtA43SAgOLcrH8=",
+ "dev": true,
+ "requires": {
+ "array-includes": "^3.0.3"
+ }
+ }
+ }
+ },
+ "eslint-scope": {
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz",
+ "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=",
+ "requires": {
+ "esrecurse": "^4.1.0",
+ "estraverse": "^4.1.1"
+ }
+ },
+ "eslint-visitor-keys": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
+ "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==",
+ "dev": true
+ },
+ "espree": {
+ "version": "3.5.4",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz",
+ "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==",
+ "requires": {
+ "acorn": "^5.5.0",
+ "acorn-jsx": "^3.0.0"
+ }
+ },
+ "esprima": {
+ "version": "2.7.3",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz",
+ "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE="
+ },
+ "esquery": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz",
+ "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==",
+ "requires": {
+ "estraverse": "^4.0.0"
+ }
+ },
+ "esrecurse": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
+ "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
+ "requires": {
+ "estraverse": "^4.1.0"
+ }
+ },
+ "estraverse": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
+ "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM="
+ },
+ "esutils": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs="
+ },
+ "etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
+ },
+ "event-emitter": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
+ "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=",
+ "requires": {
+ "d": "1",
+ "es5-ext": "~0.10.14"
+ }
+ },
+ "eventemitter3": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz",
+ "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA=="
+ },
+ "events": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
+ "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ="
+ },
+ "eventsource": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-0.1.6.tgz",
+ "integrity": "sha1-Cs7ehJ7X3RzMMsgRuxG5RNTykjI=",
+ "requires": {
+ "original": ">=0.0.5"
+ }
+ },
+ "evp_bytestokey": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
+ "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
+ "requires": {
+ "md5.js": "^1.3.4",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "exec-sh": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.1.tgz",
+ "integrity": "sha512-aLt95pexaugVtQerpmE51+4QfWrNc304uez7jvj6fWnN8GeEHpttB8F36n8N7uVhUMbH/1enbxQ9HImZ4w/9qg==",
+ "requires": {
+ "merge": "^1.1.3"
+ }
+ },
+ "execa": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
+ "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=",
+ "requires": {
+ "cross-spawn": "^5.0.1",
+ "get-stream": "^3.0.0",
+ "is-stream": "^1.1.0",
+ "npm-run-path": "^2.0.0",
+ "p-finally": "^1.0.0",
+ "signal-exit": "^3.0.0",
+ "strip-eof": "^1.0.0"
+ }
+ },
+ "expand-brackets": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+ "requires": {
+ "debug": "^2.3.3",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "posix-character-classes": "^0.1.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "expand-range": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
+ "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
+ "requires": {
+ "fill-range": "^2.1.0"
+ },
+ "dependencies": {
+ "fill-range": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz",
+ "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==",
+ "requires": {
+ "is-number": "^2.1.0",
+ "isobject": "^2.0.0",
+ "randomatic": "^3.0.0",
+ "repeat-element": "^1.1.2",
+ "repeat-string": "^1.5.2"
+ }
+ },
+ "is-number": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
+ "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
+ "requires": {
+ "kind-of": "^3.0.2"
+ }
+ },
+ "isobject": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+ "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+ "requires": {
+ "isarray": "1.0.0"
+ }
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "expand-tilde": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
+ "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=",
+ "requires": {
+ "homedir-polyfill": "^1.0.1"
+ }
+ },
+ "express": {
+ "version": "4.16.3",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz",
+ "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=",
+ "requires": {
+ "accepts": "~1.3.5",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.18.2",
+ "content-disposition": "0.5.2",
+ "content-type": "~1.0.4",
+ "cookie": "0.3.1",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "1.1.1",
+ "fresh": "0.5.2",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.2",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.3",
+ "qs": "6.5.1",
+ "range-parser": "~1.2.0",
+ "safe-buffer": "5.1.1",
+ "send": "0.16.2",
+ "serve-static": "1.13.2",
+ "setprototypeof": "1.1.0",
+ "statuses": "~1.4.0",
+ "type-is": "~1.6.16",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "dependencies": {
+ "array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+ },
+ "path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
+ },
+ "qs": {
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
+ "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A=="
+ },
+ "safe-buffer": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
+ "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
+ }
+ }
+ },
+ "extend": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
+ "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ="
+ },
+ "extend-shallow": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
+ "requires": {
+ "assign-symbols": "^1.0.0",
+ "is-extendable": "^1.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "requires": {
+ "is-plain-object": "^2.0.4"
+ }
+ }
+ }
+ },
+ "external-editor": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
+ "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==",
+ "requires": {
+ "chardet": "^0.4.0",
+ "iconv-lite": "^0.4.17",
+ "tmp": "^0.0.33"
+ }
+ },
+ "extglob": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+ "requires": {
+ "array-unique": "^0.3.2",
+ "define-property": "^1.0.0",
+ "expand-brackets": "^2.1.4",
+ "extend-shallow": "^2.0.1",
+ "fragment-cache": "^0.2.1",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "extract-text-webpack-plugin": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extract-text-webpack-plugin/-/extract-text-webpack-plugin-3.0.2.tgz",
+ "integrity": "sha512-bt/LZ4m5Rqt/Crl2HiKuAl/oqg0psx1tsTLkvWbJen1CtD+fftkZhMaQ9HOtY2gWsl2Wq+sABmMVi9z3DhKWQQ==",
+ "requires": {
+ "async": "^2.4.1",
+ "loader-utils": "^1.1.0",
+ "schema-utils": "^0.3.0",
+ "webpack-sources": "^1.0.1"
+ }
+ },
+ "extsprintf": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
+ },
+ "fancybox": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/fancybox/-/fancybox-3.0.1.tgz",
+ "integrity": "sha512-HZ57O6j5Zk4Uvusd5pNUgWi7CCjKx+HFlCzjMPeRJ//0bQWUK+xVpkn3EzXWJate4ZSKNFP9kU2l49MP1g+oow=="
+ },
+ "fast-deep-equal": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
+ "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ="
+ },
+ "fast-json-stable-stringify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
+ "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
+ },
+ "fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
+ },
+ "fastparse": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.1.tgz",
+ "integrity": "sha1-0eJkOzipTXWDtHkGDmxK/8lAcfg="
+ },
+ "faye-websocket": {
+ "version": "0.11.1",
+ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.1.tgz",
+ "integrity": "sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg=",
+ "requires": {
+ "websocket-driver": ">=0.5.1"
+ }
+ },
+ "fb-watchman": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz",
+ "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=",
+ "requires": {
+ "bser": "^2.0.0"
+ }
+ },
+ "fbjs": {
+ "version": "0.8.17",
+ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz",
+ "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=",
+ "requires": {
+ "core-js": "^1.0.0",
+ "isomorphic-fetch": "^2.1.1",
+ "loose-envify": "^1.0.0",
+ "object-assign": "^4.1.0",
+ "promise": "^7.1.1",
+ "setimmediate": "^1.0.5",
+ "ua-parser-js": "^0.7.18"
+ }
+ },
+ "figures": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
+ "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
+ "requires": {
+ "escape-string-regexp": "^1.0.5"
+ }
+ },
+ "file-entry-cache": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz",
+ "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=",
+ "requires": {
+ "flat-cache": "^1.2.1",
+ "object-assign": "^4.0.1"
+ }
+ },
+ "file-loader": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.5.tgz",
+ "integrity": "sha512-RzGHDatcVNpGISTvCpfUfOGpYuSR7HSsSg87ki+wF6rw1Hm0RALPTiAdsxAq1UwLf0RRhbe22/eHK6nhXspiOQ==",
+ "requires": {
+ "loader-utils": "^1.0.2",
+ "schema-utils": "^0.3.0"
+ }
+ },
+ "filename-regex": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
+ "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY="
+ },
+ "fileset": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz",
+ "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=",
+ "requires": {
+ "glob": "^7.0.3",
+ "minimatch": "^3.0.3"
+ }
+ },
+ "filesize": {
+ "version": "3.5.11",
+ "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.5.11.tgz",
+ "integrity": "sha512-ZH7loueKBoDb7yG9esn1U+fgq7BzlzW6NRi5/rMdxIZ05dj7GFD/Xc5rq2CDt5Yq86CyfSYVyx4242QQNZbx1g=="
+ },
+ "fill-range": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1",
+ "to-regex-range": "^2.1.0"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "finalhandler": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
+ "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==",
+ "requires": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.2",
+ "statuses": "~1.4.0",
+ "unpipe": "~1.0.0"
+ }
+ },
+ "find-cache-dir": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz",
+ "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=",
+ "requires": {
+ "commondir": "^1.0.1",
+ "make-dir": "^1.0.0",
+ "pkg-dir": "^2.0.0"
+ }
+ },
+ "find-up": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
+ "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
+ "requires": {
+ "locate-path": "^2.0.0"
+ }
+ },
+ "flat-cache": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz",
+ "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=",
+ "requires": {
+ "circular-json": "^0.3.1",
+ "del": "^2.0.2",
+ "graceful-fs": "^4.1.2",
+ "write": "^0.2.1"
+ }
+ },
+ "flatten": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz",
+ "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I="
+ },
+ "follow-redirects": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.0.tgz",
+ "integrity": "sha512-fdrt472/9qQ6Kgjvb935ig6vJCuofpBUD14f9Vb+SLlm7xIe4Qva5gey8EKtv8lp7ahE1wilg3xL1znpVGtZIA==",
+ "requires": {
+ "debug": "^3.1.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ }
+ }
+ },
+ "for-in": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA="
+ },
+ "for-own": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
+ "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
+ "requires": {
+ "for-in": "^1.0.1"
+ }
+ },
+ "foreach": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
+ "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k="
+ },
+ "forever-agent": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
+ },
+ "form-data": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz",
+ "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=",
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "1.0.6",
+ "mime-types": "^2.1.12"
+ }
+ },
+ "forwarded": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
+ "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
+ },
+ "fragment-cache": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
+ "requires": {
+ "map-cache": "^0.2.2"
+ }
+ },
+ "fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
+ },
+ "fs-extra": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz",
+ "integrity": "sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE=",
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "jsonfile": "^3.0.0",
+ "universalify": "^0.1.0"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+ },
+ "fsevents": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz",
+ "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==",
+ "optional": true,
+ "requires": {
+ "nan": "^2.9.2",
+ "node-pre-gyp": "^0.10.0"
+ },
+ "dependencies": {
+ "abbrev": {
+ "version": "1.1.1",
+ "bundled": true,
+ "optional": true
+ },
+ "ansi-regex": {
+ "version": "2.1.1",
+ "bundled": true
+ },
+ "aproba": {
+ "version": "1.2.0",
+ "bundled": true,
+ "optional": true
+ },
+ "are-we-there-yet": {
+ "version": "1.1.4",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "delegates": "^1.0.0",
+ "readable-stream": "^2.0.6"
+ }
+ },
+ "balanced-match": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "bundled": true,
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "chownr": {
+ "version": "1.0.1",
+ "bundled": true,
+ "optional": true
+ },
+ "code-point-at": {
+ "version": "1.1.0",
+ "bundled": true
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "bundled": true
+ },
+ "console-control-strings": {
+ "version": "1.1.0",
+ "bundled": true
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "bundled": true,
+ "optional": true
+ },
+ "debug": {
+ "version": "2.6.9",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "deep-extend": {
+ "version": "0.5.1",
+ "bundled": true,
+ "optional": true
+ },
+ "delegates": {
+ "version": "1.0.0",
+ "bundled": true,
+ "optional": true
+ },
+ "detect-libc": {
+ "version": "1.0.3",
+ "bundled": true,
+ "optional": true
+ },
+ "fs-minipass": {
+ "version": "1.2.5",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "minipass": "^2.2.1"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "bundled": true,
+ "optional": true
+ },
+ "gauge": {
+ "version": "2.7.4",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "aproba": "^1.0.3",
+ "console-control-strings": "^1.0.0",
+ "has-unicode": "^2.0.0",
+ "object-assign": "^4.1.0",
+ "signal-exit": "^3.0.0",
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1",
+ "wide-align": "^1.1.0"
+ }
+ },
+ "glob": {
+ "version": "7.1.2",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "has-unicode": {
+ "version": "2.0.1",
+ "bundled": true,
+ "optional": true
+ },
+ "iconv-lite": {
+ "version": "0.4.21",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "safer-buffer": "^2.1.0"
+ }
+ },
+ "ignore-walk": {
+ "version": "3.0.1",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "minimatch": "^3.0.4"
+ }
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "bundled": true
+ },
+ "ini": {
+ "version": "1.3.5",
+ "bundled": true,
+ "optional": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "bundled": true,
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "bundled": true,
+ "optional": true
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "bundled": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "minimist": {
+ "version": "0.0.8",
+ "bundled": true
+ },
+ "minipass": {
+ "version": "2.2.4",
+ "bundled": true,
+ "requires": {
+ "safe-buffer": "^5.1.1",
+ "yallist": "^3.0.0"
+ }
+ },
+ "minizlib": {
+ "version": "1.1.0",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "minipass": "^2.2.1"
+ }
+ },
+ "mkdirp": {
+ "version": "0.5.1",
+ "bundled": true,
+ "requires": {
+ "minimist": "0.0.8"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "bundled": true,
+ "optional": true
+ },
+ "needle": {
+ "version": "2.2.0",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "debug": "^2.1.2",
+ "iconv-lite": "^0.4.4",
+ "sax": "^1.2.4"
+ }
+ },
+ "node-pre-gyp": {
+ "version": "0.10.0",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "detect-libc": "^1.0.2",
+ "mkdirp": "^0.5.1",
+ "needle": "^2.2.0",
+ "nopt": "^4.0.1",
+ "npm-packlist": "^1.1.6",
+ "npmlog": "^4.0.2",
+ "rc": "^1.1.7",
+ "rimraf": "^2.6.1",
+ "semver": "^5.3.0",
+ "tar": "^4"
+ }
+ },
+ "nopt": {
+ "version": "4.0.1",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "abbrev": "1",
+ "osenv": "^0.1.4"
+ }
+ },
+ "npm-bundled": {
+ "version": "1.0.3",
+ "bundled": true,
+ "optional": true
+ },
+ "npm-packlist": {
+ "version": "1.1.10",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "ignore-walk": "^3.0.1",
+ "npm-bundled": "^1.0.1"
+ }
+ },
+ "npmlog": {
+ "version": "4.1.2",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "are-we-there-yet": "~1.1.2",
+ "console-control-strings": "~1.1.0",
+ "gauge": "~2.7.3",
+ "set-blocking": "~2.0.0"
+ }
+ },
+ "number-is-nan": {
+ "version": "1.0.1",
+ "bundled": true
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "bundled": true,
+ "optional": true
+ },
+ "once": {
+ "version": "1.4.0",
+ "bundled": true,
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "os-homedir": {
+ "version": "1.0.2",
+ "bundled": true,
+ "optional": true
+ },
+ "os-tmpdir": {
+ "version": "1.0.2",
+ "bundled": true,
+ "optional": true
+ },
+ "osenv": {
+ "version": "0.1.5",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "os-homedir": "^1.0.0",
+ "os-tmpdir": "^1.0.0"
+ }
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "bundled": true,
+ "optional": true
+ },
+ "process-nextick-args": {
+ "version": "2.0.0",
+ "bundled": true,
+ "optional": true
+ },
+ "rc": {
+ "version": "1.2.7",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "deep-extend": "^0.5.1",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "1.2.0",
+ "bundled": true,
+ "optional": true
+ }
+ }
+ },
+ "readable-stream": {
+ "version": "2.3.6",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "rimraf": {
+ "version": "2.6.2",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "glob": "^7.0.5"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.1",
+ "bundled": true
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "bundled": true,
+ "optional": true
+ },
+ "sax": {
+ "version": "1.2.4",
+ "bundled": true,
+ "optional": true
+ },
+ "semver": {
+ "version": "5.5.0",
+ "bundled": true,
+ "optional": true
+ },
+ "set-blocking": {
+ "version": "2.0.0",
+ "bundled": true,
+ "optional": true
+ },
+ "signal-exit": {
+ "version": "3.0.2",
+ "bundled": true,
+ "optional": true
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "bundled": true,
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "bundled": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "strip-json-comments": {
+ "version": "2.0.1",
+ "bundled": true,
+ "optional": true
+ },
+ "tar": {
+ "version": "4.4.1",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "chownr": "^1.0.1",
+ "fs-minipass": "^1.2.5",
+ "minipass": "^2.2.4",
+ "minizlib": "^1.1.0",
+ "mkdirp": "^0.5.0",
+ "safe-buffer": "^5.1.1",
+ "yallist": "^3.0.2"
+ }
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "bundled": true,
+ "optional": true
+ },
+ "wide-align": {
+ "version": "1.1.2",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "string-width": "^1.0.2"
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "bundled": true
+ },
+ "yallist": {
+ "version": "3.0.2",
+ "bundled": true
+ }
+ }
+ },
+ "function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+ },
+ "functional-red-black-tree": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc="
+ },
+ "get-caller-file": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz",
+ "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U="
+ },
+ "get-stdin": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
+ "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4="
+ },
+ "get-stream": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
+ "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
+ },
+ "get-value": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg="
+ },
+ "getpass": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "glob": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "glob-base": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
+ "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
+ "requires": {
+ "glob-parent": "^2.0.0",
+ "is-glob": "^2.0.0"
+ }
+ },
+ "glob-parent": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
+ "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
+ "requires": {
+ "is-glob": "^2.0.0"
+ }
+ },
+ "global-dirs": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz",
+ "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=",
+ "requires": {
+ "ini": "^1.3.4"
+ }
+ },
+ "global-modules": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
+ "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
+ "requires": {
+ "global-prefix": "^1.0.1",
+ "is-windows": "^1.0.1",
+ "resolve-dir": "^1.0.0"
+ }
+ },
+ "global-prefix": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz",
+ "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=",
+ "requires": {
+ "expand-tilde": "^2.0.2",
+ "homedir-polyfill": "^1.0.1",
+ "ini": "^1.3.4",
+ "is-windows": "^1.0.1",
+ "which": "^1.2.14"
+ }
+ },
+ "globals": {
+ "version": "9.18.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
+ "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ=="
+ },
+ "globby": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz",
+ "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=",
+ "requires": {
+ "array-union": "^1.0.1",
+ "arrify": "^1.0.0",
+ "glob": "^7.0.3",
+ "object-assign": "^4.0.1",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ }
+ },
+ "got": {
+ "version": "6.7.1",
+ "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz",
+ "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=",
+ "requires": {
+ "create-error-class": "^3.0.0",
+ "duplexer3": "^0.1.4",
+ "get-stream": "^3.0.0",
+ "is-redirect": "^1.0.0",
+ "is-retry-allowed": "^1.0.0",
+ "is-stream": "^1.0.0",
+ "lowercase-keys": "^1.0.0",
+ "safe-buffer": "^5.0.1",
+ "timed-out": "^4.0.0",
+ "unzip-response": "^2.0.1",
+ "url-parse-lax": "^1.0.0"
+ }
+ },
+ "graceful-fs": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
+ "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
+ },
+ "growly": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
+ "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE="
+ },
+ "gzip-size": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-3.0.0.tgz",
+ "integrity": "sha1-VGGI6b3DN/Zzdy+BZgRks4nc5SA=",
+ "requires": {
+ "duplexer": "^0.1.1"
+ }
+ },
+ "handle-thing": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-1.2.5.tgz",
+ "integrity": "sha1-/Xqtcmvxpf0W38KbL3pmAdJxOcQ="
+ },
+ "handlebars": {
+ "version": "4.0.11",
+ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz",
+ "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=",
+ "requires": {
+ "async": "^1.4.0",
+ "optimist": "^0.6.1",
+ "source-map": "^0.4.4",
+ "uglify-js": "^2.6"
+ },
+ "dependencies": {
+ "async": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
+ },
+ "source-map": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
+ "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
+ "requires": {
+ "amdefine": ">=0.0.4"
+ }
+ },
+ "uglify-js": {
+ "version": "2.8.29",
+ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
+ "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=",
+ "optional": true,
+ "requires": {
+ "source-map": "~0.5.1",
+ "uglify-to-browserify": "~1.0.0",
+ "yargs": "~3.10.0"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "optional": true
+ }
+ }
+ },
+ "yargs": {
+ "version": "3.10.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
+ "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
+ "optional": true,
+ "requires": {
+ "camelcase": "^1.0.2",
+ "cliui": "^2.1.0",
+ "decamelize": "^1.0.0",
+ "window-size": "0.1.0"
+ }
+ }
+ }
+ },
+ "har-schema": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
+ },
+ "har-validator": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz",
+ "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=",
+ "requires": {
+ "ajv": "^5.1.0",
+ "har-schema": "^2.0.0"
+ }
+ },
+ "has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "requires": {
+ "function-bind": "^1.1.1"
+ }
+ },
+ "has-ansi": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
+ },
+ "has-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
+ "requires": {
+ "get-value": "^2.0.6",
+ "has-values": "^1.0.0",
+ "isobject": "^3.0.0"
+ }
+ },
+ "has-values": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
+ "requires": {
+ "is-number": "^3.0.0",
+ "kind-of": "^4.0.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "hash-base": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz",
+ "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=",
+ "requires": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "hash.js": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.4.tgz",
+ "integrity": "sha512-A6RlQvvZEtFS5fLU43IDu0QUmBy+fDO9VMdTXvufKwIkt/rFfvICAViCax5fbDO4zdNzaC3/27ZhKUok5bAJyw==",
+ "requires": {
+ "inherits": "^2.0.3",
+ "minimalistic-assert": "^1.0.0"
+ }
+ },
+ "he": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
+ "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0="
+ },
+ "hmac-drbg": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
+ "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
+ "requires": {
+ "hash.js": "^1.0.3",
+ "minimalistic-assert": "^1.0.0",
+ "minimalistic-crypto-utils": "^1.0.1"
+ }
+ },
+ "home-or-tmp": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
+ "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=",
+ "requires": {
+ "os-homedir": "^1.0.0",
+ "os-tmpdir": "^1.0.1"
+ }
+ },
+ "homedir-polyfill": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz",
+ "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=",
+ "requires": {
+ "parse-passwd": "^1.0.0"
+ }
+ },
+ "hosted-git-info": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz",
+ "integrity": "sha512-lIbgIIQA3lz5XaB6vxakj6sDHADJiZadYEJB+FgA+C4nubM1NwcuvUr9EJPmnH1skZqpqUzWborWo8EIUi0Sdw=="
+ },
+ "hpack.js": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz",
+ "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=",
+ "requires": {
+ "inherits": "^2.0.1",
+ "obuf": "^1.0.0",
+ "readable-stream": "^2.0.1",
+ "wbuf": "^1.1.0"
+ }
+ },
+ "html-comment-regex": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.1.tgz",
+ "integrity": "sha1-ZouTd26q5V696POtRkswekljYl4="
+ },
+ "html-encoding-sniffer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz",
+ "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==",
+ "requires": {
+ "whatwg-encoding": "^1.0.1"
+ }
+ },
+ "html-entities": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz",
+ "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8="
+ },
+ "html-minifier": {
+ "version": "3.5.16",
+ "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.16.tgz",
+ "integrity": "sha512-zP5EfLSpiLRp0aAgud4CQXPQZm9kXwWjR/cF0PfdOj+jjWnOaCgeZcll4kYXSvIBPeUMmyaSc7mM4IDtA+kboA==",
+ "requires": {
+ "camel-case": "3.0.x",
+ "clean-css": "4.1.x",
+ "commander": "2.15.x",
+ "he": "1.1.x",
+ "param-case": "2.1.x",
+ "relateurl": "0.2.x",
+ "uglify-js": "3.3.x"
+ }
+ },
+ "html-webpack-plugin": {
+ "version": "2.29.0",
+ "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-2.29.0.tgz",
+ "integrity": "sha1-6Yf0IYU9O2k4yMTIFxhC5f0XryM=",
+ "requires": {
+ "bluebird": "^3.4.7",
+ "html-minifier": "^3.2.3",
+ "loader-utils": "^0.2.16",
+ "lodash": "^4.17.3",
+ "pretty-error": "^2.0.2",
+ "toposort": "^1.0.0"
+ },
+ "dependencies": {
+ "loader-utils": {
+ "version": "0.2.17",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz",
+ "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=",
+ "requires": {
+ "big.js": "^3.1.3",
+ "emojis-list": "^2.0.0",
+ "json5": "^0.5.0",
+ "object-assign": "^4.0.1"
+ }
+ }
+ }
+ },
+ "htmlparser2": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.3.0.tgz",
+ "integrity": "sha1-zHDQWln2VC5D8OaFyYLhTJJKnv4=",
+ "requires": {
+ "domelementtype": "1",
+ "domhandler": "2.1",
+ "domutils": "1.1",
+ "readable-stream": "1.0"
+ },
+ "dependencies": {
+ "domutils": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.1.6.tgz",
+ "integrity": "sha1-vdw94Jm5ou+sxRxiPyj0FuzFdIU=",
+ "requires": {
+ "domelementtype": "1"
+ }
+ },
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+ },
+ "readable-stream": {
+ "version": "1.0.34",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
+ "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.1",
+ "isarray": "0.0.1",
+ "string_decoder": "~0.10.x"
+ }
+ },
+ "string_decoder": {
+ "version": "0.10.31",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+ }
+ }
+ },
+ "http-deceiver": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz",
+ "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc="
+ },
+ "http-errors": {
+ "version": "1.6.3",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
+ "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
+ "requires": {
+ "depd": "~1.1.2",
+ "inherits": "2.0.3",
+ "setprototypeof": "1.1.0",
+ "statuses": ">= 1.4.0 < 2"
+ }
+ },
+ "http-parser-js": {
+ "version": "0.4.13",
+ "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.13.tgz",
+ "integrity": "sha1-O9bW/ebjFyyTNMOzO2wZPYD+ETc="
+ },
+ "http-proxy": {
+ "version": "1.17.0",
+ "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz",
+ "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==",
+ "requires": {
+ "eventemitter3": "^3.0.0",
+ "follow-redirects": "^1.0.0",
+ "requires-port": "^1.0.0"
+ }
+ },
+ "http-proxy-middleware": {
+ "version": "0.17.4",
+ "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.17.4.tgz",
+ "integrity": "sha1-ZC6ISIUdZvCdTxJJEoRtuutBuDM=",
+ "requires": {
+ "http-proxy": "^1.16.2",
+ "is-glob": "^3.1.0",
+ "lodash": "^4.17.2",
+ "micromatch": "^2.3.11"
+ },
+ "dependencies": {
+ "arr-diff": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
+ "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
+ "requires": {
+ "arr-flatten": "^1.0.1"
+ }
+ },
+ "array-unique": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
+ "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM="
+ },
+ "braces": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
+ "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
+ "requires": {
+ "expand-range": "^1.8.1",
+ "preserve": "^0.2.0",
+ "repeat-element": "^1.1.2"
+ }
+ },
+ "expand-brackets": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
+ "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
+ "requires": {
+ "is-posix-bracket": "^0.1.0"
+ }
+ },
+ "extglob": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
+ "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
+ "requires": {
+ "is-extglob": "^1.0.0"
+ },
+ "dependencies": {
+ "is-extglob": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+ "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA="
+ }
+ }
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
+ },
+ "is-glob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+ "requires": {
+ "is-extglob": "^2.1.0"
+ }
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ },
+ "micromatch": {
+ "version": "2.3.11",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
+ "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
+ "requires": {
+ "arr-diff": "^2.0.0",
+ "array-unique": "^0.2.1",
+ "braces": "^1.8.2",
+ "expand-brackets": "^0.1.4",
+ "extglob": "^0.3.1",
+ "filename-regex": "^2.0.0",
+ "is-extglob": "^1.0.0",
+ "is-glob": "^2.0.1",
+ "kind-of": "^3.0.2",
+ "normalize-path": "^2.0.1",
+ "object.omit": "^2.0.0",
+ "parse-glob": "^3.0.4",
+ "regex-cache": "^0.4.2"
+ },
+ "dependencies": {
+ "is-extglob": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+ "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA="
+ },
+ "is-glob": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+ "requires": {
+ "is-extglob": "^1.0.0"
+ }
+ }
+ }
+ }
+ }
+ },
+ "http-signature": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+ "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+ "requires": {
+ "assert-plus": "^1.0.0",
+ "jsprim": "^1.2.2",
+ "sshpk": "^1.7.0"
+ }
+ },
+ "httpplease": {
+ "version": "0.16.4",
+ "resolved": "https://registry.npmjs.org/httpplease/-/httpplease-0.16.4.tgz",
+ "integrity": "sha1-04Lr4jDvUHkIC06f/r8xap51wNo=",
+ "requires": {
+ "urllite": "~0.5.0",
+ "xmlhttprequest": "*",
+ "xtend": "~3.0.0"
+ }
+ },
+ "https-browserify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
+ "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM="
+ },
+ "iconv-lite": {
+ "version": "0.4.23",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
+ "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "icss-replace-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz",
+ "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0="
+ },
+ "icss-utils": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-2.1.0.tgz",
+ "integrity": "sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=",
+ "requires": {
+ "postcss": "^6.0.1"
+ }
+ },
+ "ieee754": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz",
+ "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA=="
+ },
+ "ignore": {
+ "version": "3.3.8",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.8.tgz",
+ "integrity": "sha512-pUh+xUQQhQzevjRHHFqqcTy0/dP/kS9I8HSrUydhihjuD09W6ldVWFtIrwhXdUJHis3i2rZNqEHpZH/cbinFbg=="
+ },
+ "import-lazy": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz",
+ "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM="
+ },
+ "import-local": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/import-local/-/import-local-0.1.1.tgz",
+ "integrity": "sha1-sReVcqrNwRxqkQCftDDbyrX2aKg=",
+ "requires": {
+ "pkg-dir": "^2.0.0",
+ "resolve-cwd": "^2.0.0"
+ }
+ },
+ "imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o="
+ },
+ "indent-string": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
+ "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",
+ "requires": {
+ "repeating": "^2.0.0"
+ }
+ },
+ "indexes-of": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
+ "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc="
+ },
+ "indexof": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
+ "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10="
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ },
+ "ini": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
+ },
+ "inquirer": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz",
+ "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==",
+ "requires": {
+ "ansi-escapes": "^3.0.0",
+ "chalk": "^2.0.0",
+ "cli-cursor": "^2.1.0",
+ "cli-width": "^2.0.0",
+ "external-editor": "^2.0.4",
+ "figures": "^2.0.0",
+ "lodash": "^4.3.0",
+ "mute-stream": "0.0.7",
+ "run-async": "^2.2.0",
+ "rx-lite": "^4.0.8",
+ "rx-lite-aggregates": "^4.0.8",
+ "string-width": "^2.1.0",
+ "strip-ansi": "^4.0.0",
+ "through": "^2.3.6"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
+ },
+ "chalk": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
+ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "requires": {
+ "ansi-regex": "^3.0.0"
+ }
+ }
+ }
+ },
+ "internal-ip": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-1.2.0.tgz",
+ "integrity": "sha1-rp+/k7mEh4eF1QqN4bNWlWBYz1w=",
+ "requires": {
+ "meow": "^3.3.0"
+ }
+ },
+ "interpret": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz",
+ "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ="
+ },
+ "invariant": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
+ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
+ "requires": {
+ "loose-envify": "^1.0.0"
+ }
+ },
+ "invert-kv": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
+ "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY="
+ },
+ "ip": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
+ "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo="
+ },
+ "ipaddr.js": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.6.0.tgz",
+ "integrity": "sha1-4/o1e3c9phnybpXwSdBVxyeW+Gs="
+ },
+ "is-absolute-url": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz",
+ "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY="
+ },
+ "is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
+ },
+ "is-binary-path": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
+ "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
+ "requires": {
+ "binary-extensions": "^1.0.0"
+ }
+ },
+ "is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
+ },
+ "is-builtin-module": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
+ "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
+ "requires": {
+ "builtin-modules": "^1.0.0"
+ }
+ },
+ "is-callable": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz",
+ "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI="
+ },
+ "is-ci": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.1.0.tgz",
+ "integrity": "sha512-c7TnwxLePuqIlxHgr7xtxzycJPegNHFuIrBkwbf8hc58//+Op1CqFkyS+xnIMkwn9UsJIwc174BIjkyBmSpjKg==",
+ "requires": {
+ "ci-info": "^1.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-date-object": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
+ "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY="
+ },
+ "is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "requires": {
+ "is-accessor-descriptor": "^0.1.6",
+ "is-data-descriptor": "^0.1.4",
+ "kind-of": "^5.0.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw=="
+ }
+ }
+ },
+ "is-directory": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
+ "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE="
+ },
+ "is-dotfile": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
+ "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE="
+ },
+ "is-equal-shallow": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
+ "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
+ "requires": {
+ "is-primitive": "^2.0.0"
+ }
+ },
+ "is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik="
+ },
+ "is-extglob": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+ "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA="
+ },
+ "is-finite": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz",
+ "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=",
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "is-fullwidth-code-point": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
+ },
+ "is-glob": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+ "requires": {
+ "is-extglob": "^1.0.0"
+ }
+ },
+ "is-installed-globally": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz",
+ "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=",
+ "requires": {
+ "global-dirs": "^0.1.0",
+ "is-path-inside": "^1.0.0"
+ }
+ },
+ "is-npm": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz",
+ "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ="
+ },
+ "is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-obj": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
+ "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8="
+ },
+ "is-odd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz",
+ "integrity": "sha512-OTiixgpZAT1M4NHgS5IguFp/Vz2VI3U7Goh4/HA1adtwyLtSBrxYlcSYkhpAE07s4fKEcjrFxyvtQBND4vFQyQ==",
+ "requires": {
+ "is-number": "^4.0.0"
+ },
+ "dependencies": {
+ "is-number": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
+ "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ=="
+ }
+ }
+ },
+ "is-path-cwd": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz",
+ "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0="
+ },
+ "is-path-in-cwd": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz",
+ "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==",
+ "requires": {
+ "is-path-inside": "^1.0.0"
+ }
+ },
+ "is-path-inside": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz",
+ "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=",
+ "requires": {
+ "path-is-inside": "^1.0.1"
+ }
+ },
+ "is-plain-obj": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
+ "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4="
+ },
+ "is-plain-object": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+ "requires": {
+ "isobject": "^3.0.1"
+ }
+ },
+ "is-posix-bracket": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
+ "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q="
+ },
+ "is-primitive": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
+ "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU="
+ },
+ "is-promise": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
+ "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o="
+ },
+ "is-redirect": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz",
+ "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ="
+ },
+ "is-regex": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
+ "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
+ "requires": {
+ "has": "^1.0.1"
+ }
+ },
+ "is-resolvable": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz",
+ "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg=="
+ },
+ "is-retry-allowed": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz",
+ "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ="
+ },
+ "is-root": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-root/-/is-root-1.0.0.tgz",
+ "integrity": "sha1-B7bCM7w5TNnQK6FclmvWZg1jQtU="
+ },
+ "is-stream": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
+ },
+ "is-svg": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-2.1.0.tgz",
+ "integrity": "sha1-z2EJDaDZ77yrhyLeum8DIgjbsOk=",
+ "requires": {
+ "html-comment-regex": "^1.1.0"
+ }
+ },
+ "is-symbol": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz",
+ "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI="
+ },
+ "is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
+ },
+ "is-utf8": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+ "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI="
+ },
+ "is-windows": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA=="
+ },
+ "is-wsl": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
+ "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0="
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+ },
+ "isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
+ },
+ "isomorphic-fetch": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
+ "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=",
+ "requires": {
+ "node-fetch": "^1.0.1",
+ "whatwg-fetch": ">=0.10.0"
+ }
+ },
+ "isstream": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
+ },
+ "istanbul-api": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.3.1.tgz",
+ "integrity": "sha512-duj6AlLcsWNwUpfyfHt0nWIeRiZpuShnP40YTxOGQgtaN8fd6JYSxsvxUphTDy8V5MfDXo4s/xVCIIvVCO808g==",
+ "requires": {
+ "async": "^2.1.4",
+ "compare-versions": "^3.1.0",
+ "fileset": "^2.0.2",
+ "istanbul-lib-coverage": "^1.2.0",
+ "istanbul-lib-hook": "^1.2.0",
+ "istanbul-lib-instrument": "^1.10.1",
+ "istanbul-lib-report": "^1.1.4",
+ "istanbul-lib-source-maps": "^1.2.4",
+ "istanbul-reports": "^1.3.0",
+ "js-yaml": "^3.7.0",
+ "mkdirp": "^0.5.1",
+ "once": "^1.4.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "istanbul-lib-source-maps": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.5.tgz",
+ "integrity": "sha512-8O2T/3VhrQHn0XcJbP1/GN7kXMiRAlPi+fj3uEHrjBD8Oz7Py0prSC25C09NuAZS6bgW1NNKAvCSHZXB0irSGA==",
+ "requires": {
+ "debug": "^3.1.0",
+ "istanbul-lib-coverage": "^1.2.0",
+ "mkdirp": "^0.5.1",
+ "rimraf": "^2.6.1",
+ "source-map": "^0.5.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ }
+ }
+ },
+ "istanbul-lib-coverage": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.0.tgz",
+ "integrity": "sha512-GvgM/uXRwm+gLlvkWHTjDAvwynZkL9ns15calTrmhGgowlwJBbWMYzWbKqE2DT6JDP1AFXKa+Zi0EkqNCUqY0A=="
+ },
+ "istanbul-lib-hook": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.2.1.tgz",
+ "integrity": "sha512-eLAMkPG9FU0v5L02lIkcj/2/Zlz9OuluaXikdr5iStk8FDbSwAixTK9TkYxbF0eNnzAJTwM2fkV2A1tpsIp4Jg==",
+ "requires": {
+ "append-transform": "^1.0.0"
+ }
+ },
+ "istanbul-lib-instrument": {
+ "version": "1.10.1",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.1.tgz",
+ "integrity": "sha512-1dYuzkOCbuR5GRJqySuZdsmsNKPL3PTuyPevQfoCXJePT9C8y1ga75neU+Tuy9+yS3G/dgx8wgOmp2KLpgdoeQ==",
+ "requires": {
+ "babel-generator": "^6.18.0",
+ "babel-template": "^6.16.0",
+ "babel-traverse": "^6.18.0",
+ "babel-types": "^6.18.0",
+ "babylon": "^6.18.0",
+ "istanbul-lib-coverage": "^1.2.0",
+ "semver": "^5.3.0"
+ }
+ },
+ "istanbul-lib-report": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.4.tgz",
+ "integrity": "sha512-Azqvq5tT0U09nrncK3q82e/Zjkxa4tkFZv7E6VcqP0QCPn6oNljDPfrZEC/umNXds2t7b8sRJfs6Kmpzt8m2kA==",
+ "requires": {
+ "istanbul-lib-coverage": "^1.2.0",
+ "mkdirp": "^0.5.1",
+ "path-parse": "^1.0.5",
+ "supports-color": "^3.1.2"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "istanbul-lib-source-maps": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.3.tgz",
+ "integrity": "sha512-fDa0hwU/5sDXwAklXgAoCJCOsFsBplVQ6WBldz5UwaqOzmDhUK4nfuR7/G//G2lERlblUNJB8P6e8cXq3a7MlA==",
+ "requires": {
+ "debug": "^3.1.0",
+ "istanbul-lib-coverage": "^1.1.2",
+ "mkdirp": "^0.5.1",
+ "rimraf": "^2.6.1",
+ "source-map": "^0.5.3"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ }
+ }
+ },
+ "istanbul-reports": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.3.0.tgz",
+ "integrity": "sha512-y2Z2IMqE1gefWUaVjrBm0mSKvUkaBy9Vqz8iwr/r40Y9hBbIteH5wqHG/9DLTfJ9xUnUT2j7A3+VVJ6EaYBllA==",
+ "requires": {
+ "handlebars": "^4.0.3"
+ }
+ },
+ "jest": {
+ "version": "20.0.4",
+ "resolved": "https://registry.npmjs.org/jest/-/jest-20.0.4.tgz",
+ "integrity": "sha1-PdJgwpidba1nix6cxNkZRPbWAqw=",
+ "requires": {
+ "jest-cli": "^20.0.4"
+ },
+ "dependencies": {
+ "ansi-escapes": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz",
+ "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4="
+ },
+ "arr-diff": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
+ "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
+ "requires": {
+ "arr-flatten": "^1.0.1"
+ }
+ },
+ "array-unique": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
+ "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM="
+ },
+ "braces": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
+ "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
+ "requires": {
+ "expand-range": "^1.8.1",
+ "preserve": "^0.2.0",
+ "repeat-element": "^1.1.2"
+ }
+ },
+ "callsites": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
+ "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA="
+ },
+ "expand-brackets": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
+ "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
+ "requires": {
+ "is-posix-bracket": "^0.1.0"
+ }
+ },
+ "extglob": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
+ "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
+ "requires": {
+ "is-extglob": "^1.0.0"
+ }
+ },
+ "jest-cli": {
+ "version": "20.0.4",
+ "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-20.0.4.tgz",
+ "integrity": "sha1-5TKxnYiuW8bEF+iwWTpv6VSx3JM=",
+ "requires": {
+ "ansi-escapes": "^1.4.0",
+ "callsites": "^2.0.0",
+ "chalk": "^1.1.3",
+ "graceful-fs": "^4.1.11",
+ "is-ci": "^1.0.10",
+ "istanbul-api": "^1.1.1",
+ "istanbul-lib-coverage": "^1.0.1",
+ "istanbul-lib-instrument": "^1.4.2",
+ "istanbul-lib-source-maps": "^1.1.0",
+ "jest-changed-files": "^20.0.3",
+ "jest-config": "^20.0.4",
+ "jest-docblock": "^20.0.3",
+ "jest-environment-jsdom": "^20.0.3",
+ "jest-haste-map": "^20.0.4",
+ "jest-jasmine2": "^20.0.4",
+ "jest-message-util": "^20.0.3",
+ "jest-regex-util": "^20.0.3",
+ "jest-resolve-dependencies": "^20.0.3",
+ "jest-runtime": "^20.0.4",
+ "jest-snapshot": "^20.0.3",
+ "jest-util": "^20.0.3",
+ "micromatch": "^2.3.11",
+ "node-notifier": "^5.0.2",
+ "pify": "^2.3.0",
+ "slash": "^1.0.0",
+ "string-length": "^1.0.1",
+ "throat": "^3.0.0",
+ "which": "^1.2.12",
+ "worker-farm": "^1.3.1",
+ "yargs": "^7.0.2"
+ }
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ },
+ "micromatch": {
+ "version": "2.3.11",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
+ "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
+ "requires": {
+ "arr-diff": "^2.0.0",
+ "array-unique": "^0.2.1",
+ "braces": "^1.8.2",
+ "expand-brackets": "^0.1.4",
+ "extglob": "^0.3.1",
+ "filename-regex": "^2.0.0",
+ "is-extglob": "^1.0.0",
+ "is-glob": "^2.0.1",
+ "kind-of": "^3.0.2",
+ "normalize-path": "^2.0.1",
+ "object.omit": "^2.0.0",
+ "parse-glob": "^3.0.4",
+ "regex-cache": "^0.4.2"
+ }
+ }
+ }
+ },
+ "jest-changed-files": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-20.0.3.tgz",
+ "integrity": "sha1-k5TVzGXEOEBhSb7xv01Sto4D4/g="
+ },
+ "jest-config": {
+ "version": "20.0.4",
+ "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-20.0.4.tgz",
+ "integrity": "sha1-43kwqyIXyRNgXv8T5712PsSPruo=",
+ "requires": {
+ "chalk": "^1.1.3",
+ "glob": "^7.1.1",
+ "jest-environment-jsdom": "^20.0.3",
+ "jest-environment-node": "^20.0.3",
+ "jest-jasmine2": "^20.0.4",
+ "jest-matcher-utils": "^20.0.3",
+ "jest-regex-util": "^20.0.3",
+ "jest-resolve": "^20.0.4",
+ "jest-validate": "^20.0.3",
+ "pretty-format": "^20.0.3"
+ }
+ },
+ "jest-diff": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-20.0.3.tgz",
+ "integrity": "sha1-gfKI/Z5nXw+yPHXxwrGURf5YZhc=",
+ "requires": {
+ "chalk": "^1.1.3",
+ "diff": "^3.2.0",
+ "jest-matcher-utils": "^20.0.3",
+ "pretty-format": "^20.0.3"
+ }
+ },
+ "jest-docblock": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-20.0.3.tgz",
+ "integrity": "sha1-F76phDQswz2DxQ++FUXqDvqkRxI="
+ },
+ "jest-environment-jsdom": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-20.0.3.tgz",
+ "integrity": "sha1-BIqKwS7iJfcZBBdxODS7mZeH3pk=",
+ "requires": {
+ "jest-mock": "^20.0.3",
+ "jest-util": "^20.0.3",
+ "jsdom": "^9.12.0"
+ }
+ },
+ "jest-environment-node": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-20.0.3.tgz",
+ "integrity": "sha1-1Ii8RhKvLCRumG6K52caCZFj1AM=",
+ "requires": {
+ "jest-mock": "^20.0.3",
+ "jest-util": "^20.0.3"
+ }
+ },
+ "jest-haste-map": {
+ "version": "20.0.5",
+ "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-20.0.5.tgz",
+ "integrity": "sha512-0IKAQjUvuZjMCNi/0VNQQF74/H9KB67hsHJqGiwTWQC6XO5Azs7kLWm+6Q/dwuhvDUvABDOBMFK2/FwZ3sZ07Q==",
+ "requires": {
+ "fb-watchman": "^2.0.0",
+ "graceful-fs": "^4.1.11",
+ "jest-docblock": "^20.0.3",
+ "micromatch": "^2.3.11",
+ "sane": "~1.6.0",
+ "worker-farm": "^1.3.1"
+ },
+ "dependencies": {
+ "arr-diff": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
+ "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
+ "requires": {
+ "arr-flatten": "^1.0.1"
+ }
+ },
+ "array-unique": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
+ "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM="
+ },
+ "braces": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
+ "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
+ "requires": {
+ "expand-range": "^1.8.1",
+ "preserve": "^0.2.0",
+ "repeat-element": "^1.1.2"
+ }
+ },
+ "expand-brackets": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
+ "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
+ "requires": {
+ "is-posix-bracket": "^0.1.0"
+ }
+ },
+ "extglob": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
+ "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
+ "requires": {
+ "is-extglob": "^1.0.0"
+ }
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ },
+ "micromatch": {
+ "version": "2.3.11",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
+ "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
+ "requires": {
+ "arr-diff": "^2.0.0",
+ "array-unique": "^0.2.1",
+ "braces": "^1.8.2",
+ "expand-brackets": "^0.1.4",
+ "extglob": "^0.3.1",
+ "filename-regex": "^2.0.0",
+ "is-extglob": "^1.0.0",
+ "is-glob": "^2.0.1",
+ "kind-of": "^3.0.2",
+ "normalize-path": "^2.0.1",
+ "object.omit": "^2.0.0",
+ "parse-glob": "^3.0.4",
+ "regex-cache": "^0.4.2"
+ }
+ }
+ }
+ },
+ "jest-jasmine2": {
+ "version": "20.0.4",
+ "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-20.0.4.tgz",
+ "integrity": "sha1-/MWxQReA2RHQQpAu8YWehS5g1eE=",
+ "requires": {
+ "chalk": "^1.1.3",
+ "graceful-fs": "^4.1.11",
+ "jest-diff": "^20.0.3",
+ "jest-matcher-utils": "^20.0.3",
+ "jest-matchers": "^20.0.3",
+ "jest-message-util": "^20.0.3",
+ "jest-snapshot": "^20.0.3",
+ "once": "^1.4.0",
+ "p-map": "^1.1.1"
+ }
+ },
+ "jest-matcher-utils": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-20.0.3.tgz",
+ "integrity": "sha1-s6a443yld4A7CDKpixZPRLeBVhI=",
+ "requires": {
+ "chalk": "^1.1.3",
+ "pretty-format": "^20.0.3"
+ }
+ },
+ "jest-matchers": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-matchers/-/jest-matchers-20.0.3.tgz",
+ "integrity": "sha1-ymnbHDLbWm9wf6XgQBq7VXAN/WA=",
+ "requires": {
+ "jest-diff": "^20.0.3",
+ "jest-matcher-utils": "^20.0.3",
+ "jest-message-util": "^20.0.3",
+ "jest-regex-util": "^20.0.3"
+ }
+ },
+ "jest-message-util": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-20.0.3.tgz",
+ "integrity": "sha1-auwoRDBvyw5udNV5bBAG2W/dgxw=",
+ "requires": {
+ "chalk": "^1.1.3",
+ "micromatch": "^2.3.11",
+ "slash": "^1.0.0"
+ },
+ "dependencies": {
+ "arr-diff": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
+ "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
+ "requires": {
+ "arr-flatten": "^1.0.1"
+ }
+ },
+ "array-unique": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
+ "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM="
+ },
+ "braces": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
+ "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
+ "requires": {
+ "expand-range": "^1.8.1",
+ "preserve": "^0.2.0",
+ "repeat-element": "^1.1.2"
+ }
+ },
+ "expand-brackets": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
+ "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
+ "requires": {
+ "is-posix-bracket": "^0.1.0"
+ }
+ },
+ "extglob": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
+ "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
+ "requires": {
+ "is-extglob": "^1.0.0"
+ }
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ },
+ "micromatch": {
+ "version": "2.3.11",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
+ "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
+ "requires": {
+ "arr-diff": "^2.0.0",
+ "array-unique": "^0.2.1",
+ "braces": "^1.8.2",
+ "expand-brackets": "^0.1.4",
+ "extglob": "^0.3.1",
+ "filename-regex": "^2.0.0",
+ "is-extglob": "^1.0.0",
+ "is-glob": "^2.0.1",
+ "kind-of": "^3.0.2",
+ "normalize-path": "^2.0.1",
+ "object.omit": "^2.0.0",
+ "parse-glob": "^3.0.4",
+ "regex-cache": "^0.4.2"
+ }
+ }
+ }
+ },
+ "jest-mock": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-20.0.3.tgz",
+ "integrity": "sha1-i8Bw6QQUqhVcEajWTIaaDVxx2lk="
+ },
+ "jest-regex-util": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-20.0.3.tgz",
+ "integrity": "sha1-hburXRM+RGJbGfr4xqpRItCF12I="
+ },
+ "jest-resolve": {
+ "version": "20.0.4",
+ "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-20.0.4.tgz",
+ "integrity": "sha1-lEiz6La6/BVHlETGSZBFt//ll6U=",
+ "requires": {
+ "browser-resolve": "^1.11.2",
+ "is-builtin-module": "^1.0.0",
+ "resolve": "^1.3.2"
+ }
+ },
+ "jest-resolve-dependencies": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-20.0.3.tgz",
+ "integrity": "sha1-bhSntxevDyyzZnxUneQK8Bexcjo=",
+ "requires": {
+ "jest-regex-util": "^20.0.3"
+ }
+ },
+ "jest-runtime": {
+ "version": "20.0.4",
+ "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-20.0.4.tgz",
+ "integrity": "sha1-osgCIZxCA/dU3xQE5JAYYWnRJNg=",
+ "requires": {
+ "babel-core": "^6.0.0",
+ "babel-jest": "^20.0.3",
+ "babel-plugin-istanbul": "^4.0.0",
+ "chalk": "^1.1.3",
+ "convert-source-map": "^1.4.0",
+ "graceful-fs": "^4.1.11",
+ "jest-config": "^20.0.4",
+ "jest-haste-map": "^20.0.4",
+ "jest-regex-util": "^20.0.3",
+ "jest-resolve": "^20.0.4",
+ "jest-util": "^20.0.3",
+ "json-stable-stringify": "^1.0.1",
+ "micromatch": "^2.3.11",
+ "strip-bom": "3.0.0",
+ "yargs": "^7.0.2"
+ },
+ "dependencies": {
+ "arr-diff": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
+ "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
+ "requires": {
+ "arr-flatten": "^1.0.1"
+ }
+ },
+ "array-unique": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
+ "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM="
+ },
+ "braces": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
+ "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
+ "requires": {
+ "expand-range": "^1.8.1",
+ "preserve": "^0.2.0",
+ "repeat-element": "^1.1.2"
+ }
+ },
+ "expand-brackets": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
+ "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
+ "requires": {
+ "is-posix-bracket": "^0.1.0"
+ }
+ },
+ "extglob": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
+ "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
+ "requires": {
+ "is-extglob": "^1.0.0"
+ }
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ },
+ "micromatch": {
+ "version": "2.3.11",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
+ "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
+ "requires": {
+ "arr-diff": "^2.0.0",
+ "array-unique": "^0.2.1",
+ "braces": "^1.8.2",
+ "expand-brackets": "^0.1.4",
+ "extglob": "^0.3.1",
+ "filename-regex": "^2.0.0",
+ "is-extglob": "^1.0.0",
+ "is-glob": "^2.0.1",
+ "kind-of": "^3.0.2",
+ "normalize-path": "^2.0.1",
+ "object.omit": "^2.0.0",
+ "parse-glob": "^3.0.4",
+ "regex-cache": "^0.4.2"
+ }
+ },
+ "strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM="
+ }
+ }
+ },
+ "jest-snapshot": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-20.0.3.tgz",
+ "integrity": "sha1-W4R+GtsaTZCFKn+fElCG4YfHZWY=",
+ "requires": {
+ "chalk": "^1.1.3",
+ "jest-diff": "^20.0.3",
+ "jest-matcher-utils": "^20.0.3",
+ "jest-util": "^20.0.3",
+ "natural-compare": "^1.4.0",
+ "pretty-format": "^20.0.3"
+ }
+ },
+ "jest-util": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-20.0.3.tgz",
+ "integrity": "sha1-DAf32A2C9OWmfG+LnD/n9lz9Mq0=",
+ "requires": {
+ "chalk": "^1.1.3",
+ "graceful-fs": "^4.1.11",
+ "jest-message-util": "^20.0.3",
+ "jest-mock": "^20.0.3",
+ "jest-validate": "^20.0.3",
+ "leven": "^2.1.0",
+ "mkdirp": "^0.5.1"
+ }
+ },
+ "jest-validate": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-20.0.3.tgz",
+ "integrity": "sha1-0M/R3k9XnymEhJJcKA+PHZTsPKs=",
+ "requires": {
+ "chalk": "^1.1.3",
+ "jest-matcher-utils": "^20.0.3",
+ "leven": "^2.1.0",
+ "pretty-format": "^20.0.3"
+ }
+ },
+ "jquery": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz",
+ "integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg=="
+ },
+ "js-base64": {
+ "version": "2.4.5",
+ "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.5.tgz",
+ "integrity": "sha512-aUnNwqMOXw3yvErjMPSQu6qIIzUmT1e5KcU1OZxRDU1g/am6mzBvcrmLAYwzmB59BHPrh5/tKaiF4OPhqRWESQ=="
+ },
+ "js-tokens": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
+ "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
+ },
+ "js-yaml": {
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz",
+ "integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=",
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^2.6.0"
+ }
+ },
+ "jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+ "optional": true
+ },
+ "jsdom": {
+ "version": "9.12.0",
+ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-9.12.0.tgz",
+ "integrity": "sha1-6MVG//ywbADUgzyoRBD+1/igl9Q=",
+ "requires": {
+ "abab": "^1.0.3",
+ "acorn": "^4.0.4",
+ "acorn-globals": "^3.1.0",
+ "array-equal": "^1.0.0",
+ "content-type-parser": "^1.0.1",
+ "cssom": ">= 0.3.2 < 0.4.0",
+ "cssstyle": ">= 0.2.37 < 0.3.0",
+ "escodegen": "^1.6.1",
+ "html-encoding-sniffer": "^1.0.1",
+ "nwmatcher": ">= 1.3.9 < 2.0.0",
+ "parse5": "^1.5.1",
+ "request": "^2.79.0",
+ "sax": "^1.2.1",
+ "symbol-tree": "^3.2.1",
+ "tough-cookie": "^2.3.2",
+ "webidl-conversions": "^4.0.0",
+ "whatwg-encoding": "^1.0.1",
+ "whatwg-url": "^4.3.0",
+ "xml-name-validator": "^2.0.1"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "4.0.13",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz",
+ "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c="
+ }
+ }
+ },
+ "jsesc": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
+ "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s="
+ },
+ "json-loader": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz",
+ "integrity": "sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w=="
+ },
+ "json-schema": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
+ },
+ "json-schema-traverse": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
+ "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
+ },
+ "json-stable-stringify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
+ "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
+ "requires": {
+ "jsonify": "~0.0.0"
+ }
+ },
+ "json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
+ "dev": true
+ },
+ "json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
+ },
+ "json3": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz",
+ "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE="
+ },
+ "json5": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
+ "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE="
+ },
+ "jsonfile": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz",
+ "integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=",
+ "requires": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "jsonify": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
+ "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM="
+ },
+ "jsprim": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+ "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+ "requires": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.2.3",
+ "verror": "1.10.0"
+ }
+ },
+ "jsx-ast-utils": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz",
+ "integrity": "sha1-OGchPo3Xm/Ho8jAMDPwe+xgsDfE="
+ },
+ "killable": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.0.tgz",
+ "integrity": "sha1-2ouEvUfeU5WHj5XWTQLyRJ/gXms="
+ },
+ "kind-of": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA=="
+ },
+ "klaw": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz",
+ "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=",
+ "requires": {
+ "graceful-fs": "^4.1.9"
+ }
+ },
+ "latest-version": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz",
+ "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=",
+ "requires": {
+ "package-json": "^4.0.0"
+ }
+ },
+ "lazy-cache": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
+ "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4="
+ },
+ "lcid": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
+ "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
+ "requires": {
+ "invert-kv": "^1.0.0"
+ }
+ },
+ "leven": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz",
+ "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA="
+ },
+ "levn": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+ "requires": {
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2"
+ }
+ },
+ "load-json-file": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
+ "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "parse-json": "^2.2.0",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0",
+ "strip-bom": "^2.0.0"
+ }
+ },
+ "loader-fs-cache": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/loader-fs-cache/-/loader-fs-cache-1.0.1.tgz",
+ "integrity": "sha1-VuC/CL2XCLJqdltoUJhAyN7J/bw=",
+ "requires": {
+ "find-cache-dir": "^0.1.1",
+ "mkdirp": "0.5.1"
+ },
+ "dependencies": {
+ "find-cache-dir": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz",
+ "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=",
+ "requires": {
+ "commondir": "^1.0.1",
+ "mkdirp": "^0.5.1",
+ "pkg-dir": "^1.0.0"
+ }
+ },
+ "find-up": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
+ "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
+ "requires": {
+ "path-exists": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ }
+ },
+ "path-exists": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
+ "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
+ "requires": {
+ "pinkie-promise": "^2.0.0"
+ }
+ },
+ "pkg-dir": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz",
+ "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=",
+ "requires": {
+ "find-up": "^1.0.0"
+ }
+ }
+ }
+ },
+ "loader-runner": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.3.0.tgz",
+ "integrity": "sha1-9IKuqC1UPgeSFwDVpG7yb9rGuKI="
+ },
+ "loader-utils": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz",
+ "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=",
+ "requires": {
+ "big.js": "^3.1.3",
+ "emojis-list": "^2.0.0",
+ "json5": "^0.5.0"
+ }
+ },
+ "locate-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
+ "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
+ "requires": {
+ "p-locate": "^2.0.0",
+ "path-exists": "^3.0.0"
+ }
+ },
+ "lodash": {
+ "version": "4.17.10",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
+ "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg=="
+ },
+ "lodash._reinterpolate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
+ "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0="
+ },
+ "lodash.camelcase": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+ "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY="
+ },
+ "lodash.cond": {
+ "version": "4.5.2",
+ "resolved": "https://registry.npmjs.org/lodash.cond/-/lodash.cond-4.5.2.tgz",
+ "integrity": "sha1-9HGh2khr5g9quVXRcRVSPdHSVdU="
+ },
+ "lodash.defaults": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
+ "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw="
+ },
+ "lodash.memoize": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
+ "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4="
+ },
+ "lodash.template": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz",
+ "integrity": "sha1-5zoDhcg1VZF0bgILmWecaQ5o+6A=",
+ "requires": {
+ "lodash._reinterpolate": "~3.0.0",
+ "lodash.templatesettings": "^4.0.0"
+ }
+ },
+ "lodash.templatesettings": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz",
+ "integrity": "sha1-K01OlbpEDZFf8IvImeRVNmZxMxY=",
+ "requires": {
+ "lodash._reinterpolate": "~3.0.0"
+ }
+ },
+ "lodash.uniq": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
+ "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M="
+ },
+ "loglevel": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.1.tgz",
+ "integrity": "sha1-4PyVEztu8nbNyIh82vJKpvFW+Po="
+ },
+ "longest": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
+ "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc="
+ },
+ "loose-envify": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz",
+ "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=",
+ "requires": {
+ "js-tokens": "^3.0.0"
+ }
+ },
+ "loud-rejection": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
+ "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",
+ "requires": {
+ "currently-unhandled": "^0.4.1",
+ "signal-exit": "^3.0.0"
+ }
+ },
+ "lower-case": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz",
+ "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw="
+ },
+ "lowercase-keys": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
+ "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA=="
+ },
+ "lru-cache": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz",
+ "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==",
+ "requires": {
+ "pseudomap": "^1.0.2",
+ "yallist": "^2.1.2"
+ }
+ },
+ "make-dir": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
+ "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
+ "requires": {
+ "pify": "^3.0.0"
+ },
+ "dependencies": {
+ "pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY="
+ }
+ }
+ },
+ "makeerror": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz",
+ "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=",
+ "requires": {
+ "tmpl": "1.0.x"
+ }
+ },
+ "map-cache": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+ "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8="
+ },
+ "map-obj": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
+ "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0="
+ },
+ "map-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
+ "requires": {
+ "object-visit": "^1.0.0"
+ }
+ },
+ "math-expression-evaluator": {
+ "version": "1.2.17",
+ "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz",
+ "integrity": "sha1-3oGf282E3M2PrlnGrreWFbnSZqw="
+ },
+ "math-random": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz",
+ "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w="
+ },
+ "md5.js": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz",
+ "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=",
+ "requires": {
+ "hash-base": "^3.0.0",
+ "inherits": "^2.0.1"
+ }
+ },
+ "media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+ },
+ "mem": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz",
+ "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=",
+ "requires": {
+ "mimic-fn": "^1.0.0"
+ }
+ },
+ "memory-fs": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
+ "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=",
+ "requires": {
+ "errno": "^0.1.3",
+ "readable-stream": "^2.0.1"
+ }
+ },
+ "meow": {
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
+ "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
+ "requires": {
+ "camelcase-keys": "^2.0.0",
+ "decamelize": "^1.1.2",
+ "loud-rejection": "^1.0.0",
+ "map-obj": "^1.0.1",
+ "minimist": "^1.1.3",
+ "normalize-package-data": "^2.3.4",
+ "object-assign": "^4.0.1",
+ "read-pkg-up": "^1.0.1",
+ "redent": "^1.0.0",
+ "trim-newlines": "^1.0.0"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+ }
+ }
+ },
+ "merge": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz",
+ "integrity": "sha1-dTHjnUlJwoGma4xabgJl6LBYlNo="
+ },
+ "merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
+ },
+ "methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
+ },
+ "micromatch": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+ "requires": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "braces": "^2.3.1",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "extglob": "^2.0.4",
+ "fragment-cache": "^0.2.1",
+ "kind-of": "^6.0.2",
+ "nanomatch": "^1.2.9",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.2"
+ }
+ },
+ "miller-rabin": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
+ "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==",
+ "requires": {
+ "bn.js": "^4.0.0",
+ "brorand": "^1.0.1"
+ }
+ },
+ "mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
+ },
+ "mime-db": {
+ "version": "1.33.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz",
+ "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ=="
+ },
+ "mime-types": {
+ "version": "2.1.18",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz",
+ "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==",
+ "requires": {
+ "mime-db": "~1.33.0"
+ }
+ },
+ "mimic-fn": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
+ "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="
+ },
+ "minimalistic-assert": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
+ "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="
+ },
+ "minimalistic-crypto-utils": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
+ "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo="
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "minimist": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
+ },
+ "mixin-deep": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
+ "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==",
+ "requires": {
+ "for-in": "^1.0.2",
+ "is-extendable": "^1.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "requires": {
+ "is-plain-object": "^2.0.4"
+ }
+ }
+ }
+ },
+ "mkdirp": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "requires": {
+ "minimist": "0.0.8"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ },
+ "multicast-dns": {
+ "version": "6.2.3",
+ "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz",
+ "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==",
+ "requires": {
+ "dns-packet": "^1.3.1",
+ "thunky": "^1.0.2"
+ }
+ },
+ "multicast-dns-service-types": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz",
+ "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE="
+ },
+ "mute-stream": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
+ "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s="
+ },
+ "nan": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz",
+ "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==",
+ "optional": true
+ },
+ "nanomatch": {
+ "version": "1.2.9",
+ "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz",
+ "integrity": "sha512-n8R9bS8yQ6eSXaV6jHUpKzD8gLsin02w1HSFiegwrs9E098Ylhw5jdyKPaYqvHknHaSCKTPp7C8dGCQ0q9koXA==",
+ "requires": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "fragment-cache": "^0.2.1",
+ "is-odd": "^2.0.0",
+ "is-windows": "^1.0.2",
+ "kind-of": "^6.0.2",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ }
+ },
+ "natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc="
+ },
+ "negotiator": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
+ "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
+ },
+ "neo-async": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.5.1.tgz",
+ "integrity": "sha512-3KL3fvuRkZ7s4IFOMfztb7zJp3QaVWnBeGoJlgB38XnCRPj/0tLzzLG5IB8NYOHbJ8g8UGrgZv44GLDk6CxTxA=="
+ },
+ "next-tick": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
+ "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw="
+ },
+ "no-case": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz",
+ "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==",
+ "requires": {
+ "lower-case": "^1.1.1"
+ }
+ },
+ "node-fetch": {
+ "version": "1.7.3",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
+ "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
+ "requires": {
+ "encoding": "^0.1.11",
+ "is-stream": "^1.0.1"
+ }
+ },
+ "node-forge": {
+ "version": "0.7.5",
+ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz",
+ "integrity": "sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ=="
+ },
+ "node-int64": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
+ "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs="
+ },
+ "node-libs-browser": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.1.0.tgz",
+ "integrity": "sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg==",
+ "requires": {
+ "assert": "^1.1.1",
+ "browserify-zlib": "^0.2.0",
+ "buffer": "^4.3.0",
+ "console-browserify": "^1.1.0",
+ "constants-browserify": "^1.0.0",
+ "crypto-browserify": "^3.11.0",
+ "domain-browser": "^1.1.1",
+ "events": "^1.0.0",
+ "https-browserify": "^1.0.0",
+ "os-browserify": "^0.3.0",
+ "path-browserify": "0.0.0",
+ "process": "^0.11.10",
+ "punycode": "^1.2.4",
+ "querystring-es3": "^0.2.0",
+ "readable-stream": "^2.3.3",
+ "stream-browserify": "^2.0.1",
+ "stream-http": "^2.7.2",
+ "string_decoder": "^1.0.0",
+ "timers-browserify": "^2.0.4",
+ "tty-browserify": "0.0.0",
+ "url": "^0.11.0",
+ "util": "^0.10.3",
+ "vm-browserify": "0.0.4"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
+ }
+ }
+ },
+ "node-notifier": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.2.1.tgz",
+ "integrity": "sha512-MIBs+AAd6dJ2SklbbE8RUDRlIVhU8MaNLh1A9SUZDUHPiZkWLFde6UNwG41yQHZEToHgJMXqyVZ9UcS/ReOVTg==",
+ "requires": {
+ "growly": "^1.3.0",
+ "semver": "^5.4.1",
+ "shellwords": "^0.1.1",
+ "which": "^1.3.0"
+ }
+ },
+ "normalize-package-data": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
+ "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
+ "requires": {
+ "hosted-git-info": "^2.1.4",
+ "is-builtin-module": "^1.0.0",
+ "semver": "2 || 3 || 4 || 5",
+ "validate-npm-package-license": "^3.0.1"
+ }
+ },
+ "normalize-path": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+ "requires": {
+ "remove-trailing-separator": "^1.0.1"
+ }
+ },
+ "normalize-range": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+ "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI="
+ },
+ "normalize-url": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz",
+ "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=",
+ "requires": {
+ "object-assign": "^4.0.1",
+ "prepend-http": "^1.0.0",
+ "query-string": "^4.1.0",
+ "sort-keys": "^1.0.0"
+ }
+ },
+ "npm-run-path": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
+ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
+ "requires": {
+ "path-key": "^2.0.0"
+ }
+ },
+ "nth-check": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz",
+ "integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=",
+ "requires": {
+ "boolbase": "~1.0.0"
+ }
+ },
+ "num2fraction": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
+ "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4="
+ },
+ "number-is-nan": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
+ },
+ "nwmatcher": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.4.tgz",
+ "integrity": "sha512-3iuY4N5dhgMpCUrOVnuAdGrgxVqV2cJpM+XNccjR2DKOB1RUP0aA+wGXEiNziG/UKboFyGBIoKOaNlJxx8bciQ=="
+ },
+ "oauth-sign": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
+ "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM="
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+ },
+ "object-copy": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
+ "requires": {
+ "copy-descriptor": "^0.1.0",
+ "define-property": "^0.2.5",
+ "kind-of": "^3.0.3"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "object-hash": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.0.tgz",
+ "integrity": "sha512-05KzQ70lSeGSrZJQXE5wNDiTkBJDlUT/myi6RX9dVIvz7a7Qh4oH93BQdiPMn27nldYvVQCKMUaM83AfizZlsQ=="
+ },
+ "object-keys": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz",
+ "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0="
+ },
+ "object-visit": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
+ "requires": {
+ "isobject": "^3.0.0"
+ }
+ },
+ "object.omit": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
+ "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
+ "requires": {
+ "for-own": "^0.1.4",
+ "is-extendable": "^0.1.1"
+ }
+ },
+ "object.pick": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+ "requires": {
+ "isobject": "^3.0.1"
+ }
+ },
+ "obuf": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
+ "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg=="
+ },
+ "on-finished": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ },
+ "on-headers": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz",
+ "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c="
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "onetime": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
+ "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
+ "requires": {
+ "mimic-fn": "^1.0.0"
+ }
+ },
+ "opn": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/opn/-/opn-5.2.0.tgz",
+ "integrity": "sha512-Jd/GpzPyHF4P2/aNOVmS3lfMSWV9J7cOhCG1s08XCEAsPkB7lp6ddiU0J7XzyQRDUh8BqJ7PchfINjR8jyofRQ==",
+ "requires": {
+ "is-wsl": "^1.1.0"
+ }
+ },
+ "optimist": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
+ "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
+ "requires": {
+ "minimist": "~0.0.1",
+ "wordwrap": "~0.0.2"
+ },
+ "dependencies": {
+ "wordwrap": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
+ "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="
+ }
+ }
+ },
+ "optionator": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
+ "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
+ "requires": {
+ "deep-is": "~0.1.3",
+ "fast-levenshtein": "~2.0.4",
+ "levn": "~0.3.0",
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2",
+ "wordwrap": "~1.0.0"
+ }
+ },
+ "original": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/original/-/original-1.0.1.tgz",
+ "integrity": "sha512-IEvtB5vM5ULvwnqMxWBLxkS13JIEXbakizMSo3yoPNPCIWzg8TG3Usn/UhXoZFM/m+FuEA20KdzPSFq/0rS+UA==",
+ "requires": {
+ "url-parse": "~1.4.0"
+ }
+ },
+ "os-browserify": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
+ "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc="
+ },
+ "os-homedir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+ "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
+ },
+ "os-locale": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
+ "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
+ "requires": {
+ "lcid": "^1.0.0"
+ }
+ },
+ "os-tmpdir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
+ },
+ "p-finally": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
+ "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
+ },
+ "p-limit": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
+ "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
+ "requires": {
+ "p-try": "^1.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
+ "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
+ "requires": {
+ "p-limit": "^1.1.0"
+ }
+ },
+ "p-map": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz",
+ "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA=="
+ },
+ "p-try": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
+ "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M="
+ },
+ "package-json": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz",
+ "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=",
+ "requires": {
+ "got": "^6.7.1",
+ "registry-auth-token": "^3.0.1",
+ "registry-url": "^3.0.3",
+ "semver": "^5.1.0"
+ }
+ },
+ "pako": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz",
+ "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg=="
+ },
+ "param-case": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz",
+ "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=",
+ "requires": {
+ "no-case": "^2.2.0"
+ }
+ },
+ "parse-asn1": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz",
+ "integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==",
+ "requires": {
+ "asn1.js": "^4.0.0",
+ "browserify-aes": "^1.0.0",
+ "create-hash": "^1.1.0",
+ "evp_bytestokey": "^1.0.0",
+ "pbkdf2": "^3.0.3"
+ }
+ },
+ "parse-glob": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
+ "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
+ "requires": {
+ "glob-base": "^0.3.0",
+ "is-dotfile": "^1.0.0",
+ "is-extglob": "^1.0.0",
+ "is-glob": "^2.0.0"
+ }
+ },
+ "parse-json": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
+ "requires": {
+ "error-ex": "^1.2.0"
+ }
+ },
+ "parse-passwd": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
+ "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY="
+ },
+ "parse5": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz",
+ "integrity": "sha1-m387DeMr543CQBsXVzzK8Pb1nZQ="
+ },
+ "parseurl": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
+ "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M="
+ },
+ "pascalcase": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ="
+ },
+ "path-browserify": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz",
+ "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo="
+ },
+ "path-dirname": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
+ "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA="
+ },
+ "path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+ },
+ "path-is-inside": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
+ "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM="
+ },
+ "path-key": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
+ },
+ "path-parse": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz",
+ "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME="
+ },
+ "path-to-regexp": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz",
+ "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=",
+ "requires": {
+ "isarray": "0.0.1"
+ },
+ "dependencies": {
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+ }
+ }
+ },
+ "path-type": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
+ "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ }
+ },
+ "pbkdf2": {
+ "version": "3.0.16",
+ "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.16.tgz",
+ "integrity": "sha512-y4CXP3thSxqf7c0qmOF+9UeOTrifiVTIM+u7NWlq+PRsHbr7r7dpCmvzrZxa96JJUNi0Y5w9VqG5ZNeCVMoDcA==",
+ "requires": {
+ "create-hash": "^1.1.2",
+ "create-hmac": "^1.1.4",
+ "ripemd160": "^2.0.1",
+ "safe-buffer": "^5.0.1",
+ "sha.js": "^2.4.8"
+ }
+ },
+ "performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
+ },
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
+ },
+ "pinkie": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+ "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA="
+ },
+ "pinkie-promise": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+ "requires": {
+ "pinkie": "^2.0.0"
+ }
+ },
+ "pkg-dir": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz",
+ "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=",
+ "requires": {
+ "find-up": "^2.1.0"
+ }
+ },
+ "pluralize": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz",
+ "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow=="
+ },
+ "popper.js": {
+ "version": "1.14.4",
+ "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.4.tgz",
+ "integrity": "sha1-juwdj/AqWjoVLdQ0FKFce3n9abY="
+ },
+ "portfinder": {
+ "version": "1.0.13",
+ "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.13.tgz",
+ "integrity": "sha1-uzLs2HwnEErm7kS1o8y/Drsa7ek=",
+ "requires": {
+ "async": "^1.5.2",
+ "debug": "^2.2.0",
+ "mkdirp": "0.5.x"
+ },
+ "dependencies": {
+ "async": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
+ }
+ }
+ },
+ "posix-character-classes": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs="
+ },
+ "postcss": {
+ "version": "6.0.22",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.22.tgz",
+ "integrity": "sha512-Toc9lLoUASwGqxBSJGTVcOQiDqjK+Z2XlWBg+IgYwQMY9vA2f7iMpXVc1GpPcfTSyM5lkxNo0oDwDRO+wm7XHA==",
+ "requires": {
+ "chalk": "^2.4.1",
+ "source-map": "^0.6.1",
+ "supports-color": "^5.4.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
+ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
+ }
+ },
+ "postcss-calc": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-5.3.1.tgz",
+ "integrity": "sha1-d7rnypKK2FcW4v2kLyYb98HWW14=",
+ "requires": {
+ "postcss": "^5.0.2",
+ "postcss-message-helpers": "^2.0.0",
+ "reduce-css-calc": "^1.2.6"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-colormin": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-2.2.2.tgz",
+ "integrity": "sha1-ZjFBfV8OkJo9fsJrJMio0eT5bks=",
+ "requires": {
+ "colormin": "^1.0.5",
+ "postcss": "^5.0.13",
+ "postcss-value-parser": "^3.2.3"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-convert-values": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz",
+ "integrity": "sha1-u9hZPFwf0uPRwyK7kl3K6Nrk1i0=",
+ "requires": {
+ "postcss": "^5.0.11",
+ "postcss-value-parser": "^3.1.2"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-discard-comments": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz",
+ "integrity": "sha1-vv6J+v1bPazlzM5Rt2uBUUvgDj0=",
+ "requires": {
+ "postcss": "^5.0.14"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-discard-duplicates": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz",
+ "integrity": "sha1-uavye4isGIFYpesSq8riAmO5GTI=",
+ "requires": {
+ "postcss": "^5.0.4"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-discard-empty": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz",
+ "integrity": "sha1-0rS9nVztXr2Nyt52QMfXzX9PkrU=",
+ "requires": {
+ "postcss": "^5.0.14"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-discard-overridden": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz",
+ "integrity": "sha1-ix6vVU9ob7KIzYdMVWZ7CqNmjVg=",
+ "requires": {
+ "postcss": "^5.0.16"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-discard-unused": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz",
+ "integrity": "sha1-vOMLLMWR/8Y0Mitfs0ZLbZNPRDM=",
+ "requires": {
+ "postcss": "^5.0.14",
+ "uniqs": "^2.0.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-filter-plugins": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/postcss-filter-plugins/-/postcss-filter-plugins-2.0.3.tgz",
+ "integrity": "sha512-T53GVFsdinJhgwm7rg1BzbeBRomOg9y5MBVhGcsV0CxurUdVj1UlPdKtn7aqYA/c/QVkzKMjq2bSV5dKG5+AwQ==",
+ "requires": {
+ "postcss": "^5.0.4"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-flexbugs-fixes": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-3.2.0.tgz",
+ "integrity": "sha512-0AuD9HG1Ey3/3nqPWu9yqf7rL0KCPu5VgjDsjf5mzEcuo9H/z8nco/fljKgjsOUrZypa95MI0kS4xBZeBzz2lw==",
+ "requires": {
+ "postcss": "^6.0.1"
+ }
+ },
+ "postcss-load-config": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-1.2.0.tgz",
+ "integrity": "sha1-U56a/J3chiASHr+djDZz4M5Q0oo=",
+ "requires": {
+ "cosmiconfig": "^2.1.0",
+ "object-assign": "^4.1.0",
+ "postcss-load-options": "^1.2.0",
+ "postcss-load-plugins": "^2.3.0"
+ }
+ },
+ "postcss-load-options": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-load-options/-/postcss-load-options-1.2.0.tgz",
+ "integrity": "sha1-sJixVZ3awt8EvAuzdfmaXP4rbYw=",
+ "requires": {
+ "cosmiconfig": "^2.1.0",
+ "object-assign": "^4.1.0"
+ }
+ },
+ "postcss-load-plugins": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/postcss-load-plugins/-/postcss-load-plugins-2.3.0.tgz",
+ "integrity": "sha1-dFdoEWWZrKLwCfrUJrABdQSdjZI=",
+ "requires": {
+ "cosmiconfig": "^2.1.1",
+ "object-assign": "^4.1.0"
+ }
+ },
+ "postcss-loader": {
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-2.0.8.tgz",
+ "integrity": "sha512-KtXBiQ/r/WYW8LxTSJK7h8wLqvCMSub/BqmRnud/Mu8RzwflW9cmXxwsMwbn15TNv287Hcufdb3ZSs7xHKnG8Q==",
+ "requires": {
+ "loader-utils": "^1.1.0",
+ "postcss": "^6.0.0",
+ "postcss-load-config": "^1.2.0",
+ "schema-utils": "^0.3.0"
+ }
+ },
+ "postcss-merge-idents": {
+ "version": "2.1.7",
+ "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz",
+ "integrity": "sha1-TFUwMTwI4dWzu/PSu8dH4njuonA=",
+ "requires": {
+ "has": "^1.0.1",
+ "postcss": "^5.0.10",
+ "postcss-value-parser": "^3.1.1"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-merge-longhand": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz",
+ "integrity": "sha1-I9kM0Sewp3mUkVMyc5A0oaTz1lg=",
+ "requires": {
+ "postcss": "^5.0.4"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-merge-rules": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz",
+ "integrity": "sha1-0d9d+qexrMO+VT8OnhDofGG19yE=",
+ "requires": {
+ "browserslist": "^1.5.2",
+ "caniuse-api": "^1.5.2",
+ "postcss": "^5.0.4",
+ "postcss-selector-parser": "^2.2.2",
+ "vendors": "^1.0.0"
+ },
+ "dependencies": {
+ "browserslist": {
+ "version": "1.7.7",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz",
+ "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=",
+ "requires": {
+ "caniuse-db": "^1.0.30000639",
+ "electron-to-chromium": "^1.2.7"
+ }
+ },
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-message-helpers": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz",
+ "integrity": "sha1-pPL0+rbk/gAvCu0ABHjN9S+bpg4="
+ },
+ "postcss-minify-font-values": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz",
+ "integrity": "sha1-S1jttWZB66fIR0qzUmyv17vey2k=",
+ "requires": {
+ "object-assign": "^4.0.1",
+ "postcss": "^5.0.4",
+ "postcss-value-parser": "^3.0.2"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-minify-gradients": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz",
+ "integrity": "sha1-Xb2hE3NwP4PPtKPqOIHY11/15uE=",
+ "requires": {
+ "postcss": "^5.0.12",
+ "postcss-value-parser": "^3.3.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-minify-params": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz",
+ "integrity": "sha1-rSzgcTc7lDs9kwo/pZo1jCjW8fM=",
+ "requires": {
+ "alphanum-sort": "^1.0.1",
+ "postcss": "^5.0.2",
+ "postcss-value-parser": "^3.0.2",
+ "uniqs": "^2.0.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-minify-selectors": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz",
+ "integrity": "sha1-ssapjAByz5G5MtGkllCBFDEXNb8=",
+ "requires": {
+ "alphanum-sort": "^1.0.2",
+ "has": "^1.0.1",
+ "postcss": "^5.0.14",
+ "postcss-selector-parser": "^2.0.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-modules-extract-imports": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.1.0.tgz",
+ "integrity": "sha1-thTJcgvmgW6u41+zpfqh26agXds=",
+ "requires": {
+ "postcss": "^6.0.1"
+ }
+ },
+ "postcss-modules-local-by-default": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz",
+ "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=",
+ "requires": {
+ "css-selector-tokenizer": "^0.7.0",
+ "postcss": "^6.0.1"
+ }
+ },
+ "postcss-modules-scope": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz",
+ "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=",
+ "requires": {
+ "css-selector-tokenizer": "^0.7.0",
+ "postcss": "^6.0.1"
+ }
+ },
+ "postcss-modules-values": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz",
+ "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=",
+ "requires": {
+ "icss-replace-symbols": "^1.1.0",
+ "postcss": "^6.0.1"
+ }
+ },
+ "postcss-normalize-charset": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz",
+ "integrity": "sha1-757nEhLX/nWceO0WL2HtYrXLk/E=",
+ "requires": {
+ "postcss": "^5.0.5"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-normalize-url": {
+ "version": "3.0.8",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz",
+ "integrity": "sha1-EI90s/L82viRov+j6kWSJ5/HgiI=",
+ "requires": {
+ "is-absolute-url": "^2.0.0",
+ "normalize-url": "^1.4.0",
+ "postcss": "^5.0.14",
+ "postcss-value-parser": "^3.2.3"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-ordered-values": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz",
+ "integrity": "sha1-7sbCpntsQSqNsgQud/6NpD+VwR0=",
+ "requires": {
+ "postcss": "^5.0.4",
+ "postcss-value-parser": "^3.0.1"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-reduce-idents": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz",
+ "integrity": "sha1-wsbSDMlYKE9qv75j92Cb9AkFmtM=",
+ "requires": {
+ "postcss": "^5.0.4",
+ "postcss-value-parser": "^3.0.2"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-reduce-initial": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz",
+ "integrity": "sha1-aPgGlfBF0IJjqHmtJA343WT2ROo=",
+ "requires": {
+ "postcss": "^5.0.4"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-reduce-transforms": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz",
+ "integrity": "sha1-/3b02CEkN7McKYpC0uFEQCV3GuE=",
+ "requires": {
+ "has": "^1.0.1",
+ "postcss": "^5.0.8",
+ "postcss-value-parser": "^3.0.1"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-selector-parser": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz",
+ "integrity": "sha1-+UN3iGBsPJrO4W/+jYsWKX8nu5A=",
+ "requires": {
+ "flatten": "^1.0.2",
+ "indexes-of": "^1.0.1",
+ "uniq": "^1.0.1"
+ }
+ },
+ "postcss-svgo": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-2.1.6.tgz",
+ "integrity": "sha1-tt8YqmE7Zm4TPwittSGcJoSsEI0=",
+ "requires": {
+ "is-svg": "^2.0.0",
+ "postcss": "^5.0.14",
+ "postcss-value-parser": "^3.2.3",
+ "svgo": "^0.7.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-unique-selectors": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz",
+ "integrity": "sha1-mB1X0p3csz57Hf4f1DuGSfkzyh0=",
+ "requires": {
+ "alphanum-sort": "^1.0.1",
+ "postcss": "^5.0.4",
+ "uniqs": "^2.0.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "postcss-value-parser": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz",
+ "integrity": "sha1-h/OPnxj3dKSrTIojL1xc6IcqnRU="
+ },
+ "postcss-zindex": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-2.2.0.tgz",
+ "integrity": "sha1-0hCd3AVbka9n/EyzsCWUZjnSryI=",
+ "requires": {
+ "has": "^1.0.1",
+ "postcss": "^5.0.4",
+ "uniqs": "^2.0.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ },
+ "postcss": {
+ "version": "5.2.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
+ "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
+ "requires": {
+ "chalk": "^1.1.3",
+ "js-base64": "^2.1.9",
+ "source-map": "^0.5.6",
+ "supports-color": "^3.2.3"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "requires": {
+ "has-flag": "^1.0.0"
+ }
+ }
+ }
+ },
+ "prelude-ls": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
+ },
+ "prepend-http": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
+ "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw="
+ },
+ "preserve": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
+ "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks="
+ },
+ "pretty-bytes": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-4.0.2.tgz",
+ "integrity": "sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk="
+ },
+ "pretty-error": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz",
+ "integrity": "sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM=",
+ "requires": {
+ "renderkid": "^2.0.1",
+ "utila": "~0.4"
+ }
+ },
+ "pretty-format": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-20.0.3.tgz",
+ "integrity": "sha1-Ag41ClYKH+GpjcO+tsz/s4beixQ=",
+ "requires": {
+ "ansi-regex": "^2.1.1",
+ "ansi-styles": "^3.0.0"
+ }
+ },
+ "private": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
+ "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg=="
+ },
+ "process": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI="
+ },
+ "process-nextick-args": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+ "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
+ },
+ "progress": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz",
+ "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8="
+ },
+ "promise": {
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
+ "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
+ "requires": {
+ "asap": "~2.0.3"
+ }
+ },
+ "prop-types": {
+ "version": "15.6.2",
+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz",
+ "integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==",
+ "requires": {
+ "loose-envify": "^1.3.1",
+ "object-assign": "^4.1.1"
+ }
+ },
+ "proxy-addr": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.3.tgz",
+ "integrity": "sha512-jQTChiCJteusULxjBp8+jftSQE5Obdl3k4cnmLA6WXtK6XFuWRnvVL7aCiBqaLPM8c4ph0S4tKna8XvmIwEnXQ==",
+ "requires": {
+ "forwarded": "~0.1.2",
+ "ipaddr.js": "1.6.0"
+ }
+ },
+ "prr": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
+ "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY="
+ },
+ "pseudomap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
+ },
+ "psl": {
+ "version": "1.1.28",
+ "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.28.tgz",
+ "integrity": "sha512-+AqO1Ae+N/4r7Rvchrdm432afjT9hqJRyBN3DQv9At0tPz4hIFSGKbq64fN9dVoCow4oggIIax5/iONx0r9hZw=="
+ },
+ "public-encrypt": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.2.tgz",
+ "integrity": "sha512-4kJ5Esocg8X3h8YgJsKAuoesBgB7mqH3eowiDzMUPKiRDDE7E/BqqZD1hnTByIaAFiwAw246YEltSq7tdrOH0Q==",
+ "requires": {
+ "bn.js": "^4.1.0",
+ "browserify-rsa": "^4.0.0",
+ "create-hash": "^1.1.0",
+ "parse-asn1": "^5.0.0",
+ "randombytes": "^2.0.1"
+ }
+ },
+ "q": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
+ "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc="
+ },
+ "qs": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
+ },
+ "query-string": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
+ "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
+ "requires": {
+ "object-assign": "^4.1.0",
+ "strict-uri-encode": "^1.0.0"
+ }
+ },
+ "querystring": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
+ "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA="
+ },
+ "querystring-es3": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
+ "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM="
+ },
+ "querystringify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.0.0.tgz",
+ "integrity": "sha512-eTPo5t/4bgaMNZxyjWx6N2a6AuE0mq51KWvpc7nU/MAqixcI6v6KrGUKES0HaomdnolQBBXU/++X6/QQ9KL4tw=="
+ },
+ "raf": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.0.tgz",
+ "integrity": "sha512-pDP/NMRAXoTfrhCfyfSEwJAKLaxBU9eApMeBPB1TkDouZmvPerIClV8lTAd+uF8ZiTaVl69e1FCxQrAd/VTjGw==",
+ "requires": {
+ "performance-now": "^2.1.0"
+ }
+ },
+ "randomatic": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.0.0.tgz",
+ "integrity": "sha512-VdxFOIEY3mNO5PtSRkkle/hPJDHvQhK21oa73K4yAc9qmp6N429gAyF1gZMOTMeS0/AYzaV/2Trcef+NaIonSA==",
+ "requires": {
+ "is-number": "^4.0.0",
+ "kind-of": "^6.0.0",
+ "math-random": "^1.0.1"
+ },
+ "dependencies": {
+ "is-number": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
+ "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ=="
+ }
+ }
+ },
+ "randombytes": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz",
+ "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==",
+ "requires": {
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "randomfill": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",
+ "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==",
+ "requires": {
+ "randombytes": "^2.0.5",
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "range-parser": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
+ "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4="
+ },
+ "raw-body": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz",
+ "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=",
+ "requires": {
+ "bytes": "3.0.0",
+ "http-errors": "1.6.2",
+ "iconv-lite": "0.4.19",
+ "unpipe": "1.0.0"
+ },
+ "dependencies": {
+ "depd": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
+ "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k="
+ },
+ "http-errors": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz",
+ "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=",
+ "requires": {
+ "depd": "1.1.1",
+ "inherits": "2.0.3",
+ "setprototypeof": "1.0.3",
+ "statuses": ">= 1.3.1 < 2"
+ }
+ },
+ "iconv-lite": {
+ "version": "0.4.19",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
+ "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ=="
+ },
+ "setprototypeof": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz",
+ "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ="
+ }
+ }
+ },
+ "rc": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+ "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+ "requires": {
+ "deep-extend": "^0.6.0",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+ }
+ }
+ },
+ "react": {
+ "version": "16.4.2",
+ "resolved": "https://registry.npmjs.org/react/-/react-16.4.2.tgz",
+ "integrity": "sha512-dMv7YrbxO4y2aqnvA7f/ik9ibeLSHQJTI6TrYAenPSaQ6OXfb+Oti+oJiy8WBxgRzlKatYqtCjphTgDSCEiWFg==",
+ "requires": {
+ "fbjs": "^0.8.16",
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1",
+ "prop-types": "^15.6.0"
+ }
+ },
+ "react-dev-utils": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-5.0.1.tgz",
+ "integrity": "sha512-+y92rG6pmXt3cpcg/NGmG4w/W309tWNSmyyPL8hCMxuCSg2UP/hUg3npACj2UZc8UKVSXexyLrCnxowizGoAsw==",
+ "requires": {
+ "address": "1.0.3",
+ "babel-code-frame": "6.26.0",
+ "chalk": "1.1.3",
+ "cross-spawn": "5.1.0",
+ "detect-port-alt": "1.1.6",
+ "escape-string-regexp": "1.0.5",
+ "filesize": "3.5.11",
+ "global-modules": "1.0.0",
+ "gzip-size": "3.0.0",
+ "inquirer": "3.3.0",
+ "is-root": "1.0.0",
+ "opn": "5.2.0",
+ "react-error-overlay": "^4.0.0",
+ "recursive-readdir": "2.2.1",
+ "shell-quote": "1.6.1",
+ "sockjs-client": "1.1.4",
+ "strip-ansi": "3.0.1",
+ "text-table": "0.2.0"
+ }
+ },
+ "react-dom": {
+ "version": "16.4.2",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.4.2.tgz",
+ "integrity": "sha512-Usl73nQqzvmJN+89r97zmeUpQDKDlh58eX6Hbs/ERdDHzeBzWy+ENk7fsGQ+5KxArV1iOFPT46/VneklK9zoWw==",
+ "requires": {
+ "fbjs": "^0.8.16",
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1",
+ "prop-types": "^15.6.0"
+ }
+ },
+ "react-error-overlay": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-4.0.0.tgz",
+ "integrity": "sha512-FlsPxavEyMuR6TjVbSSywovXSEyOg6ZDj5+Z8nbsRl9EkOzAhEIcS+GLoQDC5fz/t9suhUXWmUrOBrgeUvrMxw=="
+ },
+ "react-inlinesvg": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/react-inlinesvg/-/react-inlinesvg-0.8.1.tgz",
+ "integrity": "sha512-rdeqawsT17tKvY3B9rfHsNUpZ9RpDP7URNLCrv4NifWcIoPcBxAc7Vel1pK7hyAYKgv6DDMaf8x9PB3jyWjW4A==",
+ "requires": {
+ "httpplease": "^0.16.4",
+ "once": "^1.4.0"
+ }
+ },
+ "react-scripts": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-1.1.4.tgz",
+ "integrity": "sha512-UVZIujEIT9BGbx+NGvyfS92eOrNIIpqqFi1FP7a0O9l94A/XV7bhPk70SfDKaXZouCX81tFdXo0948DjhCEgGw==",
+ "requires": {
+ "autoprefixer": "7.1.6",
+ "babel-core": "6.26.0",
+ "babel-eslint": "7.2.3",
+ "babel-jest": "20.0.3",
+ "babel-loader": "7.1.2",
+ "babel-preset-react-app": "^3.1.1",
+ "babel-runtime": "6.26.0",
+ "case-sensitive-paths-webpack-plugin": "2.1.1",
+ "chalk": "1.1.3",
+ "css-loader": "0.28.7",
+ "dotenv": "4.0.0",
+ "dotenv-expand": "4.2.0",
+ "eslint": "4.10.0",
+ "eslint-config-react-app": "^2.1.0",
+ "eslint-loader": "1.9.0",
+ "eslint-plugin-flowtype": "2.39.1",
+ "eslint-plugin-import": "2.8.0",
+ "eslint-plugin-jsx-a11y": "5.1.1",
+ "eslint-plugin-react": "7.4.0",
+ "extract-text-webpack-plugin": "3.0.2",
+ "file-loader": "1.1.5",
+ "fs-extra": "3.0.1",
+ "fsevents": "^1.1.3",
+ "html-webpack-plugin": "2.29.0",
+ "jest": "20.0.4",
+ "object-assign": "4.1.1",
+ "postcss-flexbugs-fixes": "3.2.0",
+ "postcss-loader": "2.0.8",
+ "promise": "8.0.1",
+ "raf": "3.4.0",
+ "react-dev-utils": "^5.0.1",
+ "resolve": "1.6.0",
+ "style-loader": "0.19.0",
+ "sw-precache-webpack-plugin": "0.11.4",
+ "url-loader": "0.6.2",
+ "webpack": "3.8.1",
+ "webpack-dev-server": "2.9.4",
+ "webpack-manifest-plugin": "1.3.2",
+ "whatwg-fetch": "2.0.3"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
+ },
+ "debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "eslint": {
+ "version": "4.10.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.10.0.tgz",
+ "integrity": "sha512-MMVl8P/dYUFZEvolL8PYt7qc5LNdS2lwheq9BYa5Y07FblhcZqFyaUqlS8TW5QITGex21tV4Lk0a3fK8lsJIkA==",
+ "requires": {
+ "ajv": "^5.2.0",
+ "babel-code-frame": "^6.22.0",
+ "chalk": "^2.1.0",
+ "concat-stream": "^1.6.0",
+ "cross-spawn": "^5.1.0",
+ "debug": "^3.0.1",
+ "doctrine": "^2.0.0",
+ "eslint-scope": "^3.7.1",
+ "espree": "^3.5.1",
+ "esquery": "^1.0.0",
+ "estraverse": "^4.2.0",
+ "esutils": "^2.0.2",
+ "file-entry-cache": "^2.0.0",
+ "functional-red-black-tree": "^1.0.1",
+ "glob": "^7.1.2",
+ "globals": "^9.17.0",
+ "ignore": "^3.3.3",
+ "imurmurhash": "^0.1.4",
+ "inquirer": "^3.0.6",
+ "is-resolvable": "^1.0.0",
+ "js-yaml": "^3.9.1",
+ "json-stable-stringify": "^1.0.1",
+ "levn": "^0.3.0",
+ "lodash": "^4.17.4",
+ "minimatch": "^3.0.2",
+ "mkdirp": "^0.5.1",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.8.2",
+ "path-is-inside": "^1.0.2",
+ "pluralize": "^7.0.0",
+ "progress": "^2.0.0",
+ "require-uncached": "^1.0.3",
+ "semver": "^5.3.0",
+ "strip-ansi": "^4.0.0",
+ "strip-json-comments": "~2.0.1",
+ "table": "^4.0.1",
+ "text-table": "~0.2.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
+ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
+ }
+ },
+ "eslint-plugin-react": {
+ "version": "7.4.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.4.0.tgz",
+ "integrity": "sha512-tvjU9u3VqmW2vVuYnE8Qptq+6ji4JltjOjJ9u7VAOxVYkUkyBZWRvNYKbDv5fN+L6wiA+4we9+qQahZ0m63XEA==",
+ "requires": {
+ "doctrine": "^2.0.0",
+ "has": "^1.0.1",
+ "jsx-ast-utils": "^2.0.0",
+ "prop-types": "^15.5.10"
+ }
+ },
+ "esprima": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz",
+ "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw=="
+ },
+ "js-yaml": {
+ "version": "3.12.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
+ "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==",
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ }
+ },
+ "jsx-ast-utils": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz",
+ "integrity": "sha1-6AGxs5mF4g//yHtA43SAgOLcrH8=",
+ "requires": {
+ "array-includes": "^3.0.3"
+ }
+ },
+ "promise": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/promise/-/promise-8.0.1.tgz",
+ "integrity": "sha1-5F1osAoXZHttpxG/he1u1HII9FA=",
+ "requires": {
+ "asap": "~2.0.3"
+ }
+ },
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "requires": {
+ "ansi-regex": "^3.0.0"
+ }
+ },
+ "whatwg-fetch": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz",
+ "integrity": "sha1-nITsLc9oGH/wC8ZOEnS0QhduHIQ="
+ }
+ }
+ },
+ "react-scrollchor": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/react-scrollchor/-/react-scrollchor-6.0.0.tgz",
+ "integrity": "sha512-Ryc3SoxG/urLrqQ4rFIsj1nWfW9pPGZK30CSlJ670zJWpPFQtVfYOmiZmQUwY96P8L+LcCVmV4q1ZdBlZsuW/Q==",
+ "requires": {
+ "requestanimationframe-timer": "1.x.x"
+ }
+ },
+ "react-shortcut": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/react-shortcut/-/react-shortcut-1.0.6.tgz",
+ "integrity": "sha1-k9l4AlYSMaBP2bgS//p57wJYo98=",
+ "requires": {
+ "bluebird": "3.4.7",
+ "lodash": "^4.17.4",
+ "react": "15.4.2",
+ "react-dom": "^15.4.2"
+ },
+ "dependencies": {
+ "bluebird": {
+ "version": "3.4.7",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz",
+ "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM="
+ },
+ "react": {
+ "version": "15.4.2",
+ "resolved": "https://registry.npmjs.org/react/-/react-15.4.2.tgz",
+ "integrity": "sha1-QfeZGyYYU5K6m66WyIiefgGDl+8=",
+ "requires": {
+ "fbjs": "^0.8.4",
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.0"
+ }
+ },
+ "react-dom": {
+ "version": "15.6.2",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-15.6.2.tgz",
+ "integrity": "sha1-Qc+t9pO3V/rycIRDodH9WgK+9zA=",
+ "requires": {
+ "fbjs": "^0.8.9",
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.0",
+ "prop-types": "^15.5.10"
+ }
+ }
+ }
+ },
+ "read-pkg": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
+ "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
+ "requires": {
+ "load-json-file": "^1.0.0",
+ "normalize-package-data": "^2.3.2",
+ "path-type": "^1.0.0"
+ }
+ },
+ "read-pkg-up": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
+ "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
+ "requires": {
+ "find-up": "^1.0.0",
+ "read-pkg": "^1.0.0"
+ },
+ "dependencies": {
+ "find-up": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
+ "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
+ "requires": {
+ "path-exists": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ }
+ },
+ "path-exists": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
+ "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
+ "requires": {
+ "pinkie-promise": "^2.0.0"
+ }
+ }
+ }
+ },
+ "readable-stream": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "readdirp": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz",
+ "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=",
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "minimatch": "^3.0.2",
+ "readable-stream": "^2.0.2",
+ "set-immediate-shim": "^1.0.1"
+ }
+ },
+ "recursive-readdir": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.1.tgz",
+ "integrity": "sha1-kO8jHQd4xc4JPJpI105cVCLROpk=",
+ "requires": {
+ "minimatch": "3.0.3"
+ },
+ "dependencies": {
+ "minimatch": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz",
+ "integrity": "sha1-Kk5AkLlrLbBqnX3wEFWmKnfJt3Q=",
+ "requires": {
+ "brace-expansion": "^1.0.0"
+ }
+ }
+ }
+ },
+ "redent": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
+ "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=",
+ "requires": {
+ "indent-string": "^2.1.0",
+ "strip-indent": "^1.0.1"
+ }
+ },
+ "reduce-css-calc": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz",
+ "integrity": "sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=",
+ "requires": {
+ "balanced-match": "^0.4.2",
+ "math-expression-evaluator": "^1.2.14",
+ "reduce-function-call": "^1.0.1"
+ },
+ "dependencies": {
+ "balanced-match": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz",
+ "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg="
+ }
+ }
+ },
+ "reduce-function-call": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.2.tgz",
+ "integrity": "sha1-WiAL+S4ON3UXUv5FsKszD9S2vpk=",
+ "requires": {
+ "balanced-match": "^0.4.2"
+ },
+ "dependencies": {
+ "balanced-match": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz",
+ "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg="
+ }
+ }
+ },
+ "regenerate": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz",
+ "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg=="
+ },
+ "regenerator-runtime": {
+ "version": "0.11.1",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
+ "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
+ },
+ "regenerator-transform": {
+ "version": "0.10.1",
+ "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz",
+ "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==",
+ "requires": {
+ "babel-runtime": "^6.18.0",
+ "babel-types": "^6.19.0",
+ "private": "^0.1.6"
+ }
+ },
+ "regex-cache": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
+ "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==",
+ "requires": {
+ "is-equal-shallow": "^0.1.3"
+ }
+ },
+ "regex-not": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+ "requires": {
+ "extend-shallow": "^3.0.2",
+ "safe-regex": "^1.1.0"
+ }
+ },
+ "regexpp": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz",
+ "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==",
+ "dev": true
+ },
+ "regexpu-core": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz",
+ "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=",
+ "requires": {
+ "regenerate": "^1.2.1",
+ "regjsgen": "^0.2.0",
+ "regjsparser": "^0.1.4"
+ }
+ },
+ "registry-auth-token": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz",
+ "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==",
+ "requires": {
+ "rc": "^1.1.6",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "registry-url": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz",
+ "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=",
+ "requires": {
+ "rc": "^1.0.1"
+ }
+ },
+ "regjsgen": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz",
+ "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc="
+ },
+ "regjsparser": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz",
+ "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=",
+ "requires": {
+ "jsesc": "~0.5.0"
+ },
+ "dependencies": {
+ "jsesc": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
+ "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0="
+ }
+ }
+ },
+ "relateurl": {
+ "version": "0.2.7",
+ "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
+ "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk="
+ },
+ "remove-trailing-separator": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+ "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8="
+ },
+ "renderkid": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.1.tgz",
+ "integrity": "sha1-iYyr/Ivt5Le5ETWj/9Mj5YwNsxk=",
+ "requires": {
+ "css-select": "^1.1.0",
+ "dom-converter": "~0.1",
+ "htmlparser2": "~3.3.0",
+ "strip-ansi": "^3.0.0",
+ "utila": "~0.3"
+ },
+ "dependencies": {
+ "utila": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/utila/-/utila-0.3.3.tgz",
+ "integrity": "sha1-1+jn1+MJEHCSsF+NloiCTWM6QiY="
+ }
+ }
+ },
+ "repeat-element": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz",
+ "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo="
+ },
+ "repeat-string": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
+ },
+ "repeating": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
+ "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
+ "requires": {
+ "is-finite": "^1.0.0"
+ }
+ },
+ "request": {
+ "version": "2.87.0",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz",
+ "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==",
+ "requires": {
+ "aws-sign2": "~0.7.0",
+ "aws4": "^1.6.0",
+ "caseless": "~0.12.0",
+ "combined-stream": "~1.0.5",
+ "extend": "~3.0.1",
+ "forever-agent": "~0.6.1",
+ "form-data": "~2.3.1",
+ "har-validator": "~5.0.3",
+ "http-signature": "~1.2.0",
+ "is-typedarray": "~1.0.0",
+ "isstream": "~0.1.2",
+ "json-stringify-safe": "~5.0.1",
+ "mime-types": "~2.1.17",
+ "oauth-sign": "~0.8.2",
+ "performance-now": "^2.1.0",
+ "qs": "~6.5.1",
+ "safe-buffer": "^5.1.1",
+ "tough-cookie": "~2.3.3",
+ "tunnel-agent": "^0.6.0",
+ "uuid": "^3.1.0"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
+ },
+ "tough-cookie": {
+ "version": "2.3.4",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz",
+ "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==",
+ "requires": {
+ "punycode": "^1.4.1"
+ }
+ }
+ }
+ },
+ "requestanimationframe-timer": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/requestanimationframe-timer/-/requestanimationframe-timer-1.0.4.tgz",
+ "integrity": "sha512-5ehtMkIS7RLI/UxjgAEZg6zGLoRdSSzfwjwowpBRImAr8Rbs2pdcS/4tmJ7CAtvYjtO/H+ui96AMkyefzUqUlQ==",
+ "requires": {
+ "raf": "^3.4.0"
+ }
+ },
+ "require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
+ },
+ "require-from-string": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz",
+ "integrity": "sha1-UpyczvJzgK3+yaL5ZbZJu+5jZBg="
+ },
+ "require-main-filename": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
+ "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE="
+ },
+ "require-uncached": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz",
+ "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=",
+ "requires": {
+ "caller-path": "^0.1.0",
+ "resolve-from": "^1.0.0"
+ }
+ },
+ "requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
+ },
+ "resolve": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.6.0.tgz",
+ "integrity": "sha512-mw7JQNu5ExIkcw4LPih0owX/TZXjD/ZUF/ZQ/pDnkw3ZKhDcZZw5klmBlj6gVMwjQ3Pz5Jgu7F3d0jcDVuEWdw==",
+ "requires": {
+ "path-parse": "^1.0.5"
+ }
+ },
+ "resolve-cwd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz",
+ "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=",
+ "requires": {
+ "resolve-from": "^3.0.0"
+ },
+ "dependencies": {
+ "resolve-from": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
+ "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g="
+ }
+ }
+ },
+ "resolve-dir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz",
+ "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=",
+ "requires": {
+ "expand-tilde": "^2.0.0",
+ "global-modules": "^1.0.0"
+ }
+ },
+ "resolve-from": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz",
+ "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY="
+ },
+ "resolve-url": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo="
+ },
+ "restore-cursor": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
+ "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
+ "requires": {
+ "onetime": "^2.0.0",
+ "signal-exit": "^3.0.2"
+ }
+ },
+ "ret": {
+ "version": "0.1.15",
+ "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg=="
+ },
+ "right-align": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
+ "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=",
+ "requires": {
+ "align-text": "^0.1.1"
+ }
+ },
+ "rimraf": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
+ "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
+ "requires": {
+ "glob": "^7.0.5"
+ }
+ },
+ "ripemd160": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
+ "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
+ "requires": {
+ "hash-base": "^3.0.0",
+ "inherits": "^2.0.1"
+ }
+ },
+ "run-async": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
+ "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
+ "requires": {
+ "is-promise": "^2.1.0"
+ }
+ },
+ "rx-lite": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz",
+ "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ="
+ },
+ "rx-lite-aggregates": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz",
+ "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=",
+ "requires": {
+ "rx-lite": "*"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "safe-regex": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
+ "requires": {
+ "ret": "~0.1.10"
+ }
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "sane": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/sane/-/sane-1.6.0.tgz",
+ "integrity": "sha1-lhDEUjB6E10pwf3+JUcDQYDEZ3U=",
+ "requires": {
+ "anymatch": "^1.3.0",
+ "exec-sh": "^0.2.0",
+ "fb-watchman": "^1.8.0",
+ "minimatch": "^3.0.2",
+ "minimist": "^1.1.1",
+ "walker": "~1.0.5",
+ "watch": "~0.10.0"
+ },
+ "dependencies": {
+ "bser": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/bser/-/bser-1.0.2.tgz",
+ "integrity": "sha1-OBEWlwsqbe6lZG3RXdcnhES1YWk=",
+ "requires": {
+ "node-int64": "^0.4.0"
+ }
+ },
+ "fb-watchman": {
+ "version": "1.9.2",
+ "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-1.9.2.tgz",
+ "integrity": "sha1-okz0eCf4LTj7Waaa1wt247auc4M=",
+ "requires": {
+ "bser": "1.0.2"
+ }
+ },
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+ }
+ }
+ },
+ "sax": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
+ },
+ "schema-utils": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz",
+ "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=",
+ "requires": {
+ "ajv": "^5.0.0"
+ }
+ },
+ "select-hose": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
+ "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo="
+ },
+ "selfsigned": {
+ "version": "1.10.3",
+ "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.3.tgz",
+ "integrity": "sha512-vmZenZ+8Al3NLHkWnhBQ0x6BkML1eCP2xEi3JE+f3D9wW9fipD9NNJHYtE9XJM4TsPaHGZJIamrSI6MTg1dU2Q==",
+ "requires": {
+ "node-forge": "0.7.5"
+ }
+ },
+ "semver": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
+ "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA=="
+ },
+ "semver-diff": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz",
+ "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=",
+ "requires": {
+ "semver": "^5.0.3"
+ }
+ },
+ "send": {
+ "version": "0.16.2",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz",
+ "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==",
+ "requires": {
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "destroy": "~1.0.4",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "~1.6.2",
+ "mime": "1.4.1",
+ "ms": "2.0.0",
+ "on-finished": "~2.3.0",
+ "range-parser": "~1.2.0",
+ "statuses": "~1.4.0"
+ },
+ "dependencies": {
+ "mime": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
+ "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ=="
+ }
+ }
+ },
+ "serve-index": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
+ "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=",
+ "requires": {
+ "accepts": "~1.3.4",
+ "batch": "0.6.1",
+ "debug": "2.6.9",
+ "escape-html": "~1.0.3",
+ "http-errors": "~1.6.2",
+ "mime-types": "~2.1.17",
+ "parseurl": "~1.3.2"
+ }
+ },
+ "serve-static": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz",
+ "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==",
+ "requires": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.2",
+ "send": "0.16.2"
+ }
+ },
+ "serviceworker-cache-polyfill": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/serviceworker-cache-polyfill/-/serviceworker-cache-polyfill-4.0.0.tgz",
+ "integrity": "sha1-3hnuc77yGrPAdAo3sz22JGS6ves="
+ },
+ "set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
+ },
+ "set-immediate-shim": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
+ "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E="
+ },
+ "set-value": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
+ "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-extendable": "^0.1.1",
+ "is-plain-object": "^2.0.3",
+ "split-string": "^3.0.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "setimmediate": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+ "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
+ },
+ "setprototypeof": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
+ "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
+ },
+ "sha.js": {
+ "version": "2.4.11",
+ "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
+ "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
+ "requires": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "shebang-command": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+ "requires": {
+ "shebang-regex": "^1.0.0"
+ }
+ },
+ "shebang-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
+ },
+ "shell-quote": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz",
+ "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=",
+ "requires": {
+ "array-filter": "~0.0.0",
+ "array-map": "~0.0.0",
+ "array-reduce": "~0.0.0",
+ "jsonify": "~0.0.0"
+ }
+ },
+ "shellwords": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz",
+ "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww=="
+ },
+ "signal-exit": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
+ },
+ "slash": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
+ "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU="
+ },
+ "slice-ansi": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz",
+ "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==",
+ "requires": {
+ "is-fullwidth-code-point": "^2.0.0"
+ }
+ },
+ "snapdragon": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+ "requires": {
+ "base": "^0.11.1",
+ "debug": "^2.2.0",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "map-cache": "^0.2.2",
+ "source-map": "^0.5.6",
+ "source-map-resolve": "^0.5.0",
+ "use": "^3.1.0"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ }
+ }
+ },
+ "snapdragon-node": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+ "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+ "requires": {
+ "define-property": "^1.0.0",
+ "isobject": "^3.0.0",
+ "snapdragon-util": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "snapdragon-util": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+ "requires": {
+ "kind-of": "^3.2.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "sockjs": {
+ "version": "0.3.18",
+ "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.18.tgz",
+ "integrity": "sha1-2bKJMWyn33dZXvKZ4HXw+TfrQgc=",
+ "requires": {
+ "faye-websocket": "^0.10.0",
+ "uuid": "^2.0.2"
+ },
+ "dependencies": {
+ "faye-websocket": {
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz",
+ "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=",
+ "requires": {
+ "websocket-driver": ">=0.5.1"
+ }
+ },
+ "uuid": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz",
+ "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho="
+ }
+ }
+ },
+ "sockjs-client": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.1.4.tgz",
+ "integrity": "sha1-W6vjhrd15M8U51IJEUUmVAFsixI=",
+ "requires": {
+ "debug": "^2.6.6",
+ "eventsource": "0.1.6",
+ "faye-websocket": "~0.11.0",
+ "inherits": "^2.0.1",
+ "json3": "^3.3.2",
+ "url-parse": "^1.1.8"
+ }
+ },
+ "sort-keys": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
+ "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=",
+ "requires": {
+ "is-plain-obj": "^1.0.0"
+ }
+ },
+ "source-list-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz",
+ "integrity": "sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A=="
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ },
+ "source-map-resolve": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
+ "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==",
+ "requires": {
+ "atob": "^2.1.1",
+ "decode-uri-component": "^0.2.0",
+ "resolve-url": "^0.2.1",
+ "source-map-url": "^0.4.0",
+ "urix": "^0.1.0"
+ }
+ },
+ "source-map-support": {
+ "version": "0.4.18",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
+ "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==",
+ "requires": {
+ "source-map": "^0.5.6"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ }
+ }
+ },
+ "source-map-url": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
+ "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM="
+ },
+ "spdx-correct": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz",
+ "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==",
+ "requires": {
+ "spdx-expression-parse": "^3.0.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "spdx-exceptions": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz",
+ "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg=="
+ },
+ "spdx-expression-parse": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
+ "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
+ "requires": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "spdx-license-ids": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz",
+ "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA=="
+ },
+ "spdy": {
+ "version": "3.4.7",
+ "resolved": "https://registry.npmjs.org/spdy/-/spdy-3.4.7.tgz",
+ "integrity": "sha1-Qv9B7OXMD5mjpsKKq7c/XDsDrLw=",
+ "requires": {
+ "debug": "^2.6.8",
+ "handle-thing": "^1.2.5",
+ "http-deceiver": "^1.2.7",
+ "safe-buffer": "^5.0.1",
+ "select-hose": "^2.0.0",
+ "spdy-transport": "^2.0.18"
+ }
+ },
+ "spdy-transport": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-2.1.0.tgz",
+ "integrity": "sha512-bpUeGpZcmZ692rrTiqf9/2EUakI6/kXX1Rpe0ib/DyOzbiexVfXkw6GnvI9hVGvIwVaUhkaBojjCZwLNRGQg1g==",
+ "requires": {
+ "debug": "^2.6.8",
+ "detect-node": "^2.0.3",
+ "hpack.js": "^2.1.6",
+ "obuf": "^1.1.1",
+ "readable-stream": "^2.2.9",
+ "safe-buffer": "^5.0.1",
+ "wbuf": "^1.7.2"
+ }
+ },
+ "split-string": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+ "requires": {
+ "extend-shallow": "^3.0.0"
+ }
+ },
+ "sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
+ },
+ "sshpk": {
+ "version": "1.14.2",
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz",
+ "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=",
+ "requires": {
+ "asn1": "~0.2.3",
+ "assert-plus": "^1.0.0",
+ "bcrypt-pbkdf": "^1.0.0",
+ "dashdash": "^1.12.0",
+ "ecc-jsbn": "~0.1.1",
+ "getpass": "^0.1.1",
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.0.2",
+ "tweetnacl": "~0.14.0"
+ }
+ },
+ "static-extend": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
+ "requires": {
+ "define-property": "^0.2.5",
+ "object-copy": "^0.1.0"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ }
+ }
+ },
+ "statuses": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
+ "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew=="
+ },
+ "stream-browserify": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz",
+ "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=",
+ "requires": {
+ "inherits": "~2.0.1",
+ "readable-stream": "^2.0.2"
+ }
+ },
+ "stream-http": {
+ "version": "2.8.3",
+ "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz",
+ "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==",
+ "requires": {
+ "builtin-status-codes": "^3.0.0",
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.3.6",
+ "to-arraybuffer": "^1.0.0",
+ "xtend": "^4.0.0"
+ },
+ "dependencies": {
+ "xtend": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+ "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
+ }
+ }
+ },
+ "strict-uri-encode": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
+ "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM="
+ },
+ "string-length": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz",
+ "integrity": "sha1-VpcPscOFWOnnC3KL894mmsRa36w=",
+ "requires": {
+ "strip-ansi": "^3.0.0"
+ }
+ },
+ "string-width": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+ "requires": {
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^4.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
+ },
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "requires": {
+ "ansi-regex": "^3.0.0"
+ }
+ }
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "strip-bom": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
+ "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
+ "requires": {
+ "is-utf8": "^0.2.0"
+ }
+ },
+ "strip-eof": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
+ "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="
+ },
+ "strip-indent": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
+ "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=",
+ "requires": {
+ "get-stdin": "^4.0.1"
+ }
+ },
+ "strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
+ },
+ "style-loader": {
+ "version": "0.19.0",
+ "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.19.0.tgz",
+ "integrity": "sha512-9mx9sC9nX1dgP96MZOODpGC6l1RzQBITI2D5WJhu+wnbrSYVKLGuy14XJSLVQih/0GFrPpjelt+s//VcZQ2Evw==",
+ "requires": {
+ "loader-utils": "^1.0.2",
+ "schema-utils": "^0.3.0"
+ }
+ },
+ "supports-color": {
+ "version": "5.4.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
+ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ },
+ "svgo": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.2.tgz",
+ "integrity": "sha1-n1dyQTlSE1xv779Ar+ak+qiLS7U=",
+ "requires": {
+ "coa": "~1.0.1",
+ "colors": "~1.1.2",
+ "csso": "~2.3.1",
+ "js-yaml": "~3.7.0",
+ "mkdirp": "~0.5.1",
+ "sax": "~1.2.1",
+ "whet.extend": "~0.9.9"
+ }
+ },
+ "sw-precache": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/sw-precache/-/sw-precache-5.2.1.tgz",
+ "integrity": "sha512-8FAy+BP/FXE+ILfiVTt+GQJ6UEf4CVHD9OfhzH0JX+3zoy2uFk7Vn9EfXASOtVmmIVbL3jE/W8Z66VgPSZcMhw==",
+ "requires": {
+ "dom-urls": "^1.1.0",
+ "es6-promise": "^4.0.5",
+ "glob": "^7.1.1",
+ "lodash.defaults": "^4.2.0",
+ "lodash.template": "^4.4.0",
+ "meow": "^3.7.0",
+ "mkdirp": "^0.5.1",
+ "pretty-bytes": "^4.0.2",
+ "sw-toolbox": "^3.4.0",
+ "update-notifier": "^2.3.0"
+ }
+ },
+ "sw-precache-webpack-plugin": {
+ "version": "0.11.4",
+ "resolved": "https://registry.npmjs.org/sw-precache-webpack-plugin/-/sw-precache-webpack-plugin-0.11.4.tgz",
+ "integrity": "sha1-ppUBflTu1XVVFJOlGdwdqNotxeA=",
+ "requires": {
+ "del": "^2.2.2",
+ "sw-precache": "^5.1.1",
+ "uglify-js": "^3.0.13"
+ }
+ },
+ "sw-toolbox": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/sw-toolbox/-/sw-toolbox-3.6.0.tgz",
+ "integrity": "sha1-Jt8dHHA0hljk3qKIQxkUm3sxg7U=",
+ "requires": {
+ "path-to-regexp": "^1.0.1",
+ "serviceworker-cache-polyfill": "^4.0.0"
+ }
+ },
+ "symbol-tree": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz",
+ "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY="
+ },
+ "table": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz",
+ "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==",
+ "requires": {
+ "ajv": "^5.2.3",
+ "ajv-keywords": "^2.1.0",
+ "chalk": "^2.1.0",
+ "lodash": "^4.17.4",
+ "slice-ansi": "1.0.0",
+ "string-width": "^2.1.1"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
+ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
+ }
+ },
+ "tapable": {
+ "version": "0.2.8",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.8.tgz",
+ "integrity": "sha1-mTcqXJmb8t8WCvwNdL7U9HlIzSI="
+ },
+ "term-size": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz",
+ "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=",
+ "requires": {
+ "execa": "^0.7.0"
+ }
+ },
+ "test-exclude": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.2.1.tgz",
+ "integrity": "sha512-qpqlP/8Zl+sosLxBcVKl9vYy26T9NPalxSzzCP/OY6K7j938ui2oKgo+kRZYfxAeIpLqpbVnsHq1tyV70E4lWQ==",
+ "requires": {
+ "arrify": "^1.0.1",
+ "micromatch": "^3.1.8",
+ "object-assign": "^4.1.0",
+ "read-pkg-up": "^1.0.1",
+ "require-main-filename": "^1.0.1"
+ }
+ },
+ "text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ="
+ },
+ "throat": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/throat/-/throat-3.2.0.tgz",
+ "integrity": "sha512-/EY8VpvlqJ+sFtLPeOgc8Pl7kQVOWv0woD87KTXVHPIAE842FGT+rokxIhe8xIUP1cfgrkt0as0vDLjDiMtr8w=="
+ },
+ "through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
+ },
+ "thunky": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.2.tgz",
+ "integrity": "sha1-qGLgGOP7HqLsP85dVWBc9X8kc3E="
+ },
+ "time-stamp": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-2.0.0.tgz",
+ "integrity": "sha1-lcakRTDhW6jW9KPsuMOj+sRto1c="
+ },
+ "timed-out": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz",
+ "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8="
+ },
+ "timers-browserify": {
+ "version": "2.0.10",
+ "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz",
+ "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==",
+ "requires": {
+ "setimmediate": "^1.0.4"
+ }
+ },
+ "tmp": {
+ "version": "0.0.33",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+ "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+ "requires": {
+ "os-tmpdir": "~1.0.2"
+ }
+ },
+ "tmpl": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz",
+ "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE="
+ },
+ "to-arraybuffer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
+ "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M="
+ },
+ "to-fast-properties": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
+ "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc="
+ },
+ "to-object-path": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "to-regex": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+ "requires": {
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "regex-not": "^1.0.2",
+ "safe-regex": "^1.1.0"
+ }
+ },
+ "to-regex-range": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
+ "requires": {
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1"
+ }
+ },
+ "toposort": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.7.tgz",
+ "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk="
+ },
+ "tough-cookie": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.2.tgz",
+ "integrity": "sha512-vahm+X8lSV/KjXziec8x5Vp0OTC9mq8EVCOApIsRAooeuMPSO8aT7PFACYkaL0yZ/3hVqw+8DzhCJwl8H2Ad6w==",
+ "requires": {
+ "psl": "^1.1.24",
+ "punycode": "^1.4.1"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
+ }
+ }
+ },
+ "tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
+ },
+ "trim-newlines": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
+ "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM="
+ },
+ "trim-right": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
+ "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM="
+ },
+ "tty-browserify": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
+ "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY="
+ },
+ "tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+ "requires": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "tweetnacl": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
+ "optional": true
+ },
+ "type-check": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+ "requires": {
+ "prelude-ls": "~1.1.2"
+ }
+ },
+ "type-is": {
+ "version": "1.6.16",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz",
+ "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==",
+ "requires": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.18"
+ }
+ },
+ "typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
+ },
+ "ua-parser-js": {
+ "version": "0.7.18",
+ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.18.tgz",
+ "integrity": "sha512-LtzwHlVHwFGTptfNSgezHp7WUlwiqb0gA9AALRbKaERfxwJoiX0A73QbTToxteIAuIaFshhgIZfqK8s7clqgnA=="
+ },
+ "uglify-js": {
+ "version": "3.3.28",
+ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.28.tgz",
+ "integrity": "sha512-68Rc/aA6cswiaQ5SrE979UJcXX+ADA1z33/ZsPd+fbAiVdjZ16OXdbtGO+rJUUBgK6qdf3SOPhQf3K/ybF5Miw==",
+ "requires": {
+ "commander": "~2.15.0",
+ "source-map": "~0.6.1"
+ }
+ },
+ "uglify-to-browserify": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
+ "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=",
+ "optional": true
+ },
+ "uglifyjs-webpack-plugin": {
+ "version": "0.4.6",
+ "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz",
+ "integrity": "sha1-uVH0q7a9YX5m9j64kUmOORdj4wk=",
+ "requires": {
+ "source-map": "^0.5.6",
+ "uglify-js": "^2.8.29",
+ "webpack-sources": "^1.0.1"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "uglify-js": {
+ "version": "2.8.29",
+ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
+ "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=",
+ "requires": {
+ "source-map": "~0.5.1",
+ "uglify-to-browserify": "~1.0.0",
+ "yargs": "~3.10.0"
+ }
+ },
+ "yargs": {
+ "version": "3.10.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
+ "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
+ "requires": {
+ "camelcase": "^1.0.2",
+ "cliui": "^2.1.0",
+ "decamelize": "^1.0.0",
+ "window-size": "0.1.0"
+ }
+ }
+ }
+ },
+ "union-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
+ "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
+ "requires": {
+ "arr-union": "^3.1.0",
+ "get-value": "^2.0.6",
+ "is-extendable": "^0.1.1",
+ "set-value": "^0.4.3"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "set-value": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
+ "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-extendable": "^0.1.1",
+ "is-plain-object": "^2.0.1",
+ "to-object-path": "^0.3.0"
+ }
+ }
+ }
+ },
+ "uniq": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
+ "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8="
+ },
+ "uniqs": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz",
+ "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI="
+ },
+ "unique-string": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz",
+ "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=",
+ "requires": {
+ "crypto-random-string": "^1.0.0"
+ }
+ },
+ "universalify": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz",
+ "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc="
+ },
+ "unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
+ },
+ "unset-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
+ "requires": {
+ "has-value": "^0.3.1",
+ "isobject": "^3.0.0"
+ },
+ "dependencies": {
+ "has-value": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
+ "requires": {
+ "get-value": "^2.0.3",
+ "has-values": "^0.1.4",
+ "isobject": "^2.0.0"
+ },
+ "dependencies": {
+ "isobject": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+ "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+ "requires": {
+ "isarray": "1.0.0"
+ }
+ }
+ }
+ },
+ "has-values": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+ "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E="
+ }
+ }
+ },
+ "unzip-response": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz",
+ "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c="
+ },
+ "upath": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz",
+ "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw=="
+ },
+ "update-notifier": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz",
+ "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==",
+ "requires": {
+ "boxen": "^1.2.1",
+ "chalk": "^2.0.1",
+ "configstore": "^3.0.0",
+ "import-lazy": "^2.1.0",
+ "is-ci": "^1.0.10",
+ "is-installed-globally": "^0.1.0",
+ "is-npm": "^1.0.0",
+ "latest-version": "^3.0.0",
+ "semver-diff": "^2.0.0",
+ "xdg-basedir": "^3.0.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
+ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ }
+ }
+ },
+ "upper-case": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz",
+ "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg="
+ },
+ "urijs": {
+ "version": "1.19.1",
+ "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.1.tgz",
+ "integrity": "sha512-xVrGVi94ueCJNrBSTjWqjvtgvl3cyOTThp2zaMaFNGp3F542TR6sM3f2o8RqZl+AwteClSVmoCyt0ka4RjQOQg=="
+ },
+ "urix": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI="
+ },
+ "url": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
+ "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
+ "requires": {
+ "punycode": "1.3.2",
+ "querystring": "0.2.0"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
+ "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0="
+ }
+ }
+ },
+ "url-loader": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-0.6.2.tgz",
+ "integrity": "sha512-h3qf9TNn53BpuXTTcpC+UehiRrl0Cv45Yr/xWayApjw6G8Bg2dGke7rIwDQ39piciWCWrC+WiqLjOh3SUp9n0Q==",
+ "requires": {
+ "loader-utils": "^1.0.2",
+ "mime": "^1.4.1",
+ "schema-utils": "^0.3.0"
+ }
+ },
+ "url-parse": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.3.tgz",
+ "integrity": "sha512-rh+KuAW36YKo0vClhQzLLveoj8FwPJNu65xLb7Mrt+eZht0IPT0IXgSv8gcMegZ6NvjJUALf6Mf25POlMwD1Fw==",
+ "requires": {
+ "querystringify": "^2.0.0",
+ "requires-port": "^1.0.0"
+ }
+ },
+ "url-parse-lax": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz",
+ "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=",
+ "requires": {
+ "prepend-http": "^1.0.1"
+ }
+ },
+ "urllite": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/urllite/-/urllite-0.5.0.tgz",
+ "integrity": "sha1-G3u5yj+w25Ug3hE0ZrvPfMNBRRo=",
+ "requires": {
+ "xtend": "~4.0.0"
+ },
+ "dependencies": {
+ "xtend": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+ "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
+ }
+ }
+ },
+ "use": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/use/-/use-3.1.0.tgz",
+ "integrity": "sha512-6UJEQM/L+mzC3ZJNM56Q4DFGLX/evKGRg15UJHGB9X5j5Z3AFbgZvjUh2yq/UJUY4U5dh7Fal++XbNg1uzpRAw==",
+ "requires": {
+ "kind-of": "^6.0.2"
+ }
+ },
+ "util": {
+ "version": "0.10.4",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz",
+ "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==",
+ "requires": {
+ "inherits": "2.0.3"
+ }
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+ },
+ "utila": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz",
+ "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw="
+ },
+ "utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
+ },
+ "uuid": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz",
+ "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA=="
+ },
+ "validate-npm-package-license": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz",
+ "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==",
+ "requires": {
+ "spdx-correct": "^3.0.0",
+ "spdx-expression-parse": "^3.0.0"
+ }
+ },
+ "vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
+ },
+ "vendors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.2.tgz",
+ "integrity": "sha512-w/hry/368nO21AN9QljsaIhb9ZiZtZARoVH5f3CsFbawdLdayCgKRPup7CggujvySMxx0I91NOyxdVENohprLQ=="
+ },
+ "verror": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+ "requires": {
+ "assert-plus": "^1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "^1.2.0"
+ }
+ },
+ "vm-browserify": {
+ "version": "0.0.4",
+ "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz",
+ "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=",
+ "requires": {
+ "indexof": "0.0.1"
+ }
+ },
+ "walker": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz",
+ "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=",
+ "requires": {
+ "makeerror": "1.0.x"
+ }
+ },
+ "watch": {
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz",
+ "integrity": "sha1-d3mLLaD5kQ1ZXxrOWwwiWFIfIdw="
+ },
+ "watchpack": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz",
+ "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==",
+ "requires": {
+ "chokidar": "^2.0.2",
+ "graceful-fs": "^4.1.2",
+ "neo-async": "^2.5.0"
+ }
+ },
+ "wbuf": {
+ "version": "1.7.3",
+ "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz",
+ "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==",
+ "requires": {
+ "minimalistic-assert": "^1.0.0"
+ }
+ },
+ "webidl-conversions": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
+ "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg=="
+ },
+ "webpack": {
+ "version": "3.8.1",
+ "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.8.1.tgz",
+ "integrity": "sha512-5ZXLWWsMqHKFr5y0N3Eo5IIisxeEeRAajNq4mELb/WELOR7srdbQk2N5XiyNy2A/AgvlR3AmeBCZJW8lHrolbw==",
+ "requires": {
+ "acorn": "^5.0.0",
+ "acorn-dynamic-import": "^2.0.0",
+ "ajv": "^5.1.5",
+ "ajv-keywords": "^2.0.0",
+ "async": "^2.1.2",
+ "enhanced-resolve": "^3.4.0",
+ "escope": "^3.6.0",
+ "interpret": "^1.0.0",
+ "json-loader": "^0.5.4",
+ "json5": "^0.5.1",
+ "loader-runner": "^2.3.0",
+ "loader-utils": "^1.1.0",
+ "memory-fs": "~0.4.1",
+ "mkdirp": "~0.5.0",
+ "node-libs-browser": "^2.0.0",
+ "source-map": "^0.5.3",
+ "supports-color": "^4.2.1",
+ "tapable": "^0.2.7",
+ "uglifyjs-webpack-plugin": "^0.4.6",
+ "watchpack": "^1.4.0",
+ "webpack-sources": "^1.0.1",
+ "yargs": "^8.0.2"
+ },
+ "dependencies": {
+ "ajv-keywords": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz",
+ "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I="
+ },
+ "camelcase": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
+ "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0="
+ },
+ "cliui": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
+ "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
+ "requires": {
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1",
+ "wrap-ansi": "^2.0.0"
+ },
+ "dependencies": {
+ "string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ }
+ }
+ },
+ "has-flag": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
+ "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE="
+ },
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "load-json-file": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
+ "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "parse-json": "^2.2.0",
+ "pify": "^2.0.0",
+ "strip-bom": "^3.0.0"
+ }
+ },
+ "os-locale": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz",
+ "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==",
+ "requires": {
+ "execa": "^0.7.0",
+ "lcid": "^1.0.0",
+ "mem": "^1.1.0"
+ }
+ },
+ "path-type": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz",
+ "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=",
+ "requires": {
+ "pify": "^2.0.0"
+ }
+ },
+ "read-pkg": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",
+ "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=",
+ "requires": {
+ "load-json-file": "^2.0.0",
+ "normalize-package-data": "^2.3.2",
+ "path-type": "^2.0.0"
+ }
+ },
+ "read-pkg-up": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz",
+ "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=",
+ "requires": {
+ "find-up": "^2.0.0",
+ "read-pkg": "^2.0.0"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ },
+ "strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM="
+ },
+ "supports-color": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",
+ "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=",
+ "requires": {
+ "has-flag": "^2.0.0"
+ }
+ },
+ "which-module": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
+ },
+ "yargs": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz",
+ "integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=",
+ "requires": {
+ "camelcase": "^4.1.0",
+ "cliui": "^3.2.0",
+ "decamelize": "^1.1.1",
+ "get-caller-file": "^1.0.1",
+ "os-locale": "^2.0.0",
+ "read-pkg-up": "^2.0.0",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^1.0.1",
+ "set-blocking": "^2.0.0",
+ "string-width": "^2.0.0",
+ "which-module": "^2.0.0",
+ "y18n": "^3.2.1",
+ "yargs-parser": "^7.0.0"
+ }
+ },
+ "yargs-parser": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz",
+ "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=",
+ "requires": {
+ "camelcase": "^4.1.0"
+ }
+ }
+ }
+ },
+ "webpack-dev-middleware": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-1.12.2.tgz",
+ "integrity": "sha512-FCrqPy1yy/sN6U/SaEZcHKRXGlqU0DUaEBL45jkUYoB8foVb6wCnbIJ1HKIx+qUFTW+3JpVcCJCxZ8VATL4e+A==",
+ "requires": {
+ "memory-fs": "~0.4.1",
+ "mime": "^1.5.0",
+ "path-is-absolute": "^1.0.0",
+ "range-parser": "^1.0.3",
+ "time-stamp": "^2.0.0"
+ }
+ },
+ "webpack-dev-server": {
+ "version": "2.9.4",
+ "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-2.9.4.tgz",
+ "integrity": "sha512-thrqC0EQEoSjXeYgP6pUXcUCZ+LNrKsDPn+mItLnn5VyyNZOJKd06hUP5vqkYwL8nWWXsii0loSF9NHNccT6ow==",
+ "requires": {
+ "ansi-html": "0.0.7",
+ "array-includes": "^3.0.3",
+ "bonjour": "^3.5.0",
+ "chokidar": "^1.6.0",
+ "compression": "^1.5.2",
+ "connect-history-api-fallback": "^1.3.0",
+ "debug": "^3.1.0",
+ "del": "^3.0.0",
+ "express": "^4.13.3",
+ "html-entities": "^1.2.0",
+ "http-proxy-middleware": "~0.17.4",
+ "import-local": "^0.1.1",
+ "internal-ip": "1.2.0",
+ "ip": "^1.1.5",
+ "killable": "^1.0.0",
+ "loglevel": "^1.4.1",
+ "opn": "^5.1.0",
+ "portfinder": "^1.0.9",
+ "selfsigned": "^1.9.1",
+ "serve-index": "^1.7.2",
+ "sockjs": "0.3.18",
+ "sockjs-client": "1.1.4",
+ "spdy": "^3.4.1",
+ "strip-ansi": "^3.0.1",
+ "supports-color": "^4.2.1",
+ "webpack-dev-middleware": "^1.11.0",
+ "yargs": "^6.6.0"
+ },
+ "dependencies": {
+ "camelcase": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
+ "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo="
+ },
+ "chokidar": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
+ "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=",
+ "requires": {
+ "anymatch": "^1.3.0",
+ "async-each": "^1.0.0",
+ "fsevents": "^1.0.0",
+ "glob-parent": "^2.0.0",
+ "inherits": "^2.0.1",
+ "is-binary-path": "^1.0.0",
+ "is-glob": "^2.0.0",
+ "path-is-absolute": "^1.0.0",
+ "readdirp": "^2.0.0"
+ }
+ },
+ "cliui": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
+ "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
+ "requires": {
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1",
+ "wrap-ansi": "^2.0.0"
+ }
+ },
+ "debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "del": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz",
+ "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=",
+ "requires": {
+ "globby": "^6.1.0",
+ "is-path-cwd": "^1.0.0",
+ "is-path-in-cwd": "^1.0.0",
+ "p-map": "^1.1.1",
+ "pify": "^3.0.0",
+ "rimraf": "^2.2.8"
+ }
+ },
+ "globby": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
+ "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=",
+ "requires": {
+ "array-union": "^1.0.1",
+ "glob": "^7.0.3",
+ "object-assign": "^4.0.1",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ },
+ "dependencies": {
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
+ }
+ }
+ },
+ "has-flag": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
+ "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE="
+ },
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY="
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",
+ "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=",
+ "requires": {
+ "has-flag": "^2.0.0"
+ }
+ },
+ "yargs": {
+ "version": "6.6.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz",
+ "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=",
+ "requires": {
+ "camelcase": "^3.0.0",
+ "cliui": "^3.2.0",
+ "decamelize": "^1.1.1",
+ "get-caller-file": "^1.0.1",
+ "os-locale": "^1.4.0",
+ "read-pkg-up": "^1.0.1",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^1.0.1",
+ "set-blocking": "^2.0.0",
+ "string-width": "^1.0.2",
+ "which-module": "^1.0.0",
+ "y18n": "^3.2.1",
+ "yargs-parser": "^4.2.0"
+ }
+ },
+ "yargs-parser": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz",
+ "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=",
+ "requires": {
+ "camelcase": "^3.0.0"
+ }
+ }
+ }
+ },
+ "webpack-manifest-plugin": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-1.3.2.tgz",
+ "integrity": "sha512-MX60Bv2G83Zks9pi3oLOmRgnPAnwrlMn+lftMrWBm199VQjk46/xgzBi9lPfpZldw2+EI2S+OevuLIaDuxCWRw==",
+ "requires": {
+ "fs-extra": "^0.30.0",
+ "lodash": ">=3.5 <5"
+ },
+ "dependencies": {
+ "fs-extra": {
+ "version": "0.30.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz",
+ "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=",
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "jsonfile": "^2.1.0",
+ "klaw": "^1.0.0",
+ "path-is-absolute": "^1.0.0",
+ "rimraf": "^2.2.8"
+ }
+ },
+ "jsonfile": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
+ "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=",
+ "requires": {
+ "graceful-fs": "^4.1.6"
+ }
+ }
+ }
+ },
+ "webpack-sources": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.1.0.tgz",
+ "integrity": "sha512-aqYp18kPphgoO5c/+NaUvEeACtZjMESmDChuD3NBciVpah3XpMEU9VAAtIaB1BsfJWWTSdv8Vv1m3T0aRk2dUw==",
+ "requires": {
+ "source-list-map": "^2.0.0",
+ "source-map": "~0.6.1"
+ }
+ },
+ "websocket-driver": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz",
+ "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=",
+ "requires": {
+ "http-parser-js": ">=0.4.0",
+ "websocket-extensions": ">=0.1.1"
+ }
+ },
+ "websocket-extensions": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz",
+ "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg=="
+ },
+ "whatwg-encoding": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz",
+ "integrity": "sha512-jLBwwKUhi8WtBfsMQlL4bUUcT8sMkAtQinscJAe/M4KHCkHuUJAF6vuB0tueNIw4c8ziO6AkRmgY+jL3a0iiPw==",
+ "requires": {
+ "iconv-lite": "0.4.19"
+ },
+ "dependencies": {
+ "iconv-lite": {
+ "version": "0.4.19",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
+ "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ=="
+ }
+ }
+ },
+ "whatwg-fetch": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz",
+ "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng=="
+ },
+ "whatwg-url": {
+ "version": "4.8.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-4.8.0.tgz",
+ "integrity": "sha1-0pgaqRSMHgCkHFphMRZqtGg7vMA=",
+ "requires": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ },
+ "dependencies": {
+ "webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
+ }
+ }
+ },
+ "whet.extend": {
+ "version": "0.9.9",
+ "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz",
+ "integrity": "sha1-+HfVv2SMl+WqVC+twW1qJZucEaE="
+ },
+ "which": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ },
+ "which-module": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
+ "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8="
+ },
+ "widest-line": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.0.tgz",
+ "integrity": "sha1-AUKk6KJD+IgsAjOqDgKBqnYVInM=",
+ "requires": {
+ "string-width": "^2.1.1"
+ }
+ },
+ "window-size": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
+ "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0="
+ },
+ "wordwrap": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+ "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus="
+ },
+ "worker-farm": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.6.0.tgz",
+ "integrity": "sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==",
+ "requires": {
+ "errno": "~0.1.7"
+ }
+ },
+ "wrap-ansi": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+ "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
+ "requires": {
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1"
+ },
+ "dependencies": {
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ }
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+ },
+ "write": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz",
+ "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=",
+ "requires": {
+ "mkdirp": "^0.5.1"
+ }
+ },
+ "write-file-atomic": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz",
+ "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==",
+ "requires": {
+ "graceful-fs": "^4.1.11",
+ "imurmurhash": "^0.1.4",
+ "signal-exit": "^3.0.2"
+ }
+ },
+ "xdg-basedir": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz",
+ "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ="
+ },
+ "xml-name-validator": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz",
+ "integrity": "sha1-TYuPHszTQZqjYgYb7O9RXh5VljU="
+ },
+ "xmlhttprequest": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz",
+ "integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw="
+ },
+ "xtend": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz",
+ "integrity": "sha1-XM50B7r2Qsunvs2laBEcST9ZZlo="
+ },
+ "y18n": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
+ "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE="
+ },
+ "yallist": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+ "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
+ },
+ "yargs": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz",
+ "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=",
+ "requires": {
+ "camelcase": "^3.0.0",
+ "cliui": "^3.2.0",
+ "decamelize": "^1.1.1",
+ "get-caller-file": "^1.0.1",
+ "os-locale": "^1.4.0",
+ "read-pkg-up": "^1.0.1",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^1.0.1",
+ "set-blocking": "^2.0.0",
+ "string-width": "^1.0.2",
+ "which-module": "^1.0.0",
+ "y18n": "^3.2.1",
+ "yargs-parser": "^5.0.0"
+ },
+ "dependencies": {
+ "camelcase": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
+ "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo="
+ },
+ "cliui": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
+ "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
+ "requires": {
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1",
+ "wrap-ansi": "^2.0.0"
+ }
+ },
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ }
+ }
+ },
+ "yargs-parser": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz",
+ "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=",
+ "requires": {
+ "camelcase": "^3.0.0"
+ },
+ "dependencies": {
+ "camelcase": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
+ "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo="
+ }
+ }
+ }
+ }
+}
diff --git a/diplomacy/web/package.json b/diplomacy/web/package.json
new file mode 100644
index 0000000..43d6617
--- /dev/null
+++ b/diplomacy/web/package.json
@@ -0,0 +1,29 @@
+{
+ "name": "web",
+ "version": "0.1.0",
+ "private": true,
+ "dependencies": {
+ "@githubprimer/octicons-react": "^8.0.0",
+ "bootstrap": "^4.1.3",
+ "fancybox": "^3.0.1",
+ "jquery": "^3.3.1",
+ "popper.js": "^1.14.4",
+ "prop-types": "^15.6.2",
+ "react": "^16.4.2",
+ "react-dom": "^16.4.2",
+ "react-inlinesvg": "^0.8.1",
+ "react-scripts": "1.1.4",
+ "react-scrollchor": "^6.0.0",
+ "react-shortcut": "^1.0.6"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test --env=jsdom",
+ "eject": "react-scripts eject"
+ },
+ "devDependencies": {
+ "eslint": "^4.19.1",
+ "eslint-plugin-react": "^7.10.0"
+ }
+}
diff --git a/diplomacy/web/public/favicon.ico b/diplomacy/web/public/favicon.ico
new file mode 100644
index 0000000..a11777c
--- /dev/null
+++ b/diplomacy/web/public/favicon.ico
Binary files differ
diff --git a/diplomacy/web/public/index.html b/diplomacy/web/public/index.html
new file mode 100644
index 0000000..20cf957
--- /dev/null
+++ b/diplomacy/web/public/index.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+ <meta name="theme-color" content="#000000">
+ <!--
+ manifest.json provides metadata used when your web app is added to the
+ homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
+ -->
+ <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
+ <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
+ <!--
+ Notice the use of %PUBLIC_URL% in the tags above.
+ It will be replaced with the URL of the `public` folder during the build.
+ Only files inside the `public` folder can be referenced from the HTML.
+
+ Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
+ work correctly both with client-side routing and a non-root public URL.
+ Learn how to configure a non-root public URL by running `npm run build`.
+ -->
+ <title>Diplomacy</title>
+ </head>
+ <body>
+ <noscript>
+ You need to enable JavaScript to run this app.
+ </noscript>
+ <div id="root"></div>
+ <!--
+ This HTML file is a template.
+ If you open it directly in the browser, you will see an empty page.
+
+ You can add webfonts, meta tags, or analytics to this file.
+ The build step will place the bundled scripts into the <body> tag.
+
+ To begin the development, run `npm start` or `yarn start`.
+ To create a production bundle, use `npm run build` or `yarn build`.
+ -->
+ </body>
+</html>
diff --git a/diplomacy/web/public/manifest.json b/diplomacy/web/public/manifest.json
new file mode 100644
index 0000000..07cc3db
--- /dev/null
+++ b/diplomacy/web/public/manifest.json
@@ -0,0 +1,15 @@
+{
+ "short_name": "Diplomacy",
+ "name": "Diplomacy Game",
+ "icons": [
+ {
+ "src": "favicon.ico",
+ "sizes": "64x64 32x32 24x24 16x16",
+ "type": "image/x-icon"
+ }
+ ],
+ "start_url": "./index.html",
+ "display": "standalone",
+ "theme_color": "#000000",
+ "background_color": "#ffffff"
+}
diff --git a/diplomacy/web/src/diplomacy/client/channel.js b/diplomacy/web/src/diplomacy/client/channel.js
new file mode 100644
index 0000000..eb8692a
--- /dev/null
+++ b/diplomacy/web/src/diplomacy/client/channel.js
@@ -0,0 +1,256 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import {STRINGS} from "../utils/strings";
+import {UTILS} from "../utils/utils";
+import {REQUESTS} from "../communication/requests";
+
+/** Class Channel. **/
+export class Channel {
+ constructor(connection, username, token) {
+ this.connection = connection;
+ this.token = token;
+ this.username = username;
+ this.game_id_to_instances = {};
+ }
+
+ localJoinGame(joinParameters) {
+ // Game ID must be known.
+ if (this.game_id_to_instances.hasOwnProperty(joinParameters.game_id)) {
+ // If there is a power name, we return associated power game.
+ if (joinParameters.power_name)
+ return this.game_id_to_instances[joinParameters.game_id].get(joinParameters.power_name);
+ // Otherwise, we return current special game (if exists).
+ return this.game_id_to_instances[joinParameters.game_id].getSpecial();
+ }
+ return null;
+ }
+
+ _req(name, forcedParameters, localChannelFunction, parameters, game) {
+ /** Send a request object for given request name with (optional) given forced parameters..
+ * If a local channel function is given, it will be used to try retrieving a data
+ * locally instead of sending a request. If local channel function returns something, this value is returned.
+ * Otherwise, normal procedure (request sending) is used. Local channel function would be called with
+ * request parameters passed to channel request method.
+ * **/
+ parameters = Object.assign(parameters || {}, forcedParameters || {});
+ const level = REQUESTS.getLevel(name);
+ if (level === STRINGS.GAME) {
+ if (!game)
+ throw new Error('A game object is required to send a game request.');
+ parameters.token = this.token;
+ parameters.game_id = game.local.game_id;
+ parameters.game_role = game.local.role;
+ parameters.phase = game.local.phase;
+ } else {
+ if (game)
+ throw new Error('A game object should not be provided for a non-game request.');
+ if (level === STRINGS.CHANNEL)
+ parameters.token = this.token;
+ }
+ if (localChannelFunction) {
+ const localResult = localChannelFunction.apply(this, [parameters]);
+ if (localResult)
+ return localResult;
+ }
+ const request = REQUESTS.create(name, parameters);
+ const future = this.connection.send(request, game);
+ const timeoutID = setTimeout(function () {
+ if (!future.done())
+ future.setException('Timeout reached when trying to send a request ' + name + '/' + request.request_id + '.');
+ }, UTILS.REQUEST_TIMEOUT_SECONDS * 1000);
+ return future.promise().then((result) => {
+ clearTimeout(timeoutID);
+ return result;
+ });
+ }
+
+ //// Public channel API.
+
+ createGame(parameters) {
+ return this._req('create_game', undefined, undefined, parameters, undefined);
+ }
+
+ getAvailableMaps(parameters) {
+ return this._req('get_available_maps', undefined, undefined, parameters, undefined);
+ }
+
+ getPlayablePowers(parameters) {
+ return this._req('get_playable_powers', undefined, undefined, parameters, undefined);
+ }
+
+ joinGame(parameters) {
+ return this._req('join_game', null, this.localJoinGame, parameters, undefined);
+ }
+
+ listGames(parameters) {
+ return this._req('list_games', undefined, undefined, parameters, undefined);
+ }
+
+ getGamesInfo(parameters) {
+ return this._req('get_games_info', undefined, undefined, parameters, undefined);
+ }
+
+ // User account API.
+
+ deleteAccount(parameters) {
+ return this._req('delete_account', undefined, undefined, parameters, undefined);
+ }
+
+ logout(parameters) {
+ return this._req('logout', undefined, undefined, parameters, undefined);
+ }
+
+ // Admin/moderator API.
+
+ makeOmniscient(parameters) {
+ return this._req('set_grade', {
+ grade: STRINGS.OMNISCIENT,
+ grade_update: STRINGS.PROMOTE
+ }, undefined, parameters, undefined);
+ }
+
+ removeOmniscient(parameters) {
+ return this._req('set_grade', {
+ grade: STRINGS.OMNISCIENT,
+ grade_update: STRINGS.DEMOTE
+ }, undefined, parameters, undefined);
+ }
+
+ promoteAdministrator(parameters) {
+ return this._req('set_grade', {
+ grade: STRINGS.ADMIN,
+ grade_update: STRINGS.PROMOTE
+ }, undefined, parameters, undefined);
+ }
+
+ demoteAdministrator(parameters) {
+ return this._req('set_grade', {
+ grade: STRINGS.ADMIN,
+ grade_update: STRINGS.DEMOTE
+ }, undefined, parameters, undefined);
+ }
+
+ promoteModerator(parameters) {
+ return this._req('set_grade', {
+ grade: STRINGS.MODERATOR,
+ grade_update: STRINGS.PROMOTE
+ }, undefined, parameters, undefined);
+ }
+
+ demoteModerator(parameters) {
+ return this._req('set_grade', {
+ grade: STRINGS.MODERATOR,
+ grade_update: STRINGS.DEMOTE
+ }, undefined, parameters, undefined);
+ }
+
+ //// Public game API.
+
+ getAllPossibleOrders(parameters, game) {
+ return this._req('get_all_possible_orders', undefined, undefined, parameters, game);
+ }
+
+ getPhaseHistory(parameters, game) {
+ return this._req('get_phase_history', undefined, undefined, parameters, game);
+ }
+
+ leaveGame(parameters, game) {
+ return this._req('leave_game', undefined, undefined, parameters, game);
+ }
+
+ sendGameMessage(parameters, game) {
+ return this._req('send_game_message', undefined, undefined, parameters, game);
+ }
+
+ setOrders(parameters, game) {
+ return this._req('set_orders', undefined, undefined, parameters, game);
+ }
+
+ clearCenters(parameters, game) {
+ return this._req('clear_centers', undefined, undefined, parameters, game);
+ }
+
+ clearOrders(parameters, game) {
+ return this._req('clear_orders', undefined, undefined, parameters, game);
+ }
+
+ clearUnits(parameters, game) {
+ return this._req('clear_units', undefined, undefined, parameters, game);
+ }
+
+ wait(parameters, game) {
+ return this._req('set_wait_flag', {wait: true}, undefined, parameters, game);
+ }
+
+ noWait(parameters, game) {
+ return this._req('set_wait_flag', {wait: false}, undefined, parameters, game);
+ }
+
+ vote(parameters, game) {
+ return this._req('vote', undefined, undefined, parameters, game);
+ }
+
+ save(parameters, game) {
+ return this._req('save_game', undefined, undefined, parameters, game);
+ }
+
+ synchronize(parameters, game) {
+ return this._req('synchronize', undefined, undefined, parameters, game);
+ }
+
+ // Admin/moderator game API.
+
+ deleteGame(parameters, game) {
+ return this._req('delete_game', undefined, undefined, parameters, game);
+ }
+
+ kickPowers(parameters, game) {
+ return this._req('set_dummy_powers', undefined, undefined, parameters, game);
+ }
+
+ setState(parameters, game) {
+ return this._req('set_game_state', undefined, undefined, parameters, game);
+ }
+
+ process(parameters, game) {
+ return this._req('process_game', undefined, undefined, parameters, game);
+ }
+
+ querySchedule(parameters, game) {
+ return this._req('query_schedule', undefined, undefined, parameters, game);
+ }
+
+ start(parameters, game) {
+ return this._req('set_game_status', {status: STRINGS.ACTIVE}, undefined, parameters, game);
+ }
+
+ pause(parameters, game) {
+ return this._req('set_game_status', {status: STRINGS.PAUSED}, undefined, parameters, game);
+ }
+
+ resume(parameters, game) {
+ return this._req('set_game_status', {status: STRINGS.ACTIVE}, undefined, parameters, game);
+ }
+
+ cancel(parameters, game) {
+ return this._req('set_game_status', {status: STRINGS.CANCELED}, undefined, parameters, game);
+ }
+
+ draw(parameters, game) {
+ return this._req('set_game_status', {status: STRINGS.COMPLETED}, undefined, parameters, game);
+ }
+}
diff --git a/diplomacy/web/src/diplomacy/client/connection.js b/diplomacy/web/src/diplomacy/client/connection.js
new file mode 100644
index 0000000..8931df5
--- /dev/null
+++ b/diplomacy/web/src/diplomacy/client/connection.js
@@ -0,0 +1,340 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+/*eslint no-unused-vars: ["error", { "args": "none" }]*/
+import {STRINGS} from "../utils/strings";
+import {UTILS} from "../utils/utils";
+import {REQUESTS} from "../communication/requests";
+import {RESPONSES} from "../communication/responses";
+import {NOTIFICATIONS} from "../communication/notifications";
+import {RESPONSE_MANAGERS} from "./response_managers";
+import {NOTIFICATION_MANAGERS} from "./notification_managers";
+import {Future} from "../utils/future";
+import {FutureEvent} from "../utils/future_event";
+import {RequestFutureContext} from "./request_future_context";
+import {Diplog} from "../utils/diplog";
+
+class Reconnection {
+ constructor(connection) {
+ this.connection = connection;
+ this.games_phases = {};
+ this.n_expected_games = 0;
+ this.n_synchronized_games = 0;
+ }
+
+ genSyncCallback(game) {
+ const reconnection = this;
+ return ((serverSyncResponse) => {
+ reconnection.games_phases[game.local.game_id][game.local.game_role] = serverSyncResponse;
+ ++reconnection.n_synchronized_games;
+ if (reconnection.n_synchronized_games === reconnection.n_expected_games)
+ reconnection.syncDone();
+ });
+ }
+
+ reconnect() {
+ for (let waitingContext of Object.values(this.connection.requestsWaitingResponses))
+ waitingContext.request.re_sent = true;
+ const lenWaiting = Object.keys(this.connection.requestsWaitingResponses).length;
+ const lenBefore = Object.keys(this.connection.requestsToSend).length;
+ Object.assign(this.connection.requestsToSend, this.connection.requestsWaitingResponses);
+ const lenAfter = Object.keys(this.connection.requestsToSend).length;
+ if (lenAfter !== lenWaiting + lenBefore)
+ throw new Error('Programming error.');
+ this.connection.requestsWaitingResponses = {};
+
+ const requestsToSendUpdated = {};
+ for (let context of Object.values(this.connection.requestsToSend)) {
+ if (context.request.name === STRINGS.SYNCHRONIZE)
+ context.future.setException(new Error('Sync request invalidated for game ID ' + context.request.game_id));
+ else
+ requestsToSendUpdated[context.request.request_id] = context;
+ }
+ this.connection.requestsToSend = requestsToSendUpdated;
+
+ for (let channel of Object.values(this.connection.channels)) {
+ for (let gis of Object.values(channel.game_id_to_instances)) {
+ for (let game of gis.getGames()) {
+ const game_id = game.local.game_id;
+ const game_role = game.local.role;
+ if (!this.games_phases.hasOwnProperty(game_id))
+ this.games_phases[game_id] = {};
+ this.games_phases[game_id][game_role] = null;
+ ++this.n_expected_games;
+ }
+ }
+ }
+
+ if (this.n_expected_games) {
+ for (let channel of Object.values(this.connection.channels))
+ for (let gis of Object.values(channel.game_id_to_instances))
+ for (let game of gis.getGames())
+ game.synchronize().then(this.genSyncCallback(game));
+ } else {
+ this.syncDone();
+ }
+ }
+
+ syncDone() {
+ const requestsToSendUpdated = {};
+ for (let context of Object.values(this.connection.requestsToSend)) {
+ let keep = true;
+ if (REQUESTS.isPhaseDependent(context.request.name)) {
+ const request_phase = context.request.phase;
+ const server_phase = this.games_phases[context.request.game_id][context.request.game_role].phase;
+ if (request_phase !== server_phase) {
+ context.future.setException(new Error(
+ 'Game ' + context.request.game_id + ': request ' + context.request.name +
+ ': request phase ' + request_phase + ' does not match current server game phase '
+ + server_phase + '.'));
+ keep = false;
+ }
+ }
+ if (keep)
+ requestsToSendUpdated[context.request.request_id] = context;
+ }
+ Diplog.info('Keep ' + Object.keys(requestsToSendUpdated).length + '/' +
+ Object.keys(this.connection.requestsToSend).length + ' old request(s) to send.');
+ this.connection.requestsToSend = requestsToSendUpdated;
+
+ for (let context of Object.values(requestsToSendUpdated)) {
+ this.connection.__write_request(context);
+ }
+
+ this.connection.isReconnecting.set();
+
+ Diplog.info('Done reconnection work.');
+ }
+}
+
+class ConnectionProcessing {
+ constructor(connection, logger) {
+ this.connection = connection;
+ this.logger = logger || Diplog;
+ this.isConnected = false;
+ this.attemptIndex = 1;
+ this.timeoutID = null;
+
+ this.onSocketOpen = this.onSocketOpen.bind(this);
+ this.onSocketTimeout = this.onSocketTimeout.bind(this);
+ this.tryConnect = this.tryConnect.bind(this);
+ }
+
+ __on_error(error) {
+ this.connection.isConnecting.set(error);
+ }
+
+ onSocketOpen(event) {
+ this.isConnected = true;
+ if (this.timeoutID) {
+ clearTimeout(this.timeoutID);
+ this.timeoutID = null;
+ }
+ // Socket open: set onMessage and onClose callbacks.
+ this.connection.socket.onmessage = this.connection.onSocketMessage;
+ this.connection.socket.onclose = this.connection.onSocketClose;
+ this.connection.currentConnectionProcessing = null;
+ this.connection.isConnecting.set();
+ this.logger.info('Connection succeeds.');
+ }
+
+ onSocketTimeout() {
+ if (!this.isConnected) {
+ this.connection.socket.close();
+ if (this.attemptIndex === UTILS.NB_CONNECTION_ATTEMPTS) {
+ this.connection.isConnecting.set(
+ new Error('Connection failed after ' + UTILS.NB_CONNECTION_ATTEMPTS + ' attempts.'));
+ return;
+ }
+ this.logger.warn('Connection failing (attempt ' + this.attemptIndex + '/' +
+ UTILS.NB_CONNECTION_ATTEMPTS + '), retrying ...');
+ ++this.attemptIndex;
+ setTimeout(this.tryConnect, 0);
+ }
+ }
+
+ tryConnect() {
+ // When opening a socket, we configure only onOpen callback.
+ // We will configure onMessage and onClose callbacks only when the socket will be effectively open.
+ try {
+ this.connection.socket = new WebSocket(this.connection.getUrl());
+ this.connection.socket.onopen = this.onSocketOpen;
+ this.timeoutID = setTimeout(this.onSocketTimeout, UTILS.ATTEMPT_DELAY_SECONDS * 1000);
+ } catch (error) {
+ this.__on_error(error);
+ }
+ }
+
+ process() {
+ this.connection.isConnecting.clear();
+ if (this.connection.socket)
+ this.connection.socket.close();
+ this.tryConnect();
+ return this.connection.isConnecting.wait();
+ }
+
+ stop() {
+ if (!this.isConnected) {
+ if (this.connection.socket)
+ this.connection.socket.onopen = null;
+ if (this.timeoutID) {
+ clearTimeout(this.timeoutID);
+ this.timeoutID = null;
+ }
+ }
+ }
+}
+
+/** Class Connection (like Python class diplomacy.client.connection.Connection). **/
+export class Connection {
+ constructor(hostname, port, useSSL) {
+ if (useSSL)
+ Diplog.info(`Using SSL.`);
+ this.protocol = useSSL ? 'wss' : 'ws';
+ this.hostname = hostname;
+ this.port = port;
+ this.socket = null;
+ this.isConnecting = new FutureEvent();
+ this.isReconnecting = new FutureEvent();
+ this.channels = {};
+ this.requestsToSend = {};
+ this.requestsWaitingResponses = {};
+ this.currentConnectionProcessing = null;
+
+ // Attribute used to make distinction between a connection
+ // explicitly closed by client and a connection closed for
+ // other unexpected reasons (e.g. by server).
+ this.closed = false;
+
+ this.onSocketMessage = this.onSocketMessage.bind(this);
+ this.onSocketClose = this.onSocketClose.bind(this);
+
+ this.isReconnecting.set();
+ }
+
+ getUrl() {
+ return this.protocol + '://' + this.hostname + ':' + this.port;
+ }
+
+ onSocketMessage(messageEvent) {
+ /** Callback used to manage a socket message string.
+ * Try-catch block will capture eventual:
+ * - JSON parsing errors
+ * - response parsing errors
+ * - response handling errors
+ * - notification parsing errors
+ * - notification handling errors
+ * **/
+ try {
+ const message = messageEvent.data;
+ const jsonMessage = JSON.parse(message);
+ if (!(jsonMessage instanceof Object)) {
+ Diplog.error('Unable to convert a message to a JSON object.');
+ return;
+ }
+ if (jsonMessage.request_id) {
+ const requestID = jsonMessage.request_id;
+ if (!this.requestsWaitingResponses.hasOwnProperty(requestID)) {
+ Diplog.error('Unknown request ' + requestID + '.');
+ return;
+ }
+ const context = this.requestsWaitingResponses[requestID];
+ delete this.requestsWaitingResponses[requestID];
+ try {
+ context.future.setResult(RESPONSE_MANAGERS.handleResponse(context, RESPONSES.parse(jsonMessage)));
+ } catch (error) {
+ context.future.setException(error);
+ }
+ } else if (jsonMessage.hasOwnProperty('notification_id') && jsonMessage.notification_id)
+ NOTIFICATION_MANAGERS.handleNotification(this, NOTIFICATIONS.parse(jsonMessage));
+ else
+ Diplog.error('Unknown socket message received.');
+ } catch (error) {
+ Diplog.error(error);
+ }
+ }
+
+ onSocketClose(closeEvent) {
+ if (this.closed)
+ Diplog.info('Disconnected.');
+ else {
+ Diplog.error('Disconnected, trying to reconnect.');
+ this.isReconnecting.clear();
+ this.__connect().then(() => new Reconnection(this).reconnect());
+ }
+ }
+
+ __connect(logger) {
+ if (this.currentConnectionProcessing) {
+ this.currentConnectionProcessing.stop();
+ this.currentConnectionProcessing = null;
+ }
+ this.currentConnectionProcessing = new ConnectionProcessing(this, logger);
+ return this.currentConnectionProcessing.process();
+ }
+
+ __write_request(requestContext) {
+ const writeFuture = new Future();
+ const request = requestContext.request;
+ const requestID = request.request_id;
+ const connection = this;
+
+ const onConnected = () => {
+ connection.socket.send(JSON.stringify(request));
+ connection.requestsWaitingResponses[requestID] = requestContext;
+ if (connection.requestsToSend.hasOwnProperty(requestID)) {
+ delete connection.requestsToSend[requestID];
+ }
+ writeFuture.setResult(null);
+ };
+ const onAnyError = (error) => {
+ if (!connection.requestsToSend.hasOwnProperty(requestID)) {
+ connection.requestsToSend[requestID] = requestContext;
+ }
+ Diplog.info('Error occurred while sending a request ' + requestID);
+ writeFuture.setException(error);
+ };
+ if (request.name === STRINGS.SYNCHRONIZE)
+ this.isConnecting.wait().then(onConnected, onAnyError);
+ else
+ this.isReconnecting.wait().then(onConnected, onAnyError);
+ return writeFuture.promise();
+ }
+
+ connect(logger) {
+ Diplog.info('Trying to connect.');
+ return this.__connect(logger);
+ }
+
+ send(request, game = null) {
+ const requestContext = new RequestFutureContext(request, this, game);
+ this.__write_request(requestContext);
+ return requestContext.future;
+ }
+
+ authenticate(username, password, createUser = false) {
+ return this.send(REQUESTS.create('sign_in', {
+ username: username,
+ password: password,
+ create_user: createUser
+ })).promise();
+ }
+
+ close() {
+ this.closed = true;
+ this.socket.close();
+ }
+}
diff --git a/diplomacy/web/src/diplomacy/client/game_instance_set.js b/diplomacy/web/src/diplomacy/client/game_instance_set.js
new file mode 100644
index 0000000..ca92e48
--- /dev/null
+++ b/diplomacy/web/src/diplomacy/client/game_instance_set.js
@@ -0,0 +1,76 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import {STRINGS} from "../utils/strings";
+import {UTILS} from "../utils/utils";
+
+export class GameInstanceSet {
+ constructor(gameID) {
+ this.__game_id = gameID;
+ this.__games = {};
+ }
+
+ getGames() {
+ return Object.values(this.__games);
+ }
+
+ has(role) {
+ return this.__games.hasOwnProperty(role);
+ }
+
+ get(role) {
+ return this.__games[role] || null;
+ }
+
+ getSpecial() {
+ if (this.__games.hasOwnProperty(STRINGS.OBSERVER_TYPE))
+ return this.__games[STRINGS.OBSERVER_TYPE];
+ if (this.__games.hasOwnProperty(STRINGS.OMNISCIENT_TYPE))
+ return this.__games[STRINGS.OMNISCIENT_TYPE];
+ return null;
+ }
+
+ remove(role) {
+ let old = null;
+ if (this.__games[role]) {
+ old = this.__games[role];
+ delete this.__games[role];
+ }
+ return old;
+ }
+
+ removeSpecial() {
+ if (this.__games.hasOwnProperty(STRINGS.OBSERVER_TYPE))
+ delete this.__games[STRINGS.OBSERVER_TYPE];
+ if (this.__games.hasOwnProperty(STRINGS.OMNISCIENT_TYPE))
+ delete this.__games[STRINGS.OMNISCIENT_TYPE];
+ }
+
+ add(game) {
+ if (game.local.game_id !== this.__game_id)
+ throw new Error('game ID to add does not match game instance set ID.');
+ if (this.__games.hasOwnProperty(game.local.role))
+ throw new Error('Role already in game instance set.');
+ if (!game.local.isPlayerGame() && (
+ this.__games.hasOwnProperty(STRINGS.OBSERVER_TYPE) || this.__games.hasOwnProperty(STRINGS.OMNISCIENT_TYPE)))
+ throw new Error('Previous special game must be removed before adding new one.');
+ this.__games[game.local.role] = game;
+ }
+
+ size() {
+ return UTILS.javascript.count(this.__games);
+ }
+}
diff --git a/diplomacy/web/src/diplomacy/client/network_game.js b/diplomacy/web/src/diplomacy/client/network_game.js
new file mode 100644
index 0000000..9999093
--- /dev/null
+++ b/diplomacy/web/src/diplomacy/client/network_game.js
@@ -0,0 +1,297 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import {Channel} from "./channel";
+import {Game} from "../engine/game";
+
+/** Class NetworkGame. **/
+
+export class NetworkGame {
+ constructor(channel, serverGameState) {
+ // Let's use a "local" instance to manage game.
+ // This will help make distinction between network game request methods and local gme methods
+ // (e.g. for request set_orders).
+ this.local = new Game(serverGameState);
+ this.channel = channel;
+ this.notificationCallbacks = {};
+ this.data = null;
+ this.local.client = this;
+ }
+
+ addCallback(notificationName, notificationCallback) {
+ if (!this.notificationCallbacks.hasOwnProperty(notificationName))
+ this.notificationCallbacks[notificationName] = [notificationCallback];
+ else if (!this.notificationCallbacks[notificationName].includes(notificationCallback))
+ this.notificationCallbacks[notificationName].push(notificationCallback);
+ }
+
+ clearCallbacks(notificationName) {
+ if (this.notificationCallbacks.hasOwnProperty(notificationName))
+ delete this.notificationCallbacks[notificationName];
+ }
+
+ clearAllCallbacks() {
+ this.notificationCallbacks = {};
+ }
+
+ notify(notification) {
+ if (this.notificationCallbacks.hasOwnProperty(notification.name)) {
+ for (let callback of this.notificationCallbacks[notification.name])
+ setTimeout(() => callback(this, notification), 0);
+ }
+ }
+
+ _req(channelMethod, parameters) {
+ /** Send a game request using given channel request method. **/
+ if (!this.channel)
+ throw new Error('Invalid client game.');
+ return channelMethod.apply(this.channel, [parameters, this]);
+ }
+
+ //// Game requests API.
+
+ getAllPossibleOrders(parameters) {
+ return this._req(Channel.prototype.getAllPossibleOrders, parameters);
+ }
+
+ getPhaseHistory(parameters) {
+ return this._req(Channel.prototype.getPhaseHistory, parameters);
+ }
+
+ leave(parameters) {
+ return this._req(Channel.prototype.leaveGame, parameters);
+ }
+
+ sendGameMessage(parameters) {
+ return this._req(Channel.prototype.sendGameMessage, parameters);
+ }
+
+ setOrders(parameters) {
+ return this._req(Channel.prototype.setOrders, parameters);
+ }
+
+ clearCenters(parameters) {
+ return this._req(Channel.prototype.clearCenters, parameters);
+ }
+
+ clearOrders(parameters) {
+ return this._req(Channel.prototype.clearOrders, parameters);
+ }
+
+ clearUnits(parameters) {
+ return this._req(Channel.prototype.clearUnits, parameters);
+ }
+
+ wait(parameters) {
+ return this._req(Channel.prototype.wait, parameters);
+ }
+
+ noWait(parameters) {
+ return this._req(Channel.prototype.noWait, parameters);
+ }
+
+ setWait(wait, parameters) {
+ return wait ? this.wait(parameters) : this.noWait(parameters);
+ }
+
+ vote(parameters) {
+ return this._req(Channel.prototype.vote, parameters);
+ }
+
+ save(parameters) {
+ return this._req(Channel.prototype.save, parameters);
+ }
+
+ synchronize() {
+ if (!this.channel)
+ throw new Error('Invalid client game.');
+ return Channel.prototype.synchronize.apply(this.channel, [{timestamp: this.local.getLatestTimestamp()}, this]);
+ }
+
+ // Admin/moderator API.
+
+ remove(parameters) {
+ return this._req(Channel.prototype.deleteGame, parameters);
+ }
+
+ kickPowers(parameters) {
+ return this._req(Channel.prototype.kickPowers, parameters);
+ }
+
+ setState(parameters) {
+ return this._req(Channel.prototype.setState, parameters);
+ }
+
+ process(parameters) {
+ return this._req(Channel.prototype.process, parameters);
+ }
+
+ querySchedule(parameters) {
+ return this._req(Channel.prototype.querySchedule, parameters);
+ }
+
+ start(parameters) {
+ return this._req(Channel.prototype.start, parameters);
+ }
+
+ pause(parameters) {
+ return this._req(Channel.prototype.pause, parameters);
+ }
+
+ resume(parameters) {
+ return this._req(Channel.prototype.resume, parameters);
+ }
+
+ cancel(parameters) {
+ return this._req(Channel.prototype.cancel, parameters);
+ }
+
+ draw(parameters) {
+ return this._req(Channel.prototype.draw, parameters);
+ }
+
+ //// Game callbacks setting API.
+
+ addOnClearedCenters(callback) {
+ this.addCallback('cleared_centers', callback);
+ }
+
+ addOnClearedOrders(callback) {
+ this.addCallback('cleared_orders', callback);
+ }
+
+ addOnClearedUnits(callback) {
+ this.addCallback('cleared_units', callback);
+ }
+
+ addOnPowersControllers(callback) {
+ this.addCallback('powers_controllers', callback);
+ }
+
+ addOnGameDeleted(callback) {
+ this.addCallback('game_deleted', callback);
+ }
+
+ addOnGameMessageReceived(callback) {
+ this.addCallback('game_message_received', callback);
+ }
+
+ addOnGameProcessed(callback) {
+ this.addCallback('game_processed', callback);
+ }
+
+ addOnGamePhaseUpdate(callback) {
+ this.addCallback('game_phase_update', callback);
+ }
+
+ addOnGameStatusUpdate(callback) {
+ this.addCallback('game_status_update', callback);
+ }
+
+ addOnOmniscientUpdated(callback) {
+ this.addCallback('omniscient_updated', callback);
+ }
+
+ addOnPowerOrdersUpdate(callback) {
+ this.addCallback('power_orders_update', callback);
+ }
+
+ addOnPowerOrdersFlag(callback) {
+ this.addCallback('power_orders_flag', callback);
+ }
+
+ addOnPowerVoteUpdated(callback) {
+ this.addCallback('power_vote_updated', callback);
+ }
+
+ addOnPowerWaitFlag(callback) {
+ this.addCallback('power_wait_flag', callback);
+ }
+
+ addOnVoteCountUpdated(callback) {
+ this.addCallback('vote_count_updated', callback);
+ }
+
+ addOnVoteUpdated(callback) {
+ this.addCallback('vote_updated', callback);
+ }
+
+ //// Game callbacks clearing API.
+
+ clearOnClearedCenters() {
+ this.clearCallbacks('cleared_centers');
+ }
+
+ clearOnClearedOrders() {
+ this.clearCallbacks('cleared_orders');
+ }
+
+ clearOnClearedUnits() {
+ this.clearCallbacks('cleared_units');
+ }
+
+ clearOnPowersControllers() {
+ this.clearCallbacks('powers_controllers');
+ }
+
+ clearOnGameDeleted() {
+ this.clearCallbacks('game_deleted');
+ }
+
+ clearOnGameMessageReceived() {
+ this.clearCallbacks('game_message_received');
+ }
+
+ clearOnGameProcessed() {
+ this.clearCallbacks('game_processed');
+ }
+
+ clearOnGamePhaseUpdate() {
+ this.clearCallbacks('game_phase_update');
+ }
+
+ clearOnGameStatusUpdate() {
+ this.clearCallbacks('game_status_update');
+ }
+
+ clearOnOmniscientUpdated() {
+ this.clearCallbacks('omniscient_updated');
+ }
+
+ clearOnPowerOrdersUpdate() {
+ this.clearCallbacks('power_orders_update');
+ }
+
+ clearOnPowerOrdersFlag() {
+ this.clearCallbacks('power_orders_flag');
+ }
+
+ clearOnPowerVoteUpdated() {
+ this.clearCallbacks('power_vote_updated');
+ }
+
+ clearOnPowerWaitFlag() {
+ this.clearCallbacks('power_wait_flag');
+ }
+
+ clearOnVoteCountUpdated() {
+ this.clearCallbacks('vote_count_updated');
+ }
+
+ clearOnVoteUpdated() {
+ this.clearCallbacks('vote_updated');
+ }
+}
diff --git a/diplomacy/web/src/diplomacy/client/notification_managers.js b/diplomacy/web/src/diplomacy/client/notification_managers.js
new file mode 100644
index 0000000..bbfe862
--- /dev/null
+++ b/diplomacy/web/src/diplomacy/client/notification_managers.js
@@ -0,0 +1,127 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+/*eslint no-unused-vars: ["error", { "args": "none" }]*/
+import {STRINGS} from "../utils/strings";
+import {NOTIFICATIONS} from "../communication/notifications";
+import {Game} from "../engine/game";
+
+/** Notification managers. **/
+export const NOTIFICATION_MANAGERS = {
+ account_deleted: function (channel, notification) {
+ const connection = channel.connection;
+ if (connection.channels.hasOwnProperty(channel.token))
+ delete channel.connection.channels[channel.token];
+ },
+ cleared_centers: function (game, notification) {
+ game.local.clearCenters(notification.power_name);
+ },
+ cleared_orders: function (game, notification) {
+ game.local.clearOrders(notification.power_name);
+ },
+ cleared_units: function (game, notification) {
+ game.local.clearUnits(notification.power_name);
+ },
+ powers_controllers: function (game, notification) {
+ if (game.local.isPlayerGame() && notification.powers[game.local.role] !== game.local.getRelatedPower().getController()) {
+ game.channel.game_id_to_instances[game.local.game_id].remove(game.local.role);
+ if (!game.channel.game_id_to_instances[game.local.game_id].size())
+ delete game.channel.game_id_to_instances[game.local.game_id];
+ } else {
+ game.local.updatePowersControllers(notification.powers, notification.timestamps);
+ }
+ },
+ game_deleted: function (game, notification) {
+ game.channel.game_id_to_instances[game.local.game_id].remove(game.local.role);
+ },
+ game_message_received: function (game, notification) {
+ game.local.addMessage(notification.message);
+ },
+ game_processed: function (game, notification) {
+ game.local.extendPhaseHistory(notification.previous_phase_data);
+ game.local.setPhaseData(notification.current_phase_data);
+ game.local.clearVote();
+ },
+ game_phase_update: function (game, notification) {
+ if (notification.phase_data_type === STRINGS.STATE_HISTORY)
+ game.local.extendPhaseHistory(notification.phase_data);
+ else
+ game.local.setPhaseData(notification.phase_data);
+ },
+ game_status_update: function (game, notification) {
+ if (game.local.status !== notification.status) {
+ game.local.setStatus(notification.status);
+ }
+ },
+ omniscient_updated: function (game, notification) {
+ if (game.local.isPlayerGame()) return;
+ if (game.local.isObserverGame()) {
+ if (notification.grade_update !== STRINGS.PROMOTE || notification.game.role !== STRINGS.OMNISCIENT_TYPE)
+ throw new Error('Omniscient updated: expected promotion from observer to omniscient');
+ } else {
+ if (notification.grade_update !== STRINGS.DEMOTE || notification.game.role !== STRINGS.OBSERVER_TYPE)
+ throw new Error('Omniscient updated: expected demotion from omniscient to observer.');
+ }
+ const channel = game.channel;
+ const oldGame = channel.game_id_to_instances[game.local.game_id].remove(game.local.role);
+ oldGame.client = null;
+ game.local = new Game(notification.game);
+ game.local.client = game;
+ channel.game_id_to_instances[game.local.game_id].add(game);
+ },
+ power_orders_update: function (game, notification) {
+ game.local.setOrders(notification.power_name, notification.orders);
+ },
+ power_orders_flag: function (game, notification) {
+ game.local.getPower(notification.power_name).order_is_set = notification.order_is_set;
+ },
+ power_vote_updated: function (game, notification) {
+ game.local.assertPlayerGame();
+ game.local.getRelatedPower().vote = notification.vote;
+ },
+ power_wait_flag: function (game, notification) {
+ game.local.setWait(notification.power_name, notification.wait);
+ },
+ vote_count_updated: function (game, notification) {
+ // Nothing currently done.
+ },
+ vote_updated: function (game, notification) {
+ game.assertOmniscientGame();
+ for (let power_name of notification.vote) {
+ game.local.getPower(power_name).vote = notification.vote[power_name];
+ }
+ },
+ handleNotification: function (connection, notification) {
+ if (!NOTIFICATION_MANAGERS.hasOwnProperty(notification.name))
+ throw new Error('No notification handler available for notification ' + notification.name);
+ const handler = NOTIFICATION_MANAGERS[notification.name];
+ const level = NOTIFICATIONS.levels[notification.name];
+ if (!connection.channels.hasOwnProperty(notification.token))
+ throw new Error('Unable to find channel related to notification ' + notification.name);
+ let objectToNotify = connection.channels[notification.token];
+ if (level === STRINGS.GAME) {
+ if (objectToNotify.game_id_to_instances.hasOwnProperty(notification.game_id)
+ && objectToNotify.game_id_to_instances[notification.game_id].has(notification.game_role))
+ objectToNotify = objectToNotify.game_id_to_instances[notification.game_id].get(notification.game_role);
+ else
+ throw new Error('Unable to find game instance related to notification '
+ + notification.name + '/' + notification.game_id + '/' + notification.game_role);
+ }
+ handler(objectToNotify, notification);
+ if (level === STRINGS.GAME)
+ objectToNotify.notify(notification);
+ }
+};
diff --git a/diplomacy/web/src/diplomacy/client/request_future_context.js b/diplomacy/web/src/diplomacy/client/request_future_context.js
new file mode 100644
index 0000000..16103fb
--- /dev/null
+++ b/diplomacy/web/src/diplomacy/client/request_future_context.js
@@ -0,0 +1,63 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import {Future} from "../utils/future";
+import {Channel} from "./channel";
+import {GameInstanceSet} from "./game_instance_set";
+import {NetworkGame} from "./network_game";
+
+/** Class RequestFutureContext. **/
+export class RequestFutureContext {
+ constructor(request, connection, game = null) {
+ this.request = request;
+ this.connection = connection;
+ this.game = game;
+ this.future = new Future();
+ }
+
+ getRequestId() {
+ return this.request.request_id;
+ }
+
+ getChannel() {
+ return this.connection.channels[this.request.token];
+ }
+
+ newChannel(username, token) {
+ const channel = new Channel(this.connection, username, token);
+ this.connection.channels[token] = channel;
+ return channel;
+ }
+
+ newGame(received_game) {
+ const channel = this.getChannel();
+ const game = new NetworkGame(channel, received_game);
+ if (!channel.game_id_to_instances.hasOwnProperty(game.local.game_id))
+ channel.game_id_to_instances[game.local.game_id] = new GameInstanceSet(game.local.game_id);
+ channel.game_id_to_instances[game.local.game_id].add(game);
+ return game;
+ }
+
+ removeChannel() {
+ delete this.connection.channels[this.request.token];
+ }
+
+ deleteGame() {
+ const channel = this.getChannel();
+ if (channel.game_id_to_instances.hasOwnProperty(this.request.game_id))
+ delete channel.game_id_to_instances[this.request.game_id];
+ }
+}
diff --git a/diplomacy/web/src/diplomacy/client/response_managers.js b/diplomacy/web/src/diplomacy/client/response_managers.js
new file mode 100644
index 0000000..ba45938
--- /dev/null
+++ b/diplomacy/web/src/diplomacy/client/response_managers.js
@@ -0,0 +1,118 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+/*eslint no-unused-vars: ["error", { "args": "none" }]*/
+import {RESPONSES} from "../communication/responses";
+
+/** Default response manager. **/
+function defaultResponseManager(context, response) {
+ if (RESPONSES.isOk(response))
+ return null;
+ if (RESPONSES.isUniqueData(response))
+ return response.data;
+ return response;
+}
+
+/** Response managers. **/
+export const RESPONSE_MANAGERS = {
+ get_all_possible_orders: defaultResponseManager,
+ get_available_maps: defaultResponseManager,
+ get_playable_powers: defaultResponseManager,
+ list_games: defaultResponseManager,
+ get_games_info: defaultResponseManager,
+ process_game: defaultResponseManager,
+ query_schedule: defaultResponseManager,
+ save_game: defaultResponseManager,
+ set_dummy_powers: defaultResponseManager,
+ set_grade: defaultResponseManager,
+ synchronize: defaultResponseManager,
+ create_game: function (context, response) {
+ return context.newGame(response.data);
+ },
+ delete_account: function (context, response) {
+ context.removeChannel();
+ },
+ delete_game: function (context, response) {
+ context.deleteGame();
+ },
+ get_phase_history: function (context, response) {
+ for (let phaseData of response.data) {
+ context.game.local.extendPhaseHistory(phaseData);
+ }
+ return response.data;
+ },
+ join_game: function (context, response) {
+ return context.newGame(response.data);
+ },
+ leave_game: function (context, response) {
+ context.deleteGame();
+ },
+ logout: function (context, response) {
+ context.removeChannel();
+ },
+ send_game_message: function (context, response) {
+ const message = context.request.message;
+ message.time_sent = response.data;
+ context.game.local.addMessage(message);
+ },
+ set_game_state: function (context, response) {
+ context.game.local.setPhaseData({
+ name: context.request.state.name,
+ state: context.request.state,
+ orders: context.request.orders,
+ messages: context.request.messages,
+ results: context.request.results
+ });
+ },
+ set_game_status: function (context, response) {
+ context.game.local.setStatus(context.request.status);
+ },
+ set_orders: function (context, response) {
+ const orders = context.request.orders;
+ if (context.game.local.isPlayerGame(context.request.game_role))
+ context.game.local.setOrders(context.request.game_role, orders);
+ else
+ context.game.local.setOrders(context.request.power_name, orders);
+ },
+ clear_orders: function (context, response) {
+ context.game.local.clearOrders(context.request.power_name);
+ },
+ clear_units: function (context, response) {
+ context.game.local.clearUnits(context.request.power_name);
+ },
+ clear_centers: function (context, response) {
+ context.game.local.clearCenters(context.request.power_name);
+ },
+ set_wait_flag: function (context, response) {
+ const wait = context.request.wait;
+ if (context.game.local.isPlayerGame(context.request.game_role))
+ context.game.local.setWait(context.request.game_role, wait);
+ else
+ context.game.local.setWait(context.request.power_name, wait);
+ },
+ vote: function (context, response) {
+ context.game.local.getRelatedPower().vote = context.request.vote;
+ },
+ sign_in: function (context, response) {
+ return context.newChannel(context.request.username, response.data);
+ },
+ handleResponse: function (context, response) {
+ if (!RESPONSE_MANAGERS.hasOwnProperty(context.request.name))
+ throw new Error('No response handler available for request ' + context.request.name);
+ const handler = RESPONSE_MANAGERS[context.request.name];
+ return handler(context, response);
+ }
+};
diff --git a/diplomacy/web/src/diplomacy/communication/notifications.js b/diplomacy/web/src/diplomacy/communication/notifications.js
new file mode 100644
index 0000000..149df09
--- /dev/null
+++ b/diplomacy/web/src/diplomacy/communication/notifications.js
@@ -0,0 +1,56 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import {STRINGS} from "../utils/strings";
+
+/** Notifications. **/
+export const NOTIFICATIONS = {
+ levels: {
+ // Notification name to notification level ('channel' or 'game').
+ account_deleted: STRINGS.CHANNEL,
+ cleared_centers: STRINGS.GAME,
+ cleared_orders: STRINGS.GAME,
+ cleared_units: STRINGS.GAME,
+ game_deleted: STRINGS.GAME,
+ game_message_received: STRINGS.GAME,
+ game_processed: STRINGS.GAME,
+ game_phase_update: STRINGS.GAME,
+ game_status_update: STRINGS.GAME,
+ omniscient_updated: STRINGS.GAME,
+ power_orders_flag: STRINGS.GAME,
+ power_orders_update: STRINGS.GAME,
+ power_vote_updated: STRINGS.GAME,
+ power_wait_flag: STRINGS.GAME,
+ powers_controllers: STRINGS.GAME,
+ vote_count_updated: STRINGS.GAME,
+ vote_updated: STRINGS.GAME,
+ },
+ parse: function (jsonObject) {
+ if (!jsonObject.hasOwnProperty('name'))
+ throw new Error('No name field in expected notification object.');
+ if (!jsonObject.hasOwnProperty('token'))
+ throw new Error('No token field in expected notification object.');
+ if (!NOTIFICATIONS.levels.hasOwnProperty(jsonObject.name))
+ throw new Error('Invalid notification name ' + jsonObject.name);
+ if (NOTIFICATIONS.levels[jsonObject.name] === STRINGS.GAME) {
+ if (!jsonObject.hasOwnProperty('game_id'))
+ throw new Error('No game_id field in expected game notification object.');
+ if (!jsonObject.hasOwnProperty('game_role'))
+ throw new Error('No game_role field in expected game notification object.');
+ }
+ return jsonObject;
+ }
+};
diff --git a/diplomacy/web/src/diplomacy/communication/requests.js b/diplomacy/web/src/diplomacy/communication/requests.js
new file mode 100644
index 0000000..6902b5f
--- /dev/null
+++ b/diplomacy/web/src/diplomacy/communication/requests.js
@@ -0,0 +1,120 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import {STRINGS} from "../utils/strings";
+import {UTILS} from "../utils/utils";
+
+/** Requests. **/
+export const REQUESTS = {
+ /** Abstract request models, mapping base request field names with default values.
+ * Every request has at least basic fields.
+ * Every channel request has at least basic and channel fields.
+ * Every game request has at least basic, channel and game fields. **/
+ abstract: {
+ basic: {request_id: null, name: null, re_sent: false},
+ channel: {token: null},
+ game: {game_id: null, game_role: null, phase: null},
+ },
+
+ /** Request models. A request model is defined with:
+ * - request level: either null, 'channel' or 'game'
+ * - request model itself: a dictionary mapping each request field name with a default value.
+ * - request phase dependent (optional, for game requests): boolean (default, true)
+ * **/
+ models: {
+ sign_in: {level: null, model: {username: null, password: null, create_user: null}},
+ create_game: {
+ level: STRINGS.CHANNEL,
+ model: {
+ game_id: null, n_controls: null, deadline: 300, registration_password: null,
+ power_name: null, state: null, map_name: 'standard', rules: null
+ }
+ },
+ delete_account: {level: STRINGS.CHANNEL, model: {username: null}},
+ get_all_possible_orders: {level: STRINGS.GAME, model: {}},
+ get_available_maps: {level: STRINGS.CHANNEL, model: {}},
+ get_playable_powers: {level: STRINGS.CHANNEL, model: {game_id: null}},
+ join_game: {level: STRINGS.CHANNEL, model: {game_id: null, power_name: null, registration_password: null}},
+ list_games: {
+ level: STRINGS.CHANNEL,
+ model: {game_id: null, status: null, map_name: null, include_protected: true, for_omniscience: false}
+ },
+ get_games_info: {level: STRINGS.CHANNEL, model: {games: null}},
+ logout: {level: STRINGS.CHANNEL, model: {}},
+ set_grade: {level: STRINGS.CHANNEL, model: {grade: null, grade_update: null, username: null, game_id: null}},
+ clear_centers: {level: STRINGS.GAME, model: {power_name: null}},
+ clear_orders: {level: STRINGS.GAME, model: {power_name: null}},
+ clear_units: {level: STRINGS.GAME, model: {power_name: null}},
+ delete_game: {level: STRINGS.GAME, phase_dependent: false, model: {}},
+ get_phase_history: {
+ level: STRINGS.GAME,
+ phase_dependent: false,
+ model: {from_phase: null, to_phase: null}
+ },
+ leave_game: {level: STRINGS.GAME, model: {}},
+ process_game: {level: STRINGS.GAME, model: {}},
+ query_schedule: {level: STRINGS.GAME, model: {}},
+ send_game_message: {level: STRINGS.GAME, model: {message: null}},
+ set_dummy_powers: {level: STRINGS.GAME, model: {username: null, power_names: null}},
+ set_game_state: {level: STRINGS.GAME, model: {state: null, orders: null, results: null, messages: null}},
+ set_game_status: {level: STRINGS.GAME, model: {status: null}},
+ set_orders: {level: STRINGS.GAME, model: {power_name: null, orders: null}},
+ set_wait_flag: {level: STRINGS.GAME, model: {power_name: null, wait: null}},
+ synchronize: {level: STRINGS.GAME, phase_dependent: false, model: {timestamp: null}},
+ vote: {level: STRINGS.GAME, model: {vote: null}},
+ save_game: {level: STRINGS.GAME, model: {}},
+ },
+
+ isPhaseDependent: function (name) {
+ if (!REQUESTS.models.hasOwnProperty(name))
+ throw new Error('Unknown request name ' + name);
+ const model = REQUESTS.models[name];
+ return (model.level === STRINGS.GAME && (!model.hasOwnProperty('phase_dependent') || model.phase_dependent));
+ },
+
+ /** Return request level for given request name. Either null, 'channel' or 'game'. **/
+ getLevel: function (name) {
+ if (!REQUESTS.models.hasOwnProperty(name))
+ throw new Error('Unknown request name ' + name);
+ return REQUESTS.models[name].level;
+ },
+
+ /** Create a request object for given request name with given request field values.
+ * `parameters` is a dictionary mapping some request fields with values.
+ * Parameters may not contain values for optional request fields. See Python module
+ * diplomacy.communication.requests about requests definitions, required and optional fields.
+ * **/
+ create: function (name, parameters) {
+ if (!REQUESTS.models.hasOwnProperty(name))
+ throw new Error('Unknown request name ' + name);
+ let models = null;
+ const definition = REQUESTS.models[name];
+ if (definition.level === STRINGS.GAME)
+ models = [{}, definition.model, REQUESTS.abstract.game, REQUESTS.abstract.channel];
+ else if (definition.level === STRINGS.CHANNEL)
+ models = [{}, definition.model, REQUESTS.abstract.channel];
+ else
+ models = [{}, definition.model];
+ models.push(REQUESTS.abstract.basic);
+ models.push({name: name});
+ const request = Object.assign.apply(null, models);
+ if (parameters) for (let parameter of Object.keys(parameters)) if (request.hasOwnProperty(parameter))
+ request[parameter] = parameters[parameter];
+ if (!request.request_id)
+ request.request_id = UTILS.createID();
+ return request;
+ },
+};
diff --git a/diplomacy/web/src/diplomacy/communication/responses.js b/diplomacy/web/src/diplomacy/communication/responses.js
new file mode 100644
index 0000000..7c87c67
--- /dev/null
+++ b/diplomacy/web/src/diplomacy/communication/responses.js
@@ -0,0 +1,42 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import {STRINGS} from "../utils/strings";
+
+/** Responses. **/
+export const RESPONSES = {
+ names: new Set([
+ 'error', 'ok', 'data_game_phase', 'data_token', 'data_maps', 'data_power_names', 'data_games',
+ 'data_possible_orders', 'data_game_info', 'data_time_stamp', 'data_game_phases', 'data_game',
+ 'data_game_schedule', 'data_saved_game'
+ ]),
+ parse: function (jsonObject) {
+ if (!jsonObject.hasOwnProperty('name'))
+ throw new Error('No name field in expected response object');
+ if (!RESPONSES.names.has(jsonObject.name))
+ throw new Error('Invalid response name ' + jsonObject.name);
+ if (jsonObject.name === STRINGS.ERROR)
+ throw new Error(jsonObject.name + ': ' + jsonObject.message);
+ return jsonObject;
+ },
+ isOk: function (response) {
+ return response.name === STRINGS.OK;
+ },
+ isUniqueData: function (response) {
+ // Expected only 3 fields: name, request_id, data.
+ return (response.hasOwnProperty('data') && Object.keys(response).length === 3);
+ }
+};
diff --git a/diplomacy/web/src/diplomacy/engine/game.js b/diplomacy/web/src/diplomacy/engine/game.js
new file mode 100644
index 0000000..cc9803e
--- /dev/null
+++ b/diplomacy/web/src/diplomacy/engine/game.js
@@ -0,0 +1,507 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import {UTILS} from "../utils/utils";
+import {STRINGS} from "../utils/strings";
+import {SortedDict} from "../utils/sorted_dict";
+import {Power} from "./power";
+import {Message} from "./message";
+
+export function comparablePhase(shortPhaseName) {
+ /** Return a unique integer corresponding to given short phase name, so that
+ * phases can be compared using such integers.
+ * **/
+ // Phase 'FORMING' is assumed to be the smallest phase.
+ if (shortPhaseName === 'FORMING')
+ return 0;
+ // Phase 'COMPLETED' is assumed to be the greatest phase.
+ if (shortPhaseName === 'COMPLETED')
+ return Number.MAX_SAFE_INTEGER;
+ if (shortPhaseName.length !== 6)
+ throw new Error(`Invalid short phase name: ${shortPhaseName}`);
+ const seasonOrder = {S: 0, F: 1, W: 2};
+ const stepOrder = {M: 0, R: 1, A: 2};
+ const phaseSeason = shortPhaseName[0];
+ const phaseYear = parseInt(shortPhaseName.substring(1, 5), 10);
+ const phaseStep = shortPhaseName[5];
+ if (isNaN(phaseYear))
+ throw new Error(`Unable to parse phase year from ${shortPhaseName}`);
+ if (!seasonOrder.hasOwnProperty(phaseSeason))
+ throw new Error(`Unable to parse phase season from ${shortPhaseName}`);
+ if (!stepOrder.hasOwnProperty(phaseStep))
+ throw new Error(`Unable to parse phase step from ${shortPhaseName}`);
+ return (phaseYear * 100) + (seasonOrder[phaseSeason] * 10) + stepOrder[phaseStep];
+}
+
+export class Game {
+ constructor(gameData) {
+ ////// Instead of using: `Object.assign(this, gameState)`,
+ ////// we set each field separately to let IDE know all attributes expected for Game class.
+ //// We first check gameState.
+ // These fields must not be null.
+
+ const nonNullFields = [
+ 'game_id', 'map_name', 'messages', 'role', 'rules', 'status', 'timestamp_created', 'deadline',
+ 'message_history', 'order_history', 'state_history'
+ ];
+ // These fields may be null.
+ const nullFields = ['n_controls', 'registration_password'];
+ // All fields are required.
+ for (let field of nonNullFields)
+ if (!gameData.hasOwnProperty(field) || gameData[field] == null)
+ throw new Error('Game: given state must have field `' + field + '` with non-null value.');
+ for (let field of nullFields)
+ if (!gameData.hasOwnProperty(field))
+ throw new Error('Game: given state must have field `' + field + '`.');
+
+ this.game_id = gameData.game_id;
+ this.map_name = gameData.map_name;
+ this.messages = new SortedDict(gameData instanceof Game ? null : gameData.messages, parseInt);
+
+ // {short phase name => state}
+ this.state_history = gameData instanceof Game ? gameData.state_history : new SortedDict(gameData.state_history, comparablePhase);
+ // {short phase name => {power name => [orders]}}
+ this.order_history = gameData instanceof Game ? gameData.order_history : new SortedDict(gameData.order_history, comparablePhase);
+ // {short phase name => {unit => [results]}}
+ this.result_history = gameData instanceof Game ? gameData.result_history : new SortedDict(gameData.result_history, comparablePhase);
+ // {short phase name => {message.time_sent => message}}
+ if (gameData instanceof Game) {
+ this.message_history = gameData.message_history;
+ } else {
+ this.message_history = new SortedDict(null, comparablePhase);
+ for (let entry of Object.entries(gameData.message_history)) {
+ const shortPhaseName = entry[0];
+ const phaseMessages = entry[1];
+ const sortedPhaseMessages = new SortedDict(phaseMessages, parseInt);
+ this.message_history.put(shortPhaseName, sortedPhaseMessages);
+ }
+ }
+
+ this.role = gameData.role;
+ this.rules = gameData.rules;
+ this.status = gameData.status;
+ this.timestamp_created = gameData.timestamp_created;
+ this.deadline = gameData.deadline;
+ this.n_controls = gameData.n_controls;
+ this.registration_password = gameData.registration_password;
+ this.observer_level = gameData.observer_level;
+ this.controlled_powers = gameData.controlled_powers;
+ this.result = gameData.result || null;
+
+ this.phase = gameData.phase_abbr || null; // phase abbreviation
+
+ this.powers = {};
+ if (gameData.powers) {
+ for (let entry of Object.entries(gameData.powers)) {
+ const power_name = entry[0];
+ const powerState = entry[1];
+ if (powerState instanceof Power) {
+ this.powers[power_name] = powerState.copy();
+ } else {
+ this.powers[power_name] = new Power(power_name, (this.isPlayerGame() ? power_name : this.role), this);
+ this.powers[power_name].setState(powerState);
+ }
+ }
+ } else if(this.state_history.size()) {
+ const lastState = this.state_history.lastValue();
+ if (lastState.units) {
+ for (let powerName of Object.keys(lastState.units)) {
+ this.powers[powerName] = new Power(powerName, (this.isPlayerGame() ? powerName : this.role), this);
+ }
+ }
+ }
+
+ this.note = gameData.note;
+ this.builds = null;
+
+ // {location => [possible orders]}
+ this.possibleOrders = null;
+ // {power name => [orderable locations]}
+ this.orderableLocations = null;
+ this.ordersTree = null;
+ // {loc => order type}
+ this.orderableLocToTypes = null;
+ this.client = null; // Used as pointer to a NetworkGame.
+ }
+
+ get n_players() {
+ return this.countControlledPowers();
+ }
+
+ static createOrdersTree(possibleOrders, tree, locToTypes) {
+ for (let orders of Object.values(possibleOrders)) {
+ for (let order of orders) {
+ // We ignore WAIVE order.
+ if (order === 'WAIVE')
+ continue;
+ const pieces = order.split(/ +/);
+ const thirdPiece = pieces[2];
+ const lastPiece = pieces[pieces.length - 1];
+ switch (thirdPiece) {
+ case 'H':
+ // 'H', unit
+ UTILS.javascript.extendTreeValue(tree, ['H'], `${pieces[0]} ${pieces[1]}`);
+ UTILS.javascript.extendArrayWithUniqueValues(locToTypes, pieces[1], 'H');
+ break;
+ case '-':
+ // 'M', unit, province
+ // 'V', unit, province
+ UTILS.javascript.extendTreeValue(tree, ['M', `${pieces[0]} ${pieces[1]}`, pieces[3]], (lastPiece === 'VIA' ? 'V' : 'M'));
+ UTILS.javascript.extendArrayWithUniqueValues(locToTypes, pieces[1], 'M');
+ break;
+ case 'S':
+ // 'S', supporter unit, supported unit, province
+ UTILS.javascript.extendTreeValue(tree, ['S', `${pieces[0]} ${pieces[1]}`, `${pieces[3]} ${pieces[4]}`], lastPiece);
+ UTILS.javascript.extendArrayWithUniqueValues(locToTypes, pieces[1], 'S');
+ break;
+ case 'C':
+ // 'C', convoyer unit, convoyed unit, province
+ UTILS.javascript.extendTreeValue(tree, ['C', `${pieces[0]} ${pieces[1]}`, `${pieces[3]} ${pieces[4]}`], pieces[6]);
+ UTILS.javascript.extendArrayWithUniqueValues(locToTypes, pieces[1], 'C');
+ break;
+ case 'R':
+ // 'R', unit, province
+ UTILS.javascript.extendTreeValue(tree, ['R', `${pieces[0]} ${pieces[1]}`], pieces[3]);
+ UTILS.javascript.extendArrayWithUniqueValues(locToTypes, pieces[1], 'R');
+ break;
+ case 'D':
+ // D, unit
+ UTILS.javascript.extendTreeValue(tree, ['D'], `${pieces[0]} ${pieces[1]}`);
+ UTILS.javascript.extendArrayWithUniqueValues(locToTypes, pieces[1], 'D');
+ break;
+ case 'B':
+ // B, unit
+ UTILS.javascript.extendTreeValue(tree, [pieces[0]], pieces[1]);
+ UTILS.javascript.extendArrayWithUniqueValues(locToTypes, pieces[1], pieces[0]);
+ break;
+ default:
+ throw new Error(`Unable to parse order: ${order}`);
+ }
+ }
+ }
+ }
+
+ extendPhaseHistory(phaseData) {
+ if (this.state_history.contains(phaseData.name)) throw new Error(`Phase ${phaseData.phase} already in state history.`);
+ if (this.message_history.contains(phaseData.name)) throw new Error(`Phase ${phaseData.phase} already in message history.`);
+ if (this.order_history.contains(phaseData.name)) throw new Error(`Phase ${phaseData.phase} already in order history.`);
+ if (this.result_history.contains(phaseData.name)) throw new Error(`Phase ${phaseData.phase} already in result history.`);
+ this.state_history.put(phaseData.name, phaseData.state);
+ this.order_history.put(phaseData.name, phaseData.orders);
+ this.result_history.put(phaseData.name, phaseData.results);
+ this.message_history.put(phaseData.name, new SortedDict(phaseData.messages, parseInt));
+ }
+
+ addMessage(message) {
+ message = new Message(message);
+ if (!message.time_sent)
+ throw new Error('No time sent for given message.');
+ if (this.messages.hasOwnProperty(message.time_sent))
+ throw new Error('There is already a message with time sent ' + message.time_sent + ' in message history.');
+ if (this.isPlayerGame() && !message.isGlobal() && this.role !== message.sender && this.role !== message.recipient)
+ throw new Error('Given message is not related to current player ' + this.role);
+ this.messages.put(message.time_sent, message);
+ }
+
+ assertPlayerGame(powerName) {
+ if (!this.isPlayerGame(powerName))
+ throw new Error('Expected a player game' + (powerName ? (' ' + powerName) : '') + ', got role ' + this.role + '.');
+ }
+
+ assertObserverGame() {
+ if (!this.isObserverGame())
+ throw new Error('Expected an observer game, got role ' + this.role + '.');
+ }
+
+ assertOmniscientGame() {
+ if (!this.isOmniscientGame())
+ throw new Error('Expected an omniscient game, got role ' + this.role + '.');
+ }
+
+ clearCenters(powerName) {
+ for (let power_name of Object.keys(this.powers)) {
+ if (!powerName || power_name === powerName)
+ this.powers[power_name].clearCenters();
+ }
+ }
+
+ clearOrders(powerName) {
+ for (let power_name of Object.keys(this.powers))
+ if (!powerName || power_name === powerName)
+ this.powers[power_name].clearOrders();
+ }
+
+ clearUnits(powerName) {
+ for (let power_name of Object.keys(this.powers)) {
+ if (!powerName || power_name === powerName)
+ this.powers[power_name].clearUnits();
+ }
+ }
+
+ clearVote() {
+ for (let power_name of Object.keys(this.powers))
+ this.powers[power_name].vote = 'neutral';
+ }
+
+ countControlledPowers() {
+ let count = 0;
+ for (let power of Object.values(this.powers))
+ count += power.isControlled() ? 1 : 0;
+ return count;
+ }
+
+ extendStateHistory(state) {
+ if (this.state_history.contains(state.name))
+ throw new Error('There is already a state with phase ' + state.name + ' in state history.');
+ this.state_history.put(state.name, state);
+ }
+
+ getLatestTimestamp() {
+ return Math.max(
+ this.timestamp_created,
+ (this.state_history.size() ? this.state_history.lastValue().timestamp : 0),
+ (this.messages.size() ? this.messages.lastKey() : 0)
+ );
+ }
+
+ getPower(name) {
+ return this.powers.hasOwnProperty(name) ? this.powers[name] : null;
+ }
+
+ getRelatedPower() {
+ return this.getPower(this.role);
+ }
+
+ hasPower(powerName) {
+ return this.powers.hasOwnProperty(powerName);
+ }
+
+ isPlayerGame(powerName) {
+ return (this.hasPower(this.role) && (!powerName || this.role === powerName));
+ }
+
+ isObserverGame() {
+ return this.role === STRINGS.OBSERVER_TYPE;
+ }
+
+ isOmniscientGame() {
+ return this.role === STRINGS.OMNISCIENT_TYPE;
+ }
+
+ isRealTime() {
+ return this.rules.includes('REAL_TIME');
+ }
+
+ isNoCheck() {
+ return this.rules.includes('NO_CHECK');
+ }
+
+ setPhaseData(phaseData) {
+ this.setState(phaseData.state);
+ this.clearOrders();
+ for (let entry of Object.entries(phaseData.orders)) {
+ if (entry[1])
+ this.setOrders(entry[0], entry[1]);
+ }
+ this.messages = phaseData.messages instanceof SortedDict ? phaseData.messages : new SortedDict(phaseData.messages, parseInt);
+ }
+
+ setState(state) {
+ this.result = state.result || null;
+ this.note = state.note || null;
+ this.phase = state.name;
+ if (state.units) {
+ for (let power_name of Object.keys(state.units)) {
+ if (this.powers.hasOwnProperty(power_name)) {
+ const units = state.units[power_name];
+ const power = this.powers[power_name];
+ power.retreats = {};
+ power.units = [];
+ for (let unit of units) {
+ if (unit.charAt(0) === '*')
+ power.retreats[unit.substr(1)] = {};
+ else
+ power.units.push(unit);
+ }
+ }
+ }
+ }
+ if (state.centers)
+ for (let power_name of Object.keys(state.centers))
+ if (this.powers.hasOwnProperty(power_name))
+ this.powers[power_name].centers = state.centers[power_name];
+ if (state.homes)
+ for (let power_name of Object.keys(state.homes))
+ if (this.powers.hasOwnProperty(power_name))
+ this.powers[power_name].homes = state.homes[power_name];
+ if (state.influence)
+ for (let power_name of Object.keys(state.influence))
+ if (this.powers.hasOwnProperty(power_name))
+ this.powers[power_name].influence = state.influence[power_name];
+ if (state.civil_disorder)
+ for (let power_name of Object.keys(state.civil_disorder))
+ if (this.powers.hasOwnProperty(power_name))
+ this.powers[power_name].civil_disorder = state.civil_disorder[power_name];
+ if (state.builds)
+ this.builds = state.builds;
+ }
+
+ setStatus(status) {
+ this.status = status;
+ }
+
+ setOrders(powerName, orders) {
+ if (this.powers.hasOwnProperty(powerName) && (!this.isPlayerGame() || this.isPlayerGame(powerName)))
+ this.powers[powerName].setOrders(orders);
+ }
+
+ setWait(powerName, wait) {
+ if (this.powers.hasOwnProperty(powerName)) {
+ this.powers[powerName].wait = wait;
+ }
+ }
+
+ updateDummyPowers(dummyPowers) {
+ for (let dummyPowerName of dummyPowers) if (this.powers.hasOwnProperty(dummyPowerName))
+ this.powers[dummyPowerName].setDummy();
+ }
+
+ updatePowersControllers(controllers, timestamps) {
+ for (let entry of Object.entries(controllers)) {
+ this.getPower(entry[0]).updateController(entry[1], timestamps[entry[0]]);
+ }
+ }
+
+ cloneAt(pastPhase) {
+ if (pastPhase !== null && this.state_history.contains(pastPhase)) {
+ const messages = this.message_history.get(pastPhase);
+ const orders = this.order_history.get(pastPhase);
+ const state = this.state_history.get(pastPhase);
+ const game = new Game(this);
+ game.setPhaseData({
+ name: pastPhase,
+ state: state,
+ orders: orders,
+ messages: messages
+ });
+ return game;
+ }
+ return null;
+ }
+
+ getPhaseType() {
+ if (this.phase === null || this.phase === 'FORMING' || this.phase === 'COMPLETED')
+ return null;
+ return this.phase[this.phase.length - 1];
+ }
+
+ getControllablePowers() {
+ if (!this.isObserverGame()) {
+ if (this.isOmniscientGame())
+ return Object.keys(this.powers);
+ return [this.role];
+ }
+ return [];
+ }
+
+ getMessageChannels() {
+ const messageChannels = {};
+ let messages = this.messages;
+ if (!messages.size() && this.message_history.contains(this.phase))
+ messages = this.message_history.get(this.phase);
+ if (this.isPlayerGame()) {
+ for (let message of messages.values()) {
+ let protagonist = null;
+ if (message.sender === this.role || message.recipient === 'GLOBAL')
+ protagonist = message.recipient;
+ else if (message.recipient === this.role)
+ protagonist = message.sender;
+ if (!messageChannels.hasOwnProperty(protagonist))
+ messageChannels[protagonist] = [];
+ messageChannels[protagonist].push(message);
+ }
+ } else {
+ messageChannels['messages'] = messages.values();
+ }
+ return messageChannels;
+ }
+
+ markAllMessagesRead() {
+ for (let message of this.messages.values()) {
+ if (message.sender !== this.role)
+ message.read = true;
+ }
+ }
+
+ setPossibleOrders(possibleOrders) {
+ this.possibleOrders = possibleOrders.possible_orders;
+ this.orderableLocations = possibleOrders.orderable_locations;
+ this.ordersTree = {};
+ this.orderableLocToTypes = {};
+ Game.createOrdersTree(this.possibleOrders, this.ordersTree, this.orderableLocToTypes);
+ }
+
+ getOrderTypeToLocs(powerName) {
+ const typeToLocs = {};
+ for (let loc of this.orderableLocations[powerName]) {
+ // loc may be a coastal province. In such case, we must check province coasts too.
+ const associatedLocs = [];
+ for (let possibleLoc of Object.keys(this.orderableLocToTypes)) {
+ if (possibleLoc.substring(0, 3).toUpperCase() === loc.toUpperCase()) {
+ associatedLocs.push(possibleLoc);
+ }
+ }
+ for (let associatedLoc of associatedLocs) {
+ const orderTypes = this.orderableLocToTypes[associatedLoc];
+ for (let orderType of orderTypes) {
+ if (!typeToLocs.hasOwnProperty(orderType))
+ typeToLocs[orderType] = [associatedLoc];
+ else
+ typeToLocs[orderType].push(associatedLoc);
+ }
+ }
+ }
+ return typeToLocs;
+ }
+
+ _build_sites(power) {
+ const homes = this.rules.includes('BUILD_ANY') ? power.centers : power.homes;
+ const occupiedLocations = [];
+ for (let p of Object.values(this.powers)) {
+ for (let unit of p.units) {
+ occupiedLocations.push(unit.substring(2, 5));
+ }
+ }
+ const buildSites = [];
+ for (let h of homes) {
+ if (power.centers.includes(h) && !occupiedLocations.includes(h))
+ buildSites.push(h);
+ }
+ return buildSites;
+ }
+
+ getBuildsCount(powerName) {
+ if (this.getPhaseType() !== 'A')
+ return 0;
+ const power = this.powers[powerName];
+ let buildCount = power.centers.length - power.units.length;
+ if (buildCount > 0) {
+ const buildSites = this._build_sites(power);
+ buildCount = Math.min(buildSites.length, buildCount);
+ }
+ return buildCount;
+ }
+}
diff --git a/diplomacy/web/src/diplomacy/engine/message.js b/diplomacy/web/src/diplomacy/engine/message.js
new file mode 100644
index 0000000..c91ab6f
--- /dev/null
+++ b/diplomacy/web/src/diplomacy/engine/message.js
@@ -0,0 +1,34 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+const GLOBAL = 'GLOBAL';
+
+export class Message {
+
+ constructor(message) {
+ Object.assign(this, message);
+ this.time_sent = message.time_sent;
+ this.phase = message.phase;
+ this.sender = message.sender;
+ this.recipient = message.recipient;
+ this.message = message.message;
+ }
+
+ isGlobal() {
+ return this.recipient === GLOBAL;
+ }
+
+}
diff --git a/diplomacy/web/src/diplomacy/engine/power.js b/diplomacy/web/src/diplomacy/engine/power.js
new file mode 100644
index 0000000..d13dcd4
--- /dev/null
+++ b/diplomacy/web/src/diplomacy/engine/power.js
@@ -0,0 +1,129 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+/** Class Power. **/
+import {SortedDict} from "../utils/sorted_dict";
+import {STRINGS} from "../utils/strings";
+
+export class Power {
+ constructor(name, role, game) {
+ this.game = game;
+ this.role = role;
+
+ this.name = name;
+ this.controller = new SortedDict();
+ this.vote = null;
+ this.order_is_set = 0;
+ this.wait = !this.game.isRealTime();
+ this.centers = [];
+ this.homes = [];
+ this.units = [];
+ this.retreats = {};
+ this.orders = [];
+ this.influence = [];
+ }
+
+ isControlled() {
+ if (this.controller && this.controller.size()) {
+ return this.controller.lastValue() !== STRINGS.DUMMY;
+ }
+ return false;
+ }
+
+ getController() {
+ return (this.controller && this.controller.lastValue()) || STRINGS.DUMMY;
+ }
+
+ isEliminated() {
+ return !(this.units.length || this.centers.length || Object.keys(this.retreats).length);
+ }
+
+ setState(powerState) {
+ this.name = powerState.name;
+ this.controller = new SortedDict(powerState.controller);
+ this.vote = powerState.vote;
+ this.order_is_set = powerState.order_is_set;
+ this.wait = powerState.wait;
+ this.centers = powerState.centers;
+ this.homes = powerState.homes;
+ this.units = powerState.units;
+ this.retreats = powerState.retreats;
+ this.influence = powerState.influence || [];
+ // Get orders.
+ this.orders = [];
+ if (this.game.phase.charAt(this.game.phase.length - 1) === 'M') {
+ if (this.game.isNoCheck()) {
+ for (let value of Object.values(powerState.orders)) if (value)
+ this.orders.push(value);
+ } else {
+ for (let unit of Object.keys(powerState.orders))
+ this.orders.push(unit + ' ' + powerState.orders[unit]);
+ }
+ } else {
+ for (let order of powerState.adjust)
+ if (order && order !== 'WAIVE' && !order.startsWith('VOID '))
+ this.orders.push(order);
+ }
+ }
+
+ copy() {
+ const power = new Power(this.name, this.role, this.game);
+ for (let key of this.controller.keys())
+ power.controller.put(key, this.controller.get(key));
+ power.vote = this.vote;
+ power.order_is_set = this.order_is_set;
+ power.wait = this.wait;
+ power.centers = this.centers.slice();
+ power.homes = this.homes.slice();
+ power.units = this.units.slice();
+ power.retreats = Object.assign({}, this.retreats);
+ power.influence = this.influence.slice();
+ power.orders = this.orders.slice();
+ return power;
+ }
+
+ updateController(controller, timestamp) {
+ this.controller.put(timestamp, controller);
+ }
+
+ setOrders(orders) {
+ this.orders = orders.slice();
+ this.order_is_set = this.orders.length ? 2 : 1;
+ }
+
+ setDummy() {
+ this.controller.clear();
+ }
+
+ clearCenters() {
+ this.centers = [];
+ }
+
+ clearOrders() {
+ this.orders = [];
+ this.order_is_set = 0;
+ this.wait = !this.game.isRealTime();
+ }
+
+ clearUnits() {
+ this.units = [];
+ this.influence = [];
+ }
+
+ getOrders() {
+ return this.orders.slice();
+ }
+}
diff --git a/diplomacy/web/src/diplomacy/utils/diplog.js b/diplomacy/web/src/diplomacy/utils/diplog.js
new file mode 100644
index 0000000..1e4a753
--- /dev/null
+++ b/diplomacy/web/src/diplomacy/utils/diplog.js
@@ -0,0 +1,45 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+/*eslint no-console: ["error", {allow: ["log", "info", "warn", "error"]}] */
+export class Diplog {
+ static error(msg) {
+ console.error(msg);
+ }
+
+ static warn(msg) {
+ console.warn(msg);
+ }
+
+ static info(msg) {
+ console.info(msg);
+ }
+
+ static success(msg) {
+ console.log(msg);
+ }
+
+ static printMessages(messages) {
+ if (messages) {
+ if (messages.error)
+ Diplog.error(messages.error);
+ if (messages.info)
+ Diplog.info(messages.info);
+ if (messages.success)
+ Diplog.success(messages.success);
+ }
+ }
+}
diff --git a/diplomacy/web/src/diplomacy/utils/future.js b/diplomacy/web/src/diplomacy/utils/future.js
new file mode 100644
index 0000000..c8d8add
--- /dev/null
+++ b/diplomacy/web/src/diplomacy/utils/future.js
@@ -0,0 +1,55 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+/** Class Future (like Python's Tornado future). **/
+export class Future {
+ constructor() {
+ this.__resolve_fn = null;
+ this.__reject_fn = null;
+ this.__promise = null;
+ this.__done = false;
+
+ const future = this;
+ this.__promise = new Promise((resolve, reject) => {
+ future.__resolve_fn = resolve;
+ future.__reject_fn = reject;
+ });
+ }
+
+ promise() {
+ return this.__promise;
+ }
+
+ setResult(result) {
+ if (!this.done()) {
+ this.__done = true;
+ const resolve_fn = this.__resolve_fn;
+ resolve_fn(result);
+ }
+ }
+
+ setException(exception) {
+ if (!this.done()) {
+ this.__done = true;
+ const reject_fn = this.__reject_fn;
+ reject_fn(exception);
+ }
+ }
+
+ done() {
+ return this.__done;
+ }
+}
diff --git a/diplomacy/web/src/diplomacy/utils/future_event.js b/diplomacy/web/src/diplomacy/utils/future_event.js
new file mode 100644
index 0000000..a9dfcd8
--- /dev/null
+++ b/diplomacy/web/src/diplomacy/utils/future_event.js
@@ -0,0 +1,41 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import {Future} from "./future";
+
+/** Class FutureEvent (like Python's Tornado FutureEvent). **/
+export class FutureEvent {
+ constructor() {
+ this.__future = new Future();
+ }
+
+ set(error) {
+ if (!this.__future.done())
+ if (error)
+ this.__future.setException(error);
+ else
+ this.__future.setResult(null);
+ }
+
+ clear() {
+ if (this.__future.done())
+ this.__future = new Future();
+ }
+
+ wait() {
+ return this.__future.promise();
+ }
+}
diff --git a/diplomacy/web/src/diplomacy/utils/sorted_dict.js b/diplomacy/web/src/diplomacy/utils/sorted_dict.js
new file mode 100644
index 0000000..6a27f00
--- /dev/null
+++ b/diplomacy/web/src/diplomacy/utils/sorted_dict.js
@@ -0,0 +1,109 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import {UTILS} from "./utils";
+
+function defaultComparableKey(key) {
+ return key;
+}
+
+export class SortedDict {
+ constructor(dct, keyFn) {
+ this.__real_keys = [];
+ this.__keys = [];
+ this.__values = [];
+ this.__key_fn = keyFn || defaultComparableKey;
+ if (dct) for (let key of Object.keys(dct))
+ this.put(key, dct[key]);
+ }
+
+ clear() {
+ this.__real_keys = [];
+ this.__keys = [];
+ this.__values = [];
+ }
+
+ put(key, value) {
+ const realKey = key;
+ key = this.__key_fn(key);
+ const position = UTILS.binarySearch.insert(this.__keys, key);
+ if (position === this.__values.length) {
+ this.__values.push(value);
+ this.__real_keys.push(realKey);
+ } else if (this.__values[position] !== value) {
+ this.__values.splice(position, 0, value);
+ this.__real_keys.splice(position, 0, realKey);
+ }
+ return position;
+ }
+
+ remove(key) {
+ key = this.__key_fn(key);
+ const position = UTILS.binarySearch.find(this.__keys, key);
+ if (position < 0)
+ return null;
+ this.__keys.splice(position, 1);
+ this.__real_keys.splice(position, 1);
+ return this.__values.splice(position, 1)[0];
+ }
+
+ contains(key) {
+ return UTILS.binarySearch.find(this.__keys, this.__key_fn(key)) >= 0;
+ }
+
+ get(key) {
+ const position = UTILS.binarySearch.find(this.__keys, this.__key_fn(key));
+ if (position < 0)
+ return null;
+ return this.__values[position];
+ }
+
+ indexOf(key) {
+ return UTILS.binarySearch.find(this.__keys, this.__key_fn(key));
+ }
+
+ keyFromIndex(index) {
+ return this.__real_keys[index];
+ }
+
+ valueFromIndex(index) {
+ return this.__values[index];
+ }
+
+ size() {
+ return this.__keys.length;
+ }
+
+ lastKey() {
+ if (!this.__keys.length)
+ throw new Error('Sorted dict is empty.');
+ return this.__real_keys[this.__keys.length - 1];
+ }
+
+ lastValue() {
+ if (!this.__keys.length)
+ throw new Error('Sorted dict is empty.');
+ return this.__values[this.__values.length - 1];
+ }
+
+ keys() {
+ return this.__real_keys.slice();
+ }
+
+ values() {
+ return this.__values.slice();
+ }
+}
diff --git a/diplomacy/web/src/diplomacy/utils/strings.js b/diplomacy/web/src/diplomacy/utils/strings.js
new file mode 100644
index 0000000..651e878
--- /dev/null
+++ b/diplomacy/web/src/diplomacy/utils/strings.js
@@ -0,0 +1,86 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+/** Strings. **/
+export const STRINGS = {
+ ACTIVE: 'active',
+ ADMIN: 'admin',
+ CANCELED: 'canceled',
+ CHANNEL: 'channel',
+ COMPLETED: 'completed',
+ DEMOTE: 'demote',
+ DUMMY: 'dummy',
+ ERROR: 'error',
+ GAME: 'game',
+ MASTER_TYPE: 'master_type',
+ MODERATOR: 'moderator',
+ OBSERVER: 'observer',
+ OBSERVER_TYPE: 'observer_type',
+ OK: 'ok',
+ OMNISCIENT: 'omniscient',
+ OMNISCIENT_TYPE: 'omniscient_type',
+ PAUSED: 'paused',
+ PHASE: 'phase',
+ PROMOTE: 'promote',
+ STATE: 'state',
+ STATE_HISTORY: 'state_history',
+ SYNCHRONIZE: 'synchronize',
+ ALL_GAME_STATUSES: ['forming', 'active', 'paused', 'completed', 'canceled'],
+ ALL_POWER_NAMES: ['AUSTRIA', 'ENGLAND', 'FRANCE', 'GERMANY', 'ITALY', 'RUSSIA', 'TURKEY'],
+ RULES: [
+ 'ALWAYS_WAIT',
+ 'BUILD_ANY',
+ 'CD_DUMMIES',
+ 'CIVIL_DISORDER',
+ 'DIFFERENT_ADJUDICATION',
+ 'DONT_SKIP_PHASES',
+ 'HOLD_WIN',
+ 'IGNORE_ERRORS',
+ 'MULTIPLE_POWERS_PER_PLAYER',
+ 'NO_CHECK',
+ 'NO_DEADLINE',
+ 'NO_DIAS',
+ 'NO_OBSERVATIONS',
+ 'NO_PRESS',
+ 'POWER_CHOICE',
+ 'PROPOSE_DIAS',
+ 'PUBLIC_PRESS',
+ 'REAL_TIME',
+ 'SHARED_VICTORY',
+ 'SOLITAIRE',
+ 'START_MASTER',
+ ],
+ PUBLIC_RULES: [
+ 'ALWAYS_WAIT',
+ 'BUILD_ANY',
+ 'CD_DUMMIES',
+ 'CIVIL_DISORDER',
+ 'DONT_SKIP_PHASES',
+ 'HOLD_WIN',
+ 'IGNORE_ERRORS',
+ 'MULTIPLE_POWERS_PER_PLAYER',
+ 'NO_DEADLINE',
+ 'NO_DIAS',
+ 'NO_OBSERVATIONS',
+ 'NO_PRESS',
+ 'PROPOSE_DIAS',
+ 'PUBLIC_PRESS',
+ 'REAL_TIME',
+ 'SHARED_VICTORY',
+ 'SOLITAIRE',
+ 'START_MASTER',
+ ]
+};
diff --git a/diplomacy/web/src/diplomacy/utils/utils.js b/diplomacy/web/src/diplomacy/utils/utils.js
new file mode 100644
index 0000000..f398cd2
--- /dev/null
+++ b/diplomacy/web/src/diplomacy/utils/utils.js
@@ -0,0 +1,188 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+/** Utils. **/
+
+class Dict {
+}
+
+export const UTILS = {
+ NB_CONNECTION_ATTEMPTS: 12,
+ ATTEMPT_DELAY_SECONDS: 5,
+ REQUEST_TIMEOUT_SECONDS: 30,
+
+ /** Return a random integer in interval [from, to). **/
+ randomInteger: function (from, to) {
+ return Math.floor(Math.random() * (to - from) + from);
+ },
+
+ /** Create an ID string using current time + 5 random integers each with 10 digits. **/
+ createID: function () {
+ let id = new Date().getTime().toString(10);
+ for (let i = 0; i < 5; ++i)
+ id += UTILS.randomInteger(1e9, 1e10);
+ return id;
+ },
+
+ date: function () {
+ const d = new Date();
+ return d.toLocaleString() + '.' + d.getMilliseconds();
+ },
+
+ microsecondsToDate: function (time) {
+ return new Date(Math.floor(time / 1000));
+ },
+
+ binarySearch: {
+ find: function (array, element) {
+ let a = 0;
+ let b = array.length - 1;
+ while (a <= b) {
+ const c = Math.floor((a + b) / 2);
+ if (array[c] === element)
+ return c;
+ if (array[c] < element)
+ a = c + 1;
+ else
+ b = c - 1;
+ }
+ return -1;
+ },
+ insert: function (array, element) {
+ let a = 0;
+ let b = array.length - 1;
+ while (a <= b) {
+ const c = Math.floor((a + b) / 2);
+ if (array[c] === element)
+ return c;
+ if (array[c] < element)
+ a = c + 1;
+ else
+ b = c - 1;
+ }
+ // If we go out of loop, then array[b] < element, so we must insert element at position b + 1.
+ if (b < array.length - 1)
+ array.splice(b + 1, 0, element);
+ else
+ array.push(element);
+ return b + 1;
+ }
+ },
+
+ javascript: {
+
+ arrayIsEmpty: function (array) {
+ return !(array && array.length);
+ },
+
+ hasArray: function (array) {
+ return array && array.length;
+ },
+
+ clearObject: function (obj) {
+ const keys = Object.keys(obj);
+ for (let key of keys)
+ delete obj[key];
+ },
+
+ /** Create a dictionary from given array, using array elements as dictionary values
+ * and array elements's `field` values (element[field]) as dictionary keys. **/
+ arrayToDict: function (array, field) {
+ const dictionary = {};
+ for (let entry of array)
+ dictionary[entry[field]] = entry;
+ return dictionary;
+ },
+
+ count(obj) {
+ return Object.keys(obj).length;
+ },
+
+ extendArrayWithUniqueValues(obj, key, value) {
+ if (!obj.hasOwnProperty(key))
+ obj[key] = [value];
+ else if (!obj[key].includes(value))
+ obj[key].push(value);
+ },
+
+ extendTreeValue: function (obj, path, value, allowMultipleValues) {
+ let current = obj;
+ const pathLength = path.length;
+ const parentPathLength = pathLength - 1;
+ for (let i = 0; i < parentPathLength; ++i) {
+ const stepName = path[i];
+ if (!current.hasOwnProperty(stepName))
+ current[stepName] = new Dict();
+ current = current[stepName];
+ }
+ const stepName = path[pathLength - 1];
+ if (!current.hasOwnProperty(stepName))
+ current[stepName] = [];
+ if (allowMultipleValues || !current[stepName].includes(value))
+ current[stepName].push(value);
+ },
+
+ getTreeValue: function (obj, path) {
+ let current = obj;
+ for (let stepName of path) {
+ if (!current.hasOwnProperty(stepName))
+ return null;
+ current = current[stepName];
+ }
+ if (current instanceof Dict)
+ return Object.keys(current);
+ return current;
+ }
+ },
+
+ html: {
+
+ // Source: https://www.w3schools.com/charsets/ref_utf_geometric.asp
+ UNICODE_LEFT_ARROW: '\u25C0',
+ UNICODE_RIGHT_ARROW: '\u25B6',
+ UNICODE_TOP_ARROW: '\u25BC',
+ UNICODE_BOTTOM_ARROW: '\u25B2',
+ CROSS: '\u00D7',
+ UNICODE_SMALL_RIGHT_ARROW: '\u2192',
+ UNICODE_SMALL_LEFT_ARROW: '\u2190',
+
+ isSelect: function (element) {
+ return element.tagName.toLowerCase() === 'select';
+ },
+
+ isInput: function (element) {
+ return element.tagName.toLowerCase() === 'input';
+ },
+
+ isCheckBox: function (element) {
+ return UTILS.html.isInput(element) && element.type === 'checkbox';
+ },
+
+ isRadioButton: function (element) {
+ return UTILS.html.isInput(element) && element.type === 'radio';
+ },
+
+ isTextInput: function (element) {
+ return UTILS.html.isInput(element) && element.type === 'text';
+ },
+
+ isPasswordInput: function (element) {
+ return UTILS.html.isInput(element) && element.type === 'password';
+ }
+
+ }
+
+};
diff --git a/diplomacy/web/src/gui/core/content.jsx b/diplomacy/web/src/gui/core/content.jsx
new file mode 100644
index 0000000..416ba9e
--- /dev/null
+++ b/diplomacy/web/src/gui/core/content.jsx
@@ -0,0 +1,51 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export class Content extends React.Component {
+ // PROPERTIES:
+ // page: pointer to parent Page object
+ // data: data for current content
+
+ // Each derived class must implement this static method.
+ static builder(page, data) {
+ return {
+ // page title (string)
+ title: `${data ? 'with data' : 'without data'}`,
+ // page navigation links: array of couples
+ // (navigation title, navigation callback ( onClick=() => callback() ))
+ navigation: [],
+ // page content: React component (e.g. <MyComponent/>, or <div class="content">...</div>, etc).
+ component: null
+ };
+ }
+
+ getPage() {
+ return this.props.page;
+ }
+
+ componentDidMount() {
+ window.scrollTo(0, 0);
+ }
+}
+
+
+Content.propTypes = {
+ page: PropTypes.object.isRequired,
+ data: PropTypes.object
+};
diff --git a/diplomacy/web/src/gui/core/fancybox.jsx b/diplomacy/web/src/gui/core/fancybox.jsx
new file mode 100644
index 0000000..4d1013d
--- /dev/null
+++ b/diplomacy/web/src/gui/core/fancybox.jsx
@@ -0,0 +1,59 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import React from 'react';
+import {Button} from "./widgets";
+import PropTypes from 'prop-types';
+
+const TIMES = '\u00D7';
+
+export class FancyBox extends React.Component {
+ // open-tag (<FancyBox></FancyBox>)
+ // PROPERTIES
+ // title
+ // onClose
+ render() {
+ return (
+ <div className={'fancy-wrapper'} onClick={this.props.onClose}>
+ <div className={'fancy-box container'} onClick={(event) => {
+ if (!event)
+ event = window.event;
+ if (event.hasOwnProperty('cancelBubble'))
+ event.cancelBubble = true;
+ if (event.stopPropagation)
+ event.stopPropagation();
+ }}>
+ <div className={'row fancy-bar'}>
+ <div className={'col-11 align-self-center fancy-title'}>{this.props.title}</div>
+ <div className={'col-1 fancy-button'}>
+ <Button title={TIMES} color={'danger'} onClick={this.props.onClose}/>
+ </div>
+ </div>
+ <div className={'row'}>
+ <div className={'col fancy-content'}>{this.props.children}</div>
+ </div>
+ </div>
+ </div>
+ );
+ }
+}
+
+
+FancyBox.propTypes = {
+ title: PropTypes.string.isRequired,
+ onClose: PropTypes.func.isRequired,
+ children: PropTypes.oneOfType([PropTypes.array, PropTypes.object])
+};
diff --git a/diplomacy/web/src/gui/core/forms.jsx b/diplomacy/web/src/gui/core/forms.jsx
new file mode 100644
index 0000000..76d188c
--- /dev/null
+++ b/diplomacy/web/src/gui/core/forms.jsx
@@ -0,0 +1,116 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import React from "react";
+import {Button} from "./widgets";
+import {UTILS} from "../../diplomacy/utils/utils";
+
+export class Forms {
+ static createOnChangeCallback(component, callback) {
+ return (event) => {
+ const value = UTILS.html.isCheckBox(event.target) ? event.target.checked : event.target.value;
+ const fieldName = UTILS.html.isRadioButton(event.target) ? event.target.name : event.target.id;
+ const update = {[fieldName]: value};
+ const state = Object.assign({}, component.state, update);
+ if (callback)
+ callback(state);
+ component.setState(state);
+ };
+ }
+
+ static createOnSubmitCallback(component, callback, resetState) {
+ return (event) => {
+ if (callback)
+ callback(Object.assign({}, component.state));
+ if (resetState)
+ component.setState(resetState);
+ event.preventDefault();
+ };
+ }
+
+ static createOnResetCallback(component, onChangeCallback, resetState) {
+ return (event) => {
+ if (onChangeCallback)
+ onChangeCallback(resetState);
+ component.setState(resetState);
+ if (event && event.preventDefault)
+ event.preventDefault();
+ };
+ }
+
+ static getValue(fieldValues, fieldName, defaultValue) {
+ return fieldValues.hasOwnProperty(fieldName) ? fieldValues[fieldName] : defaultValue;
+ }
+
+ static createReset(title, large, onReset) {
+ return <Button key={'reset'} title={title || 'reset'} onClick={onReset} pickEvent={true} large={large}/>;
+ }
+
+ static createSubmit(title, large, onSubmit) {
+ return <Button key={'submit'} title={title || 'submit'} onClick={onSubmit} pickEvent={true} large={large}/>;
+ }
+
+ static createButton(title, fn, color, large) {
+ const wrapFn = (event) => {
+ fn();
+ event.preventDefault();
+ };
+ return <Button large={large} key={title} color={color} title={title} onClick={wrapFn} pickEvent={true}/>;
+ }
+
+ static createCheckbox(id, title, value, onChange) {
+ const input = <input className={'form-check-input'} key={id} type={'checkbox'} id={id} checked={value}
+ onChange={onChange}/>;
+ const label = <label className={'form-check-label'} key={`label-${id}`} htmlFor={id}>{title}</label>;
+ return [input, label];
+ }
+
+ static createRadio(name, value, title, currentValue, onChange) {
+ const id = `[${name}][${value}]`;
+ const input = <input className={'form-check-input'} key={id} type={'radio'}
+ name={name} value={value} checked={currentValue === value}
+ id={id} onChange={onChange}/>;
+ const label = <label className={'form-check-label'} key={`label-${id}`} htmlFor={id}>{title || value}</label>;
+ return [input, label];
+ }
+
+ static createRow(label, input) {
+ return (
+ <div className={'form-group row'}>
+ {label}
+ <div className={'col'}>{input}</div>
+ </div>
+ );
+ }
+
+ static createLabel(htmFor, title, className) {
+ return <label className={className} htmlFor={htmFor}>{title}</label>;
+ }
+
+ static createColLabel(htmlFor, title) {
+ return Forms.createLabel(htmlFor, title, 'col');
+ }
+
+ static createSelectOptions(values, none) {
+ const options = values.slice();
+ const components = options.map((option, index) => <option key={index} value={option}>{option}</option>);
+ if (none) {
+ components.splice(0, 0, [<option key={-1} value={''}>{none === true ? '(none)' : `${none}`}</option>]);
+ }
+ return components;
+ }
+}
+
diff --git a/diplomacy/web/src/gui/core/layouts.jsx b/diplomacy/web/src/gui/core/layouts.jsx
new file mode 100644
index 0000000..78189e4
--- /dev/null
+++ b/diplomacy/web/src/gui/core/layouts.jsx
@@ -0,0 +1,55 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import React from 'react';
+import PropTypes from 'prop-types';
+
+class Div extends React.Component {
+ getClassName() {
+ return '';
+ }
+
+ render() {
+ return (
+ <div className={this.getClassName() + (this.props.className ? ' ' + this.props.className : '')}>
+ {this.props.children}
+ </div>
+ );
+ }
+}
+
+Div.propTypes = {
+ className: PropTypes.string,
+ children: PropTypes.oneOfType([PropTypes.array, PropTypes.object])
+};
+
+export class Bar extends Div {
+ getClassName() {
+ return 'bar';
+ }
+}
+
+export class Row extends Div {
+ getClassName() {
+ return 'row';
+ }
+}
+
+export class Col extends Div {
+ getClassName() {
+ return 'col';
+ }
+}
diff --git a/diplomacy/web/src/gui/core/page.jsx b/diplomacy/web/src/gui/core/page.jsx
new file mode 100644
index 0000000..5ca09fd
--- /dev/null
+++ b/diplomacy/web/src/gui/core/page.jsx
@@ -0,0 +1,434 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+/** Main class to use to create app GUI. **/
+
+import React from "react";
+import {ContentConnection} from "../diplomacy/contents/content_connection";
+import {ContentGames} from "../diplomacy/contents/content_games";
+import {ContentGame} from "../diplomacy/contents/content_game";
+import {UTILS} from "../../diplomacy/utils/utils";
+import {Diplog} from "../../diplomacy/utils/diplog";
+import {STRINGS} from "../../diplomacy/utils/strings";
+import {Game} from "../../diplomacy/engine/game";
+import Octicon, {Person} from '@githubprimer/octicons-react';
+import $ from "jquery";
+import {FancyBox} from "./fancybox";
+import {DipStorage} from "../diplomacy/utils/dipStorage";
+
+const CONTENTS = {
+ connection: ContentConnection,
+ games: ContentGames,
+ game: ContentGame
+};
+
+export class Page extends React.Component {
+
+ constructor(props) {
+ super(props);
+ this.connection = null;
+ this.channel = null;
+ this.availableMaps = null;
+ this.state = {
+ // fancybox,
+ fancyTitle: null,
+ onFancyBox: null,
+ // Page messages
+ error: null,
+ info: null,
+ success: null,
+ title: null,
+ // Page content parameters
+ contentName: 'connection',
+ contentData: null,
+ // Games.
+ games: {}, // Games found.
+ myGames: {} // Games locally stored.
+ };
+ this.loadPage = this.loadPage.bind(this);
+ this.loadConnection = this.loadConnection.bind(this);
+ this.loadGames = this.loadGames.bind(this);
+ this.loadGame = this.loadGame.bind(this);
+ this.loadGameFromDisk = this.loadGameFromDisk.bind(this);
+ this.logout = this.logout.bind(this);
+ this.error = this.error.bind(this);
+ this.info = this.info.bind(this);
+ this.success = this.success.bind(this);
+ this.unloadFancyBox = this.unloadFancyBox.bind(this);
+ }
+
+ static wrapMessage(message) {
+ return message ? `(${UTILS.date()}) ${message}` : '';
+ }
+
+ static __sort_games(games) {
+ // Sort games with not-joined games first, else compare game ID.
+ games.sort((a, b) => (((a.role ? 1 : 0) - (b.role ? 1 : 0)) || a.game_id.localeCompare(b.game_id)));
+ return games;
+ }
+
+ copyState(updatedFields) {
+ return Object.assign({}, this.state, updatedFields || {});
+ }
+
+ //// Methods to check page type.
+
+ __page_is(contentName, contentData) {
+ return this.state.contentName === contentName && (!contentData || this.state.contentData === contentData);
+ }
+
+ pageIsConnection(contentData) {
+ return this.__page_is('connection', contentData);
+ }
+
+ pageIsGames(contentData) {
+ return this.__page_is('games', contentData);
+ }
+
+ pageIsGame(contentData) {
+ return this.__page_is('game', contentData);
+ }
+
+ //// Methods to load a global fancybox.
+
+ loadFancyBox(title, callback) {
+ this.setState({fancyTitle: title, onFancyBox: callback});
+ }
+
+ unloadFancyBox() {
+ this.setState({fancyTitle: null, onFancyBox: null});
+ }
+
+ //// Methods to load a page.
+
+ loadPage(contentName, contentData, messages) {
+ messages = messages || {};
+ messages.error = Page.wrapMessage(messages.error);
+ messages.info = Page.wrapMessage(messages.info);
+ messages.success = Page.wrapMessage(messages.success);
+ Diplog.printMessages(messages);
+ this.setState(this.copyState({
+ error: messages.error,
+ info: messages.info,
+ success: messages.success,
+ contentName: contentName,
+ contentData: contentData,
+ title: null,
+ fancyTitle: null,
+ onFancyBox: null
+ }));
+ }
+
+ loadConnection(contentData, messages) {
+ this.loadPage('connection', contentData, messages);
+ }
+
+ loadGames(contentData, messages) {
+ this.loadPage('games', contentData, messages);
+ }
+
+ loadGame(gameInfo, messages) {
+ this.loadPage('game', gameInfo, messages);
+ }
+
+ loadGameFromDisk() {
+ const input = $(document.createElement('input'));
+ input.attr("type", "file");
+ input.trigger('click');
+ input.change(event => {
+ const file = event.target.files[0];
+ if (!file.name.match(/\.json$/i)) {
+ this.error(`Invalid JSON filename ${file.name}`);
+ } else {
+ const reader = new FileReader();
+ reader.onload = () => {
+ const savedData = JSON.parse(reader.result);
+ const gameObject = {};
+ gameObject.game_id = `(local) ${savedData.id}`;
+ gameObject.map_name = savedData.map;
+ gameObject.rules = savedData.rules;
+ const state_history = {};
+ const message_history = {};
+ const order_history = {};
+ const result_history = {};
+ for (let savedPhase of savedData.phases) {
+ const gameState = savedPhase.state;
+ const phaseOrders = savedPhase.orders || {};
+ const phaseResults = savedPhase.results || {};
+ const phaseMessages = {};
+ if (savedPhase.messages) {
+ for (let message of savedPhase.messages) {
+ phaseMessages[message.time_sent] = message;
+ }
+ }
+ if (!gameState.name)
+ gameState.name = savedPhase.name;
+ state_history[gameState.name] = gameState;
+ order_history[gameState.name] = phaseOrders;
+ message_history[gameState.name] = phaseMessages;
+ result_history[gameState.name] = phaseResults;
+ }
+ gameObject.state_history = state_history;
+ gameObject.message_history = message_history;
+ gameObject.order_history = order_history;
+ gameObject.state_history = state_history;
+ gameObject.result_history = result_history;
+ gameObject.messages = [];
+ gameObject.role = STRINGS.OBSERVER_TYPE;
+ gameObject.status = STRINGS.COMPLETED;
+ gameObject.timestamp_created = 0;
+ gameObject.deadline = 0;
+ gameObject.n_controls = 0;
+ gameObject.registration_password = '';
+ const game = new Game(gameObject);
+ this.loadGame(game);
+ };
+ reader.readAsText(file);
+ }
+ });
+ }
+
+ //// Methods to sign out channel and go back to connection page.
+
+ __disconnect() {
+ // Clear local data and go back to connection page.
+ this.connection.close();
+ this.connection = null;
+ this.channel = null;
+ this.availableMaps = null;
+ const message = Page.wrapMessage(`Disconnected from channel and server.`);
+ Diplog.success(message);
+ this.setState(this.copyState({
+ error: null,
+ info: null,
+ success: message,
+ contentName: 'connection',
+ contentData: null,
+ // When disconnected, remove all games previously loaded.
+ games: {},
+ myGames: {}
+ }));
+ }
+
+ logout() {
+ // Disconnect channel and go back to connection page.
+ if (this.channel) {
+ this.channel.logout()
+ .then(() => this.__disconnect())
+ .catch(error => this.error(`Error while disconnecting: ${error.toString()}.`));
+ } else {
+ this.__disconnect();
+ }
+ }
+
+ //// Methods to be used to set page title and messages.
+
+ setTitle(title) {
+ this.setState({title: title});
+ }
+
+ error(message) {
+ message = Page.wrapMessage(message);
+ Diplog.error(message);
+ this.setState({error: message});
+ }
+
+ info(message) {
+ message = Page.wrapMessage(message);
+ Diplog.info(message);
+ this.setState({info: message});
+ }
+
+ success(message) {
+ message = Page.wrapMessage(message);
+ Diplog.success(message);
+ this.setState({success: message});
+ }
+
+ warn(message) {
+ this.info(message);
+ }
+
+ //// Methods to manage games.
+
+ updateMyGames(gamesToAdd) {
+ // Update state myGames with given games. This method does not update local storage.
+ const myGames = Object.assign({}, this.state.myGames);
+ let gamesFound = null;
+ for (let gameToAdd of gamesToAdd) {
+ myGames[gameToAdd.game_id] = gameToAdd;
+ if (this.state.games.hasOwnProperty(gameToAdd.game_id)) {
+ if (!gamesFound)
+ gamesFound = Object.assign({}, this.state.games);
+ gamesFound[gameToAdd.game_id] = gameToAdd;
+ }
+ }
+ if (!gamesFound)
+ gamesFound = this.state.games;
+ this.setState({myGames: myGames, games: gamesFound});
+ }
+
+ getMyGames() {
+ return Page.__sort_games(Object.values(this.state.myGames));
+ }
+
+ getGamesFound() {
+ return Page.__sort_games(Object.values(this.state.games));
+ }
+
+ addGamesFound(gamesToAdd) {
+ const gamesFound = {};
+ for (let game of gamesToAdd) {
+ gamesFound[game.game_id] = (
+ this.state.myGames.hasOwnProperty(game.game_id) ?
+ this.state.myGames[game.game_id] : game
+ );
+ }
+ this.setState({games: gamesFound});
+ }
+
+ leaveGame(gameID) {
+ if (this.state.myGames.hasOwnProperty(gameID)) {
+ const game = this.state.myGames[gameID];
+ if (game.client) {
+ game.client.leave()
+ .then(() => {
+ this.disconnectGame(gameID);
+ this.loadGames(null, {info: `Game ${gameID} left.`});
+ })
+ .catch(error => this.error(`Error when leaving game ${gameID}: ${error.toString()}`));
+ }
+ }
+ }
+
+ disconnectGame(gameID) {
+ if (this.state.myGames.hasOwnProperty(gameID)) {
+ const game = this.state.myGames[gameID];
+ if (game.client)
+ game.client.clearAllCallbacks();
+ this.channel.getGamesInfo({games: [gameID]})
+ .then(gamesInfo => {
+ this.updateMyGames(gamesInfo);
+ })
+ .catch(error => this.error(`Error while leaving game ${gameID}: ${error.toString()}`));
+ }
+ }
+
+ addToMyGames(game) {
+ // Update state myGames with given game **and** update local storage.
+ const myGames = Object.assign({}, this.state.myGames);
+ const gamesFound = this.state.games.hasOwnProperty(game.game_id) ? Object.assign({}, this.state.games) : this.state.games;
+ myGames[game.game_id] = game;
+ if (gamesFound.hasOwnProperty(game.game_id))
+ gamesFound[game.game_id] = game;
+ DipStorage.addUserGame(this.channel.username, game.game_id);
+ this.setState({myGames: myGames, games: gamesFound});
+ }
+
+ removeFromMyGames(gameID) {
+ if (this.state.myGames.hasOwnProperty(gameID)) {
+ const games = Object.assign({}, this.state.myGames);
+ delete games[gameID];
+ DipStorage.removeUserGame(this.channel.username, gameID);
+ this.setState({myGames: games});
+ }
+ }
+
+ hasMyGame(gameID) {
+ return this.state.myGames.hasOwnProperty(gameID);
+ }
+
+ //// Render method.
+
+ render() {
+ const content = CONTENTS[this.state.contentName].builder(this, this.state.contentData);
+ const hasNavigation = UTILS.javascript.hasArray(content.navigation);
+
+ // NB: I currently don't find a better way to update document title from content details.
+ const successMessage = this.state.success || '-';
+ const infoMessage = this.state.info || '-';
+ const errorMessage = this.state.error || '-';
+ const title = this.state.title || content.title;
+ document.title = title + ' | Diplomacy';
+
+ return (
+ <div className="page container-fluid" id={this.state.contentName}>
+ <div className={'top-msg row'}>
+ <div title={successMessage !== '-' ? successMessage : ''}
+ className={'col-sm-4 msg success ' + (this.state.success ? 'with-msg' : 'no-msg')}
+ onClick={() => this.success()}>
+ {successMessage}
+ </div>
+ <div title={infoMessage !== '-' ? infoMessage : ''}
+ className={'col-sm-4 msg info ' + (this.state.info ? 'with-msg' : 'no-msg')}
+ onClick={() => this.info()}>
+ {infoMessage}
+ </div>
+ <div title={errorMessage !== '-' ? errorMessage : ''}
+ className={'col-sm-4 msg error ' + (this.state.error ? 'with-msg' : 'no-msg')}
+ onClick={() => this.error()}>
+ {errorMessage}
+ </div>
+ </div>
+ {((hasNavigation || this.channel) && (
+ <div className={'title row'}>
+ <div className={'col align-self-center'}><strong>{title}</strong></div>
+ <div className={'col-sm-1'}>
+ {(!hasNavigation && (
+ <div className={'float-right'}>
+ <strong>
+ <u className={'mr-2'}>{this.channel.username}</u>
+ <Octicon icon={Person}/>
+ </strong>
+ </div>
+ )) || (
+ <div className="dropdown float-right">
+ <button className="btn btn-secondary dropdown-toggle" type="button"
+ id="dropdownMenuButton" data-toggle="dropdown"
+ aria-haspopup="true" aria-expanded="false">
+ {(this.channel && this.channel.username && (
+ <span>
+ <u className={'mr-2'}>{this.channel.username}</u>
+ <Octicon icon={Person}/>
+ </span>
+ )) || 'Menu'}
+ </button>
+ <div className="dropdown-menu dropdown-menu-right"
+ aria-labelledby="dropdownMenuButton">
+ {content.navigation.map((nav, index) => {
+ const navTitle = nav[0];
+ const navAction = nav[1];
+ return <a key={index} className="dropdown-item"
+ onClick={navAction}>{navTitle}</a>;
+ })}
+ </div>
+ </div>
+ )}
+ </div>
+ </div>
+ )) || (
+ <div className={'title'}><strong>{title}</strong></div>
+ )}
+ {content.component}
+ {this.state.onFancyBox && (
+ <FancyBox title={this.state.fancyTitle} onClose={this.unloadFancyBox}>
+ {this.state.onFancyBox()}
+ </FancyBox>
+ )}
+ </div>
+ );
+ }
+}
diff --git a/diplomacy/web/src/gui/core/table.jsx b/diplomacy/web/src/gui/core/table.jsx
new file mode 100644
index 0000000..cb729e7
--- /dev/null
+++ b/diplomacy/web/src/gui/core/table.jsx
@@ -0,0 +1,112 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+//// Tables.
+
+import React from "react";
+import PropTypes from 'prop-types';
+
+class DefaultWrapper {
+ constructor(data) {
+ this.data = data;
+ this.get = this.get.bind(this);
+ }
+
+ get(fieldName) {
+ return this.data[fieldName];
+ }
+}
+
+function defaultWrapper(data) {
+ return new DefaultWrapper(data);
+}
+
+export class Table extends React.Component {
+ // className
+ // caption
+ // columns : {name: [title, order]}
+ // data: [objects with expected column names]
+ // wrapper: (optional) function to use to wrap one data entry into an object before accessing fields.
+ // Must return an instance with a method get(name).
+ // If provided: wrapper(data_entry).get(field_name)
+ // else: data_entry[field_name]
+
+ constructor(props) {
+ super(props);
+ if (!this.props.wrapper)
+ this.props.wrapper = defaultWrapper;
+ }
+
+ static getHeader(columns) {
+ const header = [];
+ for (let entry of Object.entries(columns)) {
+ const name = entry[0];
+ const title = entry[1][0];
+ const order = entry[1][1];
+ header.push([order, name, title]);
+ }
+ header.sort((a, b) => {
+ let t = a[0] - b[0];
+ if (t === 0)
+ t = a[1].localeCompare(b[1]);
+ if (t === 0)
+ t = a[2].localeCompare(b[2]);
+ return t;
+ });
+ return header;
+ }
+
+ static getHeaderLine(header) {
+ return (
+ <thead className={'thead-light'}>
+ <tr>{header.map((column, colIndex) => <th key={colIndex}>{column[2]}</th>)}</tr>
+ </thead>
+ );
+ }
+
+ static getBodyRow(header, row, rowIndex, wrapper) {
+ const wrapped = wrapper(row);
+ return (<tr key={rowIndex}>
+ {header.map((headerColumn, colIndex) => <td className={'align-middle'}
+ key={colIndex}>{wrapped.get(headerColumn[1])}</td>)}
+ </tr>);
+ }
+
+ static getBodyLines(header, data, wrapper) {
+ return (<tbody>{data.map((row, rowIndex) => Table.getBodyRow(header, row, rowIndex, wrapper))}</tbody>);
+ }
+
+ render() {
+ const header = Table.getHeader(this.props.columns);
+ return (
+ <div className={'table-responsive'}>
+ <table className={this.props.className}>
+ <caption>{this.props.caption} ({this.props.data.length})</caption>
+ {Table.getHeaderLine(header)}
+ {Table.getBodyLines(header, this.props.data, this.props.wrapper)}
+ </table>
+ </div>
+ );
+ }
+}
+
+Table.propTypes = {
+ wrapper: PropTypes.func,
+ columns: PropTypes.object,
+ className: PropTypes.string,
+ caption: PropTypes.string,
+ data: PropTypes.array
+};
diff --git a/diplomacy/web/src/gui/core/tabs.jsx b/diplomacy/web/src/gui/core/tabs.jsx
new file mode 100644
index 0000000..6123219
--- /dev/null
+++ b/diplomacy/web/src/gui/core/tabs.jsx
@@ -0,0 +1,96 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import React from "react";
+import {Action} from "./widgets";
+import PropTypes from 'prop-types';
+
+export class Tab extends React.Component {
+ render() {
+ const style = {
+ display: this.props.display ? 'block' : 'none'
+ };
+ const id = this.props.id ? {id: this.props.id} : {};
+ return (
+ <div className={'tab mb-4 ' + this.props.className} style={style} {...id}>
+ {this.props.children}
+ </div>
+ );
+ }
+}
+
+Tab.propTypes = {
+ display: PropTypes.bool,
+ className: PropTypes.string,
+ id: PropTypes.string,
+ children: PropTypes.oneOfType([PropTypes.array, PropTypes.object])
+};
+
+Tab.defaultProps = {
+ display: false,
+ className: '',
+ id: ''
+};
+
+export class Tabs extends React.Component {
+ /** PROPERTIES
+ * active: index of active menu (must be > menu.length).
+ * highlights: dictionary mapping a menu indice to a highlight message
+ * onChange: callback(index): receive index of menu to display.
+ * **/
+
+ generateTabAction(tabTitle, tabId, isActive, onChange, highlight) {
+ return <Action isActive={isActive}
+ title={tabTitle}
+ onClick={() => onChange(tabId)}
+ highlight={highlight}
+ key={tabId}/>;
+ }
+
+ render() {
+ if (!this.props.menu.length)
+ throw new Error(`No tab menu given.`);
+ if (this.props.menu.length !== this.props.titles.length)
+ throw new Error(`Menu length (${this.props.menu.length}) != titles length (${this.props.titles.length})`);
+ if (this.props.active && !this.props.menu.includes(this.props.active))
+ throw new Error(`Invalid active tab name, got ${this.props.active}, expected one of: ${this.props.menu.join(', ')}`);
+ const active = this.props.active || this.props.menu[0];
+ return (
+ <div className={'tabs mb-3'}>
+ <nav className={'tabs-bar nav nav-tabs justify-content-center mb-3'}>
+ {this.props.menu.map((tabName, index) => this.generateTabAction(
+ this.props.titles[index], tabName, active === tabName, this.props.onChange,
+ (this.props.highlights.hasOwnProperty(tabName) && this.props.highlights[tabName]) || null
+ ))}
+ </nav>
+ {this.props.children}
+ </div>
+ );
+ }
+}
+
+Tabs.propTypes = {
+ menu: PropTypes.arrayOf(PropTypes.string).isRequired, // tab names
+ titles: PropTypes.arrayOf(PropTypes.string).isRequired, // tab titles
+ onChange: PropTypes.func.isRequired, // callback(tab name)
+ children: PropTypes.array.isRequired,
+ active: PropTypes.string, // current active tab name
+ highlights: PropTypes.object, // {tab name => highligh message (optional)}
+};
+
+Tabs.defaultProps = {
+ highlights: {}
+};
diff --git a/diplomacy/web/src/gui/core/widgets.jsx b/diplomacy/web/src/gui/core/widgets.jsx
new file mode 100644
index 0000000..62a5eb4
--- /dev/null
+++ b/diplomacy/web/src/gui/core/widgets.jsx
@@ -0,0 +1,102 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import React from "react";
+import PropTypes from 'prop-types';
+
+export class Button extends React.Component {
+ /** Bootstrap button.
+ * Bootstrap classes:
+ * - btn
+ * - btn-primary
+ * - mx-1 (margin-left 1px, margin-right 1px)
+ * Props: title (str), onClick (function).
+ * **/
+ // title
+ // onClick
+ // pickEvent = false
+ // large = false
+ // small = false
+
+ constructor(props) {
+ super(props);
+ this.onClick = this.onClick.bind(this);
+ }
+
+ onClick(event) {
+ if (this.props.onClick)
+ this.props.onClick(this.props.pickEvent ? event : null);
+ }
+
+ render() {
+ return (
+ <button
+ className={`btn btn-${this.props.color || 'secondary'}` + (this.props.large ? ' btn-block' : '') + (this.props.small ? ' btn-sm' : '')}
+ disabled={this.props.disabled}
+ onClick={this.onClick}>
+ <strong>{this.props.title}</strong>
+ </button>
+ );
+ }
+}
+
+Button.propTypes = {
+ title: PropTypes.string.isRequired,
+ onClick: PropTypes.func.isRequired,
+ color: PropTypes.string,
+ large: PropTypes.bool,
+ small: PropTypes.bool,
+ pickEvent: PropTypes.bool,
+ disabled: PropTypes.bool
+};
+
+Button.defaultPropTypes = {
+ disabled: false
+};
+
+
+export class Action extends React.Component {
+ // title
+ // isActive
+ // onClick
+ // See Button parameters.
+
+ render() {
+ return (
+ <div className="action nav-item" onClick={this.props.onClick}>
+ <div
+ className={'nav-link' + (this.props.isActive ? ' active' : '') + (this.props.highlight !== null ? ' updated' : '')}>
+ {this.props.title}
+ {this.props.highlight !== null
+ && this.props.highlight !== undefined
+ && <span className={'update'}>{this.props.highlight}</span>}
+ </div>
+ </div>
+ );
+ }
+}
+
+Action.propTypes = {
+ title: PropTypes.string.isRequired,
+ onClick: PropTypes.func.isRequired,
+ highlight: PropTypes.any,
+ isActive: PropTypes.bool
+};
+
+Action.defaultProps = {
+ highlight: null,
+ isActive: false
+};
diff --git a/diplomacy/web/src/gui/diplomacy/contents/content_connection.jsx b/diplomacy/web/src/gui/diplomacy/contents/content_connection.jsx
new file mode 100644
index 0000000..8aa7fb1
--- /dev/null
+++ b/diplomacy/web/src/gui/diplomacy/contents/content_connection.jsx
@@ -0,0 +1,91 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import React from 'react';
+import {Content} from "../../core/content";
+import {Connection} from "../../../diplomacy/client/connection";
+import {ConnectionForm} from "../forms/connection_form";
+import {DipStorage} from "../utils/dipStorage";
+
+export class ContentConnection extends Content {
+ constructor(props) {
+ super(props);
+ this.connection = null;
+ this.onSubmit = this.onSubmit.bind(this);
+ }
+
+ static builder(page, data) {
+ return {
+ title: 'Connection',
+ navigation: [],
+ component: <ContentConnection page={page} data={data}/>
+ };
+ }
+
+ onSubmit(data) {
+ const page = this.getPage();
+ for (let fieldName of ['hostname', 'port', 'username', 'password', 'showServerFields'])
+ if (!data.hasOwnProperty(fieldName))
+ return page.error(`Missing ${fieldName}, got ${JSON.stringify(data)}`);
+ page.info('Connecting ...');
+ if (this.connection) {
+ this.connection.currentConnectionProcessing.stop();
+ }
+ this.connection = new Connection(data.hostname, data.port, window.location.protocol.toLowerCase() === 'https:');
+ // Page is passed as logger object (with methods info(), error(), success()) when connecting.
+ this.connection.connect(this.getPage())
+ .then(() => {
+ page.connection = this.connection;
+ this.connection = null;
+ page.success(`Successfully connected to server ${data.username}:${data.port}`);
+ page.connection.authenticate(data.username, data.password, false)
+ .catch((error) => {
+ page.error(`Unable to sign in, trying to create an account, error: ${error}`);
+ return page.connection.authenticate(data.username, data.password, true);
+ })
+ .then((channel) => {
+ page.channel = channel;
+ return channel.getAvailableMaps();
+ })
+ .then(availableMaps => {
+ page.availableMaps = availableMaps;
+ const userGameIndices = DipStorage.getUserGames(page.channel.username);
+ if (userGameIndices && userGameIndices.length) {
+ return page.channel.getGamesInfo({games: userGameIndices});
+ } else {
+ return null;
+ }
+ })
+ .then((gamesInfo) => {
+ if (gamesInfo) {
+ this.getPage().success('Found ' + gamesInfo.length + ' user games.');
+ this.getPage().updateMyGames(gamesInfo);
+ }
+ page.loadGames(null, {success: `Account ${data.username} connected.`});
+ })
+ .catch((error) => {
+ page.error('Error while authenticating: ' + error + ' Please re-try.');
+ });
+ })
+ .catch((error) => {
+ page.error('Error while connecting: ' + error + ' Please re-try.');
+ });
+ }
+
+ render() {
+ return <main><ConnectionForm onSubmit={this.onSubmit}/></main>;
+ }
+}
diff --git a/diplomacy/web/src/gui/diplomacy/contents/content_game.jsx b/diplomacy/web/src/gui/diplomacy/contents/content_game.jsx
new file mode 100644
index 0000000..81a689d
--- /dev/null
+++ b/diplomacy/web/src/gui/diplomacy/contents/content_game.jsx
@@ -0,0 +1,1235 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import React from "react";
+import Scrollchor from 'react-scrollchor';
+import {SelectLocationForm} from "../forms/select_location_form";
+import {SelectViaForm} from "../forms/select_via_form";
+import {Order} from "../utils/order";
+import {Button} from "../../core/widgets";
+import {Bar, Row} from "../../core/layouts";
+import {Content} from "../../core/content";
+import {Tab, Tabs} from "../../core/tabs";
+import {Map} from "../map/map";
+import {extendOrderBuilding, ORDER_BUILDER, POSSIBLE_ORDERS} from "../utils/order_building";
+import {PowerActionsForm} from "../forms/power_actions_form";
+import {MessageForm} from "../forms/message_form";
+import {UTILS} from "../../../diplomacy/utils/utils";
+import {Message} from "../../../diplomacy/engine/message";
+import {PowerOrder} from "../widgets/power_order";
+import {MessageView} from "../widgets/message_view";
+import {STRINGS} from "../../../diplomacy/utils/strings";
+import {Diplog} from "../../../diplomacy/utils/diplog";
+import {Table} from "../../core/table";
+import {PowerView} from "../utils/power_view";
+import {FancyBox} from "../../core/fancybox";
+import {DipStorage} from "../utils/dipStorage";
+
+const HotKey = require('react-shortcut');
+
+/* Order management in game page.
+ * When editing orders locally, we have to compare it to server orders
+ * to determine when we need to update orders on server side. There are
+ * 9 comparison cases, depending on orders:
+ * SERVER LOCAL DECISION
+ * null null 0 (same)
+ * null {} 1 (different, user wants to send "no orders" on server)
+ * null {orders} 1 (different, user defines new orders locally)
+ * {} null 0 (assumed same: user is not allowed to "delete" a "no orders": he can only add new orders)
+ * {} {} 0 (same)
+ * {} {orders} 1 (different, user defines new orders locally and wants to overwrite the "no-orders" on server)
+ * {orders} null 1 (different, user wants to delete all server orders, will result to "no-orders")
+ * {orders} {} 1 (different, user wants to delete all server orders, will result to "no-orders")
+ * {orders} {orders} same if we have exactly same orders on both server and local
+ * */
+
+const TABLE_POWER_VIEW = {
+ name: ['Power', 0],
+ controller: ['Controller', 1],
+ order_is_set: ['With orders', 2],
+ wait: ['Waiting', 3]
+};
+
+function Help() {
+ return (
+ <div>
+ <p>When building an order, press <strong>ESC</strong> to reset build.</p>
+ <p>Press letter associated to an order type to start building an order of this type.
+ <br/> Order type letter is indicated in order type name after order type radio button.
+ </p>
+ <p>In Phase History tab, use keyboard left and right arrows to navigate in past phases.</p>
+ </div>
+ );
+}
+
+export class ContentGame extends Content {
+
+ constructor(props) {
+ super(props);
+ // Load local orders from local storage (if available).
+ const savedOrders = this.props.data.client ? DipStorage.getUserGameOrders(
+ this.props.data.client.channel.username,
+ this.props.data.game_id,
+ this.props.data.phase
+ ) : null;
+ let orders = null;
+ if (savedOrders) {
+ orders = {};
+ for (let entry of Object.entries(savedOrders)) {
+ let powerOrders = null;
+ const powerName = entry[0];
+ if (entry[1]) {
+ powerOrders = {};
+ for (let orderString of entry[1]) {
+ const order = new Order(orderString, true);
+ powerOrders[order.loc] = order;
+ }
+ }
+ orders[powerName] = powerOrders;
+ }
+ }
+ this.schedule_timeout_id = null;
+ this.state = {
+ tabMain: null,
+ tabPastMessages: null,
+ tabCurrentMessages: null,
+ messageHighlights: {},
+ historyPhaseIndex: null,
+ historyShowOrders: true,
+ historySubView: 0,
+ historyCurrentLoc: null,
+ historyCurrentOrders: null,
+ wait: null, // {power name => bool}
+ orders: orders, // {power name => {loc => {local: bool, order: str}}}
+ power: null,
+ orderBuildingType: null,
+ orderBuildingPath: [],
+ fancy_title: null,
+ fancy_function: null,
+ on_fancy_close: null,
+ };
+
+ // Bind some class methods to this instance.
+ this.closeFancyBox = this.closeFancyBox.bind(this);
+ this.displayFirstPastPhase = this.displayFirstPastPhase.bind(this);
+ this.displayLastPastPhase = this.displayLastPastPhase.bind(this);
+ this.displayLocationOrders = this.displayLocationOrders.bind(this);
+ this.getMapInfo = this.getMapInfo.bind(this);
+ this.notifiedGamePhaseUpdated = this.notifiedGamePhaseUpdated.bind(this);
+ this.notifiedLocalStateChange = this.notifiedLocalStateChange.bind(this);
+ this.notifiedNetworkGame = this.notifiedNetworkGame.bind(this);
+ this.notifiedNewGameMessage = this.notifiedNewGameMessage.bind(this);
+ this.notifiedPowersControllers = this.notifiedPowersControllers.bind(this);
+ this.onChangeCurrentPower = this.onChangeCurrentPower.bind(this);
+ this.onChangeMainTab = this.onChangeMainTab.bind(this);
+ this.onChangeOrderType = this.onChangeOrderType.bind(this);
+ this.onChangePastPhase = this.onChangePastPhase.bind(this);
+ this.onChangePastPhaseIndex = this.onChangePastPhaseIndex.bind(this);
+ this.onChangeShowPastOrders = this.onChangeShowPastOrders.bind(this);
+ this.onChangeTabCurrentMessages = this.onChangeTabCurrentMessages.bind(this);
+ this.onChangeTabPastMessages = this.onChangeTabPastMessages.bind(this);
+ this.onClickMessage = this.onClickMessage.bind(this);
+ this.onDecrementPastPhase = this.onDecrementPastPhase.bind(this);
+ this.onIncrementPastPhase = this.onIncrementPastPhase.bind(this);
+ this.onOrderBuilding = this.onOrderBuilding.bind(this);
+ this.onOrderBuilt = this.onOrderBuilt.bind(this);
+ this.onProcessGame = this.onProcessGame.bind(this);
+ this.onRemoveAllOrders = this.onRemoveAllOrders.bind(this);
+ this.onRemoveOrder = this.onRemoveOrder.bind(this);
+ this.onSelectLocation = this.onSelectLocation.bind(this);
+ this.onSelectVia = this.onSelectVia.bind(this);
+ this.onSetNoOrders = this.onSetNoOrders.bind(this);
+ this.reloadServerOrders = this.reloadServerOrders.bind(this);
+ this.renderOrders = this.renderOrders.bind(this);
+ this.sendMessage = this.sendMessage.bind(this);
+ this.setOrders = this.setOrders.bind(this);
+ this.setSelectedLocation = this.setSelectedLocation.bind(this);
+ this.setSelectedVia = this.setSelectedVia.bind(this);
+ this.setWaitFlag = this.setWaitFlag.bind(this);
+ this.vote = this.vote.bind(this);
+ }
+
+ static gameTitle(game) {
+ let title = `${game.game_id} | ${game.phase} | ${game.status} | ${game.role} | ${game.map_name}`;
+ const remainingTime = game.deadline_timer;
+ if (remainingTime === undefined)
+ title += ` (deadline: ${game.deadline} sec)`;
+ else if (remainingTime)
+ title += ` (remaining ${remainingTime} sec)`;
+ return title;
+ }
+
+ static saveGameToDisk(game, page) {
+ if (game.client) {
+ game.client.save()
+ .then((savedData) => {
+ const domLink = document.createElement('a');
+ domLink.setAttribute(
+ 'href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(JSON.stringify(savedData)));
+ domLink.setAttribute('download', `${game.game_id}.json`);
+ domLink.style.display = 'none';
+ document.body.appendChild(domLink);
+ domLink.click();
+ document.body.removeChild(domLink);
+ })
+ .catch(exc => page.error(`Error while saving game: ${exc.toString()}`));
+ } else {
+ page.error(`Cannot save this game.`);
+ }
+ }
+
+ static builder(page, data) {
+ return {
+ title: ContentGame.gameTitle(data),
+ navigation: [
+ ['Help', () => page.loadFancyBox('Help', () => <Help/>)],
+ ['Load a game from disk', page.loadGameFromDisk],
+ ['Save game to disk', () => ContentGame.saveGameToDisk(data)],
+ [`${UTILS.html.UNICODE_SMALL_LEFT_ARROW} Games`, page.loadGames],
+ [`${UTILS.html.UNICODE_SMALL_LEFT_ARROW} Leave game`, () => page.leaveGame(data.game_id)],
+ [`${UTILS.html.UNICODE_SMALL_LEFT_ARROW} Logout`, page.logout]
+ ],
+ component: <ContentGame page={page} data={data}/>
+ };
+ }
+
+ static getServerWaitFlags(engine) {
+ const wait = {};
+ const controllablePowers = engine.getControllablePowers();
+ for (let powerName of controllablePowers) {
+ wait[powerName] = engine.powers[powerName].wait;
+ }
+ return wait;
+ }
+
+ static getServerOrders(engine) {
+ const orders = {};
+ const controllablePowers = engine.getControllablePowers();
+ for (let powerName of controllablePowers) {
+ const powerOrders = {};
+ let countOrders = 0;
+ const power = engine.powers[powerName];
+ for (let orderString of power.orders) {
+ const serverOrder = new Order(orderString, false);
+ powerOrders[serverOrder.loc] = serverOrder;
+ ++countOrders;
+ }
+ orders[powerName] = (countOrders || power.order_is_set) ? powerOrders : null;
+ }
+ return orders;
+ }
+
+ static getOrderBuilding(powerName, orderType, orderPath) {
+ return {
+ type: orderType,
+ path: orderPath,
+ power: powerName,
+ builder: orderType && ORDER_BUILDER[orderType]
+ };
+ }
+
+ closeFancyBox() {
+ this.setState({
+ fancy_title: null,
+ fancy_function: null,
+ on_fancy_close: null,
+ orderBuildingPath: []
+ });
+ }
+
+ setSelectedLocation(location, powerName, orderType, orderPath) {
+ if (!location)
+ return;
+ extendOrderBuilding(
+ powerName, orderType, orderPath, location,
+ this.onOrderBuilding, this.onOrderBuilt, this.getPage().error
+ );
+ this.setState({
+ fancy_title: null,
+ fancy_function: null,
+ on_fancy_close: null
+ });
+ }
+
+ setSelectedVia(moveType, powerName, orderPath, location) {
+ if (!moveType || !['M', 'V'].includes(moveType))
+ return;
+ extendOrderBuilding(
+ powerName, moveType, orderPath, location,
+ this.onOrderBuilding, this.onOrderBuilt, this.getPage().error
+ );
+ this.setState({
+ fancy_title: null,
+ fancy_function: null,
+ on_fancy_close: null
+ });
+ }
+
+ onSelectLocation(possibleLocations, powerName, orderType, orderPath) {
+ const title = `Select location to continue building order: ${orderPath.join(' ')} ... (press ESC or close button to cancel building)`;
+ const func = () => (<SelectLocationForm locations={possibleLocations}
+ onSelect={(location) => this.setSelectedLocation(location, powerName, orderType, orderPath)}/>);
+ this.setState({
+ fancy_title: title,
+ fancy_function: func,
+ on_fancy_close: this.closeFancyBox
+ });
+ }
+
+ onSelectVia(location, powerName, orderPath) {
+ const title = `Select move type for move order: ${orderPath.join(' ')}`;
+ const func = () => (
+ <SelectViaForm onSelect={(moveType) => this.setSelectedVia(moveType, powerName, orderPath, location)}/>);
+ this.setState({
+ fancy_title: title,
+ fancy_function: func,
+ on_fancy_close: this.closeFancyBox
+ });
+ }
+
+ __get_orders(engine) {
+ const orders = ContentGame.getServerOrders(engine);
+ if (this.state.orders) {
+ for (let powerName of Object.keys(orders)) {
+ const serverPowerOrders = orders[powerName];
+ const localPowerOrders = this.state.orders[powerName];
+ if (localPowerOrders) {
+ for (let localOrder of Object.values(localPowerOrders)) {
+ localOrder.local = (
+ !serverPowerOrders
+ || !serverPowerOrders.hasOwnProperty(localOrder.loc)
+ || serverPowerOrders[localOrder.loc].order !== localOrder.order
+ );
+ }
+ }
+ orders[powerName] = localPowerOrders;
+ }
+ }
+ return orders;
+ }
+
+ __get_wait(engine) {
+ return this.state.wait ? this.state.wait : ContentGame.getServerWaitFlags(engine);
+ }
+
+ getMapInfo() {
+ return this.props.page.availableMaps[this.props.data.map_name];
+ }
+
+ clearScheduleTimeout() {
+ if (this.schedule_timeout_id) {
+ clearInterval(this.schedule_timeout_id);
+ this.schedule_timeout_id = null;
+ }
+ }
+
+ updateDeadlineTimer() {
+ const engine = this.props.data;
+ --engine.deadline_timer;
+ if (engine.deadline_timer <= 0) {
+ engine.deadline_timer = 0;
+ this.clearScheduleTimeout();
+ }
+ this.getPage().setTitle(ContentGame.gameTitle(engine));
+ }
+
+ reloadDeadlineTimer(networkGame) {
+ networkGame.querySchedule()
+ .then(dataSchedule => {
+ const schedule = dataSchedule.schedule;
+ const server_current = schedule.current_time;
+ const server_end = schedule.time_added + schedule.delay;
+ const server_remaining = server_end - server_current;
+ this.props.data.deadline_timer = server_remaining * schedule.time_unit;
+ if (!this.schedule_timeout_id)
+ this.schedule_timeout_id = setInterval(() => this.updateDeadlineTimer(), schedule.time_unit * 1000);
+ })
+ .catch(() => {
+ if (this.props.data.hasOwnProperty('deadline_timer'))
+ delete this.props.data.deadline_timer;
+ this.clearScheduleTimeout();
+ // this.getPage().error(`Error while updating deadline timer: ${error.toString()}`);
+ });
+ }
+
+ networkGameIsDisplayed(networkGame) {
+ return this.getPage().pageIsGame(networkGame.local);
+ }
+
+ notifiedNetworkGame(networkGame, notification) {
+ if (this.networkGameIsDisplayed(networkGame)) {
+ const msg = `Game (${networkGame.local.game_id}) received notification ${notification.name}.`;
+ this.props.page.loadGame(networkGame.local, {info: msg});
+ this.reloadDeadlineTimer(networkGame);
+ }
+ }
+
+ notifiedPowersControllers(networkGame, notification) {
+ if (networkGame.local.isPlayerGame() && (
+ !networkGame.channel.game_id_to_instances.hasOwnProperty(networkGame.local.game_id)
+ || !networkGame.channel.game_id_to_instances[networkGame.local.game_id].has(networkGame.local.role)
+ )) {
+ // This power game is now invalid.
+ this.props.page.disconnectGame(networkGame.local.game_id);
+ if (this.networkGameIsDisplayed(networkGame)) {
+ this.props.page.loadGames(null,
+ {error: `Player game ${networkGame.local.game_id}/${networkGame.local.role} was kicked. Deadline over?`});
+ }
+ } else {
+ this.notifiedNetworkGame(networkGame, notification);
+ }
+ }
+
+ notifiedGamePhaseUpdated(networkGame, notification) {
+ networkGame.getAllPossibleOrders()
+ .then(allPossibleOrders => {
+ networkGame.local.setPossibleOrders(allPossibleOrders);
+ if (this.networkGameIsDisplayed(networkGame)) {
+ this.getPage().loadGame(
+ networkGame.local, {info: `Game update (${notification.name}) to ${networkGame.local.phase}.`}
+ );
+ this.__store_orders(null);
+ this.setState({orders: null, wait: null, messageHighlights: {}});
+ this.reloadDeadlineTimer(networkGame);
+ }
+ })
+ .catch(error => this.getPage().error('Error when updating possible orders: ' + error.toString()));
+ }
+
+ notifiedLocalStateChange(networkGame) {
+ networkGame.getAllPossibleOrders()
+ .then(allPossibleOrders => {
+ networkGame.local.setPossibleOrders(allPossibleOrders);
+ if (this.networkGameIsDisplayed(networkGame)) {
+ this.getPage().loadGame(
+ networkGame.local, {info: `Possible orders re-loaded.`}
+ );
+ this.reloadDeadlineTimer(networkGame);
+ }
+ })
+ .catch(error => this.getPage().error('Error when updating possible orders: ' + error.toString()));
+ }
+
+ notifiedNewGameMessage(networkGame, notification) {
+ let protagonist = notification.message.sender;
+ if (notification.message.recipient === 'GLOBAL')
+ protagonist = notification.message.recipient;
+ const messageHighlights = Object.assign({}, this.state.messageHighlights);
+ if (!messageHighlights.hasOwnProperty(protagonist))
+ messageHighlights[protagonist] = 1;
+ else
+ ++messageHighlights[protagonist];
+ this.setState({messageHighlights: messageHighlights});
+ this.notifiedNetworkGame(networkGame, notification);
+ }
+
+ bindCallbacks(networkGame) {
+ if (!networkGame.callbacksBound) {
+ networkGame.addOnClearedCenters(this.notifiedLocalStateChange);
+ networkGame.addOnClearedOrders(this.notifiedLocalStateChange);
+ networkGame.addOnClearedUnits(this.notifiedLocalStateChange);
+ networkGame.addOnPowersControllers(this.notifiedPowersControllers);
+ networkGame.addOnGameMessageReceived(this.notifiedNewGameMessage);
+ networkGame.addOnGameProcessed(this.notifiedGamePhaseUpdated);
+ networkGame.addOnGamePhaseUpdate(this.notifiedGamePhaseUpdated);
+ networkGame.addOnGameStatusUpdate(this.notifiedNetworkGame);
+ networkGame.addOnOmniscientUpdated(this.notifiedNetworkGame);
+ networkGame.addOnPowerOrdersUpdate(this.notifiedNetworkGame);
+ networkGame.addOnPowerOrdersFlag(this.notifiedNetworkGame);
+ networkGame.addOnPowerVoteUpdated(this.notifiedNetworkGame);
+ networkGame.addOnPowerWaitFlag(this.notifiedNetworkGame);
+ networkGame.addOnVoteCountUpdated(this.notifiedNetworkGame);
+ networkGame.addOnVoteUpdated(this.notifiedNetworkGame);
+ networkGame.callbacksBound = true;
+ networkGame.local.markAllMessagesRead();
+ }
+ }
+
+ onChangeCurrentPower(event) {
+ this.setState({power: event.target.value});
+ }
+
+ onChangeMainTab(tab) {
+ this.setState({tabMain: tab});
+ }
+
+ onChangeTabCurrentMessages(tab) {
+ this.setState({tabCurrentMessages: tab});
+ }
+
+ onChangeTabPastMessages(tab) {
+ this.setState({tabPastMessages: tab});
+ }
+
+ sendMessage(networkGame, recipient, body) {
+ const engine = networkGame.local;
+ const message = new Message({
+ phase: engine.phase,
+ sender: engine.role,
+ recipient: recipient,
+ message: body
+ });
+ const page = this.props.page;
+ networkGame.sendGameMessage({message: message})
+ .then(() => {
+ page.loadGame(engine, {success: `Message sent: ${JSON.stringify(message)}`});
+ })
+ .catch(error => page.error(error.toString()));
+ }
+
+ __store_orders(orders) {
+ // Save local orders into local storage.
+ const username = this.props.data.client.channel.username;
+ const gameID = this.props.data.game_id;
+ const gamePhase = this.props.data.phase;
+ if (!orders) {
+ return DipStorage.clearUserGameOrders(username, gameID);
+ }
+ for (let entry of Object.entries(orders)) {
+ const powerName = entry[0];
+ let powerOrdersList = null;
+ if (entry[1]) {
+ powerOrdersList = Object.values(entry[1]).map(order => order.order);
+ }
+ DipStorage.clearUserGameOrders(username, gameID, powerName);
+ DipStorage.addUserGameOrders(username, gameID, gamePhase, powerName, powerOrdersList);
+ }
+ }
+
+ reloadServerOrders() {
+ const serverOrders = ContentGame.getServerOrders(this.props.data);
+ this.__store_orders(serverOrders);
+ this.setState({orders: serverOrders});
+ }
+
+ setOrders() {
+ const serverOrders = ContentGame.getServerOrders(this.props.data);
+ const orders = this.__get_orders(this.props.data);
+
+ for (let entry of Object.entries(orders)) {
+ const powerName = entry[0];
+ const localPowerOrders = entry[1] ? Object.values(entry[1]).map(orderEntry => orderEntry.order) : null;
+ const serverPowerOrders = serverOrders[powerName] ? Object.values(serverOrders[powerName]).map(orderEntry => orderEntry.order) : null;
+ let same = false;
+
+ if (serverPowerOrders === null) {
+ // No orders set on server.
+ if (localPowerOrders === null)
+ same = true;
+ // Otherwise, we have local orders set (even empty local orders).
+ } else if (serverPowerOrders.length === 0) {
+ // Empty orders set on server.
+ // If local orders are null or empty, then we assume
+ // it's the same thing as empty order set on server.
+ if (localPowerOrders === null || !localPowerOrders.length)
+ same = true;
+ // Otherwise, we have local non-empty orders set.
+ } else {
+ // Orders set on server. Identical to local orders only if we have exactly same orders on server and locally.
+ if (localPowerOrders && localPowerOrders.length === serverPowerOrders.length) {
+ localPowerOrders.sort();
+ serverPowerOrders.sort();
+ const length = localPowerOrders.length;
+ same = true;
+ for (let i = 0; i < length; ++i) {
+ if (localPowerOrders[i] !== serverPowerOrders[i]) {
+ same = false;
+ break;
+ }
+ }
+ }
+ }
+
+ if (same) {
+ Diplog.warn(`Orders not changed for ${powerName}.`);
+ continue;
+ }
+ Diplog.info('Sending orders for ' + powerName + ': ' + JSON.stringify(localPowerOrders));
+ this.props.data.client.setOrders({power_name: powerName, orders: localPowerOrders || []})
+ .then(() => {
+ this.props.page.success('Orders sent.');
+ })
+ .catch(err => {
+ this.props.page.error(err.toString());
+ })
+ .then(() => {
+ this.reloadServerOrders();
+ });
+ }
+ }
+
+ onProcessGame() {
+ this.props.data.client.process()
+ .then(() => this.props.page.success('Game processed.'))
+ .catch(err => {
+ this.props.page.error(err.toString());
+ });
+ }
+
+ onRemoveOrder(powerName, order) {
+ const orders = this.__get_orders(this.props.data);
+ if (orders.hasOwnProperty(powerName)
+ && orders[powerName].hasOwnProperty(order.loc)
+ && orders[powerName][order.loc].order === order.order) {
+ delete orders[powerName][order.loc];
+ if (!UTILS.javascript.count(orders[powerName]))
+ orders[powerName] = null;
+ this.__store_orders(orders);
+ this.setState({orders: orders});
+ }
+ }
+
+ onRemoveAllOrders() {
+ const orders = {};
+ const controllablePowers = this.props.data.getControllablePowers();
+ for (let powerName of controllablePowers) {
+ orders[powerName] = null;
+ }
+ this.__store_orders(orders);
+ this.setState({orders: orders});
+ }
+
+ onOrderBuilding(powerName, path) {
+ const pathToSave = path.slice(1);
+ this.props.page.success(`Building order ${pathToSave.join(' ')} ...`);
+ this.setState({orderBuildingPath: pathToSave});
+ }
+
+ onOrderBuilt(powerName, orderString) {
+ const state = Object.assign({}, this.state);
+ state.orderBuildingPath = [];
+ state.fancy_title = null;
+ state.fancy_function = null;
+ state.on_fancy_close = null;
+ if (!orderString) {
+ Diplog.warn('No order built.');
+ this.setState(state);
+ return;
+ }
+ const engine = this.props.data;
+ const localOrder = new Order(orderString, true);
+ const allOrders = this.__get_orders(engine);
+ if (!allOrders.hasOwnProperty(powerName)) {
+ Diplog.warn(`Unknown power ${powerName}.`);
+ this.setState(state);
+ return;
+ }
+
+ if (!allOrders[powerName])
+ allOrders[powerName] = {};
+ allOrders[powerName][localOrder.loc] = localOrder;
+ state.orders = allOrders;
+ this.props.page.success(`Built order: ${orderString}`);
+ this.__store_orders(allOrders);
+ this.setState(state);
+ }
+
+ onSetNoOrders(powerName) {
+ const orders = this.__get_orders(this.props.data);
+ orders[powerName] = {};
+ this.__store_orders(orders);
+ this.setState({orders: orders});
+ }
+
+ onChangeOrderType(form) {
+ this.setState({
+ orderBuildingType: form.order_type,
+ orderBuildingPath: [],
+ fancy_title: null,
+ fancy_function: null,
+ on_fancy_close: null
+ });
+ }
+
+ vote(decision) {
+ const engine = this.props.data;
+ const networkGame = engine.client;
+ const controllablePowers = engine.getControllablePowers();
+ const currentPowerName = this.state.power || (controllablePowers.length ? controllablePowers[0] : null);
+ if (!currentPowerName)
+ throw new Error(`Internal error: unable to detect current selected power name.`);
+ networkGame.vote({power_name: currentPowerName, vote: decision})
+ .then(() => this.getPage().success(`Vote set to ${decision} for ${currentPowerName}`))
+ .catch(error => {
+ Diplog.error(error.stack);
+ this.getPage().error(`Error while setting vote for ${currentPowerName}: ${error.toString()}`);
+ });
+ }
+
+ setWaitFlag(waitFlag) {
+ const engine = this.props.data;
+ const networkGame = engine.client;
+ const controllablePowers = engine.getControllablePowers();
+ const currentPowerName = this.state.power || (controllablePowers.length ? controllablePowers[0] : null);
+ if (!currentPowerName)
+ throw new Error(`Internal error: unable to detect current selected power name.`);
+ networkGame.setWait(waitFlag, {power_name: currentPowerName})
+ .then(() => this.getPage().success(`Wait flag set to ${waitFlag} for ${currentPowerName}`))
+ .catch(error => {
+ Diplog.error(error.stack);
+ this.getPage().error(`Error while setting wait flag for ${currentPowerName}: ${error.toString()}`);
+ });
+ }
+
+ __change_past_phase(newPhaseIndex, subView) {
+ this.setState({
+ historyPhaseIndex: newPhaseIndex,
+ historySubView: (subView ? subView : 0),
+ historyCurrentLoc: null,
+ historyCurrentOrders: null
+ });
+ }
+
+ onChangePastPhase(event) {
+ this.__change_past_phase(event.target.value);
+ }
+
+ onChangePastPhaseIndex(increment) {
+ const selectObject = document.getElementById('select-past-phase');
+ if (selectObject) {
+ if (!this.state.historyShowOrders) {
+ // We must change map sub-view before showed phase index.
+ const currentSubView = this.state.historySubView;
+ const newSubView = currentSubView + (increment ? 1 : -1);
+ if (newSubView === 0 || newSubView === 1) {
+ // Sub-view correctly updated. We don't yet change showed phase.
+ return this.setState({historySubView: newSubView});
+ }
+ // Sub-view badly updated (either from 0 to -1, or from 1 to 2). We must change phase.
+ }
+ // Let's simply increase or decrease index of showed past phase.
+ const index = selectObject.selectedIndex;
+ const newIndex = index + (increment ? 1 : -1);
+ if (newIndex >= 0 && newIndex < selectObject.length) {
+ selectObject.selectedIndex = newIndex;
+ this.__change_past_phase(parseInt(selectObject.options[newIndex].value, 10), (increment ? 0 : 1));
+ }
+ }
+ }
+
+ onIncrementPastPhase(event) {
+ this.onChangePastPhaseIndex(true);
+ if (event && event.preventDefault)
+ event.preventDefault();
+ }
+
+ onDecrementPastPhase(event) {
+ this.onChangePastPhaseIndex(false);
+ if (event && event.preventDefault)
+ event.preventDefault();
+ }
+
+ displayFirstPastPhase() {
+ this.__change_past_phase(0, 0);
+ }
+
+ displayLastPastPhase() {
+ this.__change_past_phase(-1, 1);
+ }
+
+ onChangeShowPastOrders(event) {
+ this.setState({historyShowOrders: event.target.checked, historySubView: 0});
+ }
+
+ renderOrders(engine, currentPowerName) {
+ const serverOrders = ContentGame.getServerOrders(this.props.data);
+ const orders = this.__get_orders(engine);
+ const wait = this.__get_wait(engine);
+
+ const render = [];
+ render.push(<PowerOrder key={currentPowerName} name={currentPowerName} wait={wait[currentPowerName]}
+ orders={orders[currentPowerName]}
+ serverCount={serverOrders[currentPowerName] ? UTILS.javascript.count(serverOrders[currentPowerName]) : -1}
+ onRemove={this.onRemoveOrder}/>);
+ return render;
+ }
+
+ onClickMessage(message) {
+ if (!message.read) {
+ message.read = true;
+ let protagonist = message.sender;
+ if (message.recipient === 'GLOBAL')
+ protagonist = message.recipient;
+ this.getPage().loadGame(this.props.data);
+ if (this.state.messageHighlights.hasOwnProperty(protagonist) && this.state.messageHighlights[protagonist] > 0) {
+ const messageHighlights = Object.assign({}, this.state.messageHighlights);
+ --messageHighlights[protagonist];
+ this.setState({messageHighlights: messageHighlights});
+ }
+ }
+ }
+
+ displayLocationOrders(loc, orders) {
+ this.setState({
+ historyCurrentLoc: loc || null,
+ historyCurrentOrders: orders && orders.length ? orders : null
+ });
+ }
+
+ renderPastMessages(engine) {
+ const messageChannels = engine.getMessageChannels();
+ let tabNames = null;
+ if (engine.isPlayerGame()) {
+ tabNames = [];
+ for (let powerName of Object.keys(engine.powers)) if (powerName !== engine.role)
+ tabNames.push(powerName);
+ tabNames.sort();
+ tabNames.push('GLOBAL');
+ } else {
+ tabNames = Object.keys(messageChannels);
+ }
+ const currentTabId = this.state.tabPastMessages || tabNames[0];
+
+ return (
+ <div className={'panel-messages'} key={'panel-messages'}>
+ {/* Messages. */}
+ <Tabs menu={tabNames} titles={tabNames} onChange={this.onChangeTabPastMessages} active={currentTabId}>
+ {tabNames.map(protagonist => (
+ <Tab key={protagonist} className={'game-messages'} display={currentTabId === protagonist}>
+ {(!messageChannels.hasOwnProperty(protagonist) || !messageChannels[protagonist].length ?
+ (<div className={'no-game-message'}>No
+ messages{engine.isPlayerGame() ? ` with ${protagonist}` : ''}.</div>) :
+ messageChannels[protagonist].map((message, index) => (
+ <MessageView key={index} owner={engine.role} message={message} read={true}/>
+ ))
+ )}
+ </Tab>
+ ))}
+ </Tabs>
+ </div>
+ );
+ }
+
+ renderCurrentMessages(engine) {
+ const messageChannels = engine.getMessageChannels();
+ let tabNames = null;
+ let highlights = null;
+ if (engine.isPlayerGame()) {
+ tabNames = [];
+ for (let powerName of Object.keys(engine.powers)) if (powerName !== engine.role)
+ tabNames.push(powerName);
+ tabNames.sort();
+ tabNames.push('GLOBAL');
+ highlights = this.state.messageHighlights;
+ } else {
+ tabNames = Object.keys(messageChannels);
+ let totalHighlights = 0;
+ for (let count of Object.values(this.state.messageHighlights))
+ totalHighlights += count;
+ highlights = {messages: totalHighlights};
+ }
+ const unreadMarked = new Set();
+ const currentTabId = this.state.tabCurrentMessages || tabNames[0];
+
+ return (
+ <div className={'panel-messages'} key={'panel-messages'}>
+ {/* Messages. */}
+ <Tabs menu={tabNames} titles={tabNames} onChange={this.onChangeTabCurrentMessages} active={currentTabId}
+ highlights={highlights}>
+ {tabNames.map(protagonist => (
+ <Tab id={`panel-current-messages-${protagonist}`} key={protagonist} className={'game-messages'}
+ display={currentTabId === protagonist}>
+ {(!messageChannels.hasOwnProperty(protagonist) || !messageChannels[protagonist].length ?
+ (<div className={'no-game-message'}>No
+ messages{engine.isPlayerGame() ? ` with ${protagonist}` : ''}.</div>) :
+ (messageChannels[protagonist].map((message, index) => {
+ let id = null;
+ if (!message.read && !unreadMarked.has(protagonist)) {
+ if (engine.isOmniscientGame() || message.sender !== engine.role) {
+ unreadMarked.add(protagonist);
+ id = `${protagonist}-unread`;
+ }
+ }
+ return <MessageView key={index}
+ owner={engine.role}
+ message={message}
+ id={id}
+ onClick={this.onClickMessage}/>;
+ }))
+ )}
+ </Tab>
+ ))}
+ </Tabs>
+ {/* Link to go to first unread received message. */}
+ {unreadMarked.has(currentTabId) && (
+ <Scrollchor className={'link-unread-message'}
+ to={`${currentTabId}-unread`}
+ target={`panel-current-messages-${currentTabId}`}>
+ Go to 1st unread message
+ </Scrollchor>
+ )}
+ {/* Send form. */}
+ {engine.isPlayerGame() && (
+ <MessageForm sender={engine.role} recipient={currentTabId} onSubmit={form =>
+ this.sendMessage(engine.client, currentTabId, form.message)}/>)}
+ </div>
+ );
+ }
+
+ renderPastMap(gameEngine, showOrders) {
+ return <Map key={'past-map'}
+ id={'past-map'}
+ game={gameEngine}
+ mapInfo={this.getMapInfo(gameEngine.map_name)}
+ onError={this.getPage().error}
+ onHover={showOrders ? this.displayLocationOrders : null}
+ showOrders={Boolean(showOrders)}
+ orders={(gameEngine.order_history.contains(gameEngine.phase) && gameEngine.order_history.get(gameEngine.phase)) || null}
+ />;
+ }
+
+ renderCurrentMap(gameEngine, powerName, orderType, orderPath) {
+ const rawOrders = this.__get_orders(gameEngine);
+ const orders = {};
+ for (let entry of Object.entries(rawOrders)) {
+ orders[entry[0]] = [];
+ if (entry[1]) {
+ for (let orderObject of Object.values(entry[1]))
+ orders[entry[0]].push(orderObject.order);
+ }
+ }
+ return <Map key={'current-map'}
+ id={'current-map'}
+ game={gameEngine}
+ mapInfo={this.getMapInfo(gameEngine.map_name)}
+ onError={this.getPage().error}
+ orderBuilding={ContentGame.getOrderBuilding(powerName, orderType, orderPath)}
+ onOrderBuilding={this.onOrderBuilding}
+ onOrderBuilt={this.onOrderBuilt}
+ showOrders={true}
+ orders={orders}
+ onSelectLocation={this.onSelectLocation}
+ onSelectVia={this.onSelectVia}/>;
+ }
+
+ renderTabPhaseHistory(toDisplay, initialEngine) {
+ const pastPhases = initialEngine.state_history.values().map(state => state.name);
+ if (initialEngine.phase === 'COMPLETED') {
+ pastPhases.push('COMPLETED');
+ }
+ let phaseIndex = 0;
+ if (initialEngine.displayed) {
+ if (this.state.historyPhaseIndex === null || this.state.historyPhaseIndex >= pastPhases.length) {
+ phaseIndex = pastPhases.length - 1;
+ } else {
+ if (this.state.historyPhaseIndex < 0) {
+ phaseIndex = pastPhases.length + this.state.historyPhaseIndex;
+ } else {
+ phaseIndex = this.state.historyPhaseIndex;
+ }
+ }
+ }
+ const engine = (
+ phaseIndex === initialEngine.state_history.size() ?
+ initialEngine : initialEngine.cloneAt(initialEngine.state_history.keyFromIndex(phaseIndex))
+ );
+ let orders = {};
+ let orderResult = null;
+ if (engine.order_history.contains(engine.phase))
+ orders = engine.order_history.get(engine.phase);
+ if (engine.result_history.contains(engine.phase))
+ orderResult = engine.result_history.get(engine.phase);
+ let countOrders = 0;
+ for (let powerOrders of Object.values(orders)) {
+ if (powerOrders)
+ countOrders += powerOrders.length;
+ }
+ const powerNames = Object.keys(orders);
+ powerNames.sort();
+
+ const getOrderResult = (order) => {
+ if (orderResult) {
+ const pieces = order.split(/ +/);
+ const unit = `${pieces[0]} ${pieces[1]}`;
+ if (orderResult.hasOwnProperty(unit)) {
+ const resultsToParse = orderResult[unit];
+ if (!resultsToParse.length)
+ resultsToParse.push('');
+ const results = [];
+ for (let r of resultsToParse) {
+ if (results.length)
+ results.push(', ');
+ results.push(<span key={results.length} className={r || 'success'}>{r || 'OK'}</span>);
+ }
+ return <span className={'order-result'}> ({results})</span>;
+ }
+ }
+ return '';
+ };
+
+ const orderView = [
+ (<form key={1} className={'form-inline mb-4'}>
+ <Button title={UTILS.html.UNICODE_LEFT_ARROW} onClick={this.onDecrementPastPhase} pickEvent={true}
+ disabled={phaseIndex === 0}/>
+ <div className={'form-group'}>
+ <select className={'form-control custom-select'}
+ id={'select-past-phase'}
+ value={phaseIndex}
+ onChange={this.onChangePastPhase}>
+ {pastPhases.map((phaseName, index) => <option key={index} value={index}>{phaseName}</option>)}
+ </select>
+ </div>
+ <Button title={UTILS.html.UNICODE_RIGHT_ARROW} onClick={this.onIncrementPastPhase} pickEvent={true}
+ disabled={phaseIndex === pastPhases.length - 1}/>
+ <div className={'form-group'}>
+ <input className={'form-check-input'} id={'show-orders'} type={'checkbox'}
+ checked={this.state.historyShowOrders} onChange={this.onChangeShowPastOrders}/>
+ <label className={'form-check-label'} htmlFor={'show-orders'}>Show orders</label>
+ </div>
+ </form>),
+ ((this.state.historyShowOrders && (
+ (countOrders && (
+ <div key={2} className={'past-orders container'}>
+ {powerNames.map(powerName => !orders[powerName] || !orders[powerName].length ? '' : (
+ <div key={powerName} className={'row'}>
+ <div className={'past-power-name col-sm-2'}>{powerName}</div>
+ <div className={'past-power-orders col-sm-10'}>
+ {orders[powerName].map((order, index) => (
+ <div key={index}>{order}{getOrderResult(order)}</div>
+ ))}
+ </div>
+ </div>
+ ))}
+ </div>
+ )) || <div key={2} className={'no-orders'}>No orders for this phase!</div>
+ )) || '')
+ ];
+ const messageView = this.renderPastMessages(engine);
+
+ let detailsView = null;
+ if (this.state.historyShowOrders && countOrders) {
+ detailsView = (
+ <Row>
+ <div className={'col-sm-6'}>{orderView}</div>
+ <div className={'col-sm-6'}>{messageView}</div>
+ </Row>
+ );
+ } else {
+ detailsView = orderView.slice();
+ detailsView.push(messageView);
+ }
+
+ return (
+ <Tab id={'tab-phase-history'} display={toDisplay}>
+ <Row>
+ <div className={'col-xl'}>
+ {this.state.historyCurrentOrders && (
+ <div className={'history-current-orders'}>{this.state.historyCurrentOrders.join(', ')}</div>
+ )}
+ {this.renderPastMap(engine, this.state.historyShowOrders || this.state.historySubView)}
+ </div>
+ <div className={'col-xl'}>{detailsView}</div>
+ </Row>
+ {toDisplay && <HotKey keys={['arrowleft']} onKeysCoincide={this.onDecrementPastPhase}/>}
+ {toDisplay && <HotKey keys={['arrowright']} onKeysCoincide={this.onIncrementPastPhase}/>}
+ {toDisplay && <HotKey keys={['home']} onKeysCoincide={this.displayFirstPastPhase}/>}
+ {toDisplay && <HotKey keys={['end']} onKeysCoincide={this.displayLastPastPhase}/>}
+ </Tab>
+ );
+ }
+
+ renderTabCurrentPhase(toDisplay, engine, powerName, orderType, orderPath) {
+ const powerNames = Object.keys(engine.powers);
+ powerNames.sort();
+ const orderedPowers = powerNames.map(pn => engine.powers[pn]);
+ return (
+ <Tab id={'tab-current-phase'} display={toDisplay}>
+ <Row>
+ <div className={'col-xl'}>
+ {this.renderCurrentMap(engine, powerName, orderType, orderPath)}
+ </div>
+ <div className={'col-xl'}>
+ {/* Orders. */}
+ <div className={'panel-orders mb-4'}>
+ <Bar className={'p-2'}>
+ <strong className={'mr-4'}>Orders:</strong>
+ <Button title={'reset'} onClick={this.reloadServerOrders}/>
+ <Button title={'delete all'} onClick={this.onRemoveAllOrders}/>
+ <Button color={'primary'} title={'update'} onClick={this.setOrders}/>
+ {(!this.props.data.isPlayerGame() && this.props.data.observer_level === STRINGS.MASTER_TYPE &&
+ <Button color={'danger'} title={'process game'}
+ onClick={this.onProcessGame}/>) || ''}
+ </Bar>
+ <div className={'orders'}>{this.renderOrders(this.props.data, powerName)}</div>
+ <div className={'table-responsive'}>
+ <Table className={'table table-striped table-sm'}
+ caption={'Powers info'}
+ columns={TABLE_POWER_VIEW}
+ data={orderedPowers}
+ wrapper={PowerView.wrap}/>
+ </div>
+ </div>
+ {/* Messages. */}
+ {this.renderCurrentMessages(engine)}
+ </div>
+ </Row>
+ </Tab>
+ );
+ }
+
+ render() {
+ const engine = this.props.data;
+ const phaseType = engine.getPhaseType();
+ const controllablePowers = engine.getControllablePowers();
+ if (this.props.data.client)
+ this.bindCallbacks(this.props.data.client);
+
+ if (engine.phase === 'FORMING')
+ return <main>
+ <div className={'forming'}>Game not yet started!</div>
+ </main>;
+
+ const tabNames = [];
+ const tabTitles = [];
+ let hasTabPhaseHistory = false;
+ let hasTabCurrentPhase = false;
+ if (engine.state_history.size()) {
+ hasTabPhaseHistory = true;
+ tabNames.push('phase_history');
+ tabTitles.push('Phase history');
+ }
+ if (controllablePowers.length && phaseType) {
+ hasTabCurrentPhase = true;
+ tabNames.push('current_phase');
+ tabTitles.push('Current phase');
+ }
+ if (!tabNames.length) {
+ // This should never happen, but let's display this message.
+ return <main>
+ <div className={'no-data'}>No data in this game!</div>
+ </main>;
+ }
+ const mainTab = this.state.tabMain && tabNames.includes(this.state.tabMain) ? this.state.tabMain : tabNames[tabNames.length - 1];
+
+ const currentPowerName = this.state.power || (controllablePowers.length && controllablePowers[0]);
+ let currentPower = null;
+ let orderTypeToLocs = null;
+ let allowedPowerOrderTypes = null;
+ let orderBuildingType = null;
+ let buildCount = null;
+ if (hasTabCurrentPhase) {
+ currentPower = engine.getPower(currentPowerName);
+ orderTypeToLocs = engine.getOrderTypeToLocs(currentPowerName);
+ allowedPowerOrderTypes = Object.keys(orderTypeToLocs);
+ // canOrder = allowedPowerOrderTypes.length
+ if (allowedPowerOrderTypes.length) {
+ POSSIBLE_ORDERS.sortOrderTypes(allowedPowerOrderTypes, phaseType);
+ if (this.state.orderBuildingType && allowedPowerOrderTypes.includes(this.state.orderBuildingType))
+ orderBuildingType = this.state.orderBuildingType;
+ else
+ orderBuildingType = allowedPowerOrderTypes[0];
+ }
+ buildCount = engine.getBuildsCount(currentPowerName);
+ }
+
+ return (
+ <main>
+ {(hasTabCurrentPhase && (
+ <div className={'row align-items-center mb-3'}>
+ <div className={'col-sm-2'}>
+ {(controllablePowers.length === 1 &&
+ <div className={'power-name'}>{controllablePowers[0]}</div>) || (
+ <select className={'form-control custom-select'} id={'current-power'}
+ value={currentPowerName} onChange={this.onChangeCurrentPower}>
+ {controllablePowers.map(
+ powerName => <option key={powerName} value={powerName}>{powerName}</option>)}
+ </select>
+ )}
+ </div>
+ <div className={'col-sm-10'}>
+ <PowerActionsForm orderType={orderBuildingType}
+ orderTypes={allowedPowerOrderTypes}
+ onChange={this.onChangeOrderType}
+ onNoOrders={() => this.onSetNoOrders(currentPowerName)}
+ onSetWaitFlag={() => this.setWaitFlag(!currentPower.wait)}
+ onVote={this.vote}
+ role={engine.role}
+ power={currentPower}/>
+ </div>
+ </div>
+ )) || ''}
+ {(hasTabCurrentPhase && (
+ <div>
+ {(allowedPowerOrderTypes.length && (
+ <span>
+ <strong>Orderable locations</strong>: {orderTypeToLocs[orderBuildingType].join(', ')}
+ </span>
+ ))
+ || (<strong>&nbsp;No orderable location.</strong>)}
+ {phaseType === 'A' && (
+ (buildCount === null && (
+ <strong>&nbsp;(unknown build count)</strong>
+ ))
+ || (buildCount === 0 ? (
+ <strong>&nbsp;(nothing to build or disband)</strong>
+ ) : (buildCount > 0 ? (
+ <strong>&nbsp;({buildCount} unit{buildCount > 1 && 's'} may be built)</strong>
+ ) : (
+ <strong>&nbsp;({-buildCount} unit{buildCount < -1 && 's'} to disband)</strong>
+ )))
+ )}
+ </div>
+ )) || ''}
+ <Tabs menu={tabNames} titles={tabTitles} onChange={this.onChangeMainTab} active={mainTab}>
+ {/* Tab Phase history. */}
+ {(hasTabPhaseHistory && this.renderTabPhaseHistory(mainTab === 'phase_history', engine)) || ''}
+ {/* Tab Current phase. */}
+ {(hasTabCurrentPhase && this.renderTabCurrentPhase(
+ mainTab === 'current_phase',
+ engine,
+ currentPowerName,
+ orderBuildingType,
+ this.state.orderBuildingPath
+ )) || ''}
+ </Tabs>
+ {this.state.fancy_title && (
+ <FancyBox title={this.state.fancy_title} onClose={this.state.on_fancy_close}>
+ {this.state.fancy_function()}
+ </FancyBox>)}
+ </main>
+ );
+ }
+
+ componentDidMount() {
+ super.componentDidMount();
+ if (this.props.data.client)
+ this.reloadDeadlineTimer(this.props.data.client);
+ this.props.data.displayed = true;
+ // Try to prevent scrolling when pressing keys Home and End.
+ document.onkeydown = (event) => {
+ if (['home', 'end'].includes(event.key.toLowerCase())) {
+ // Try to prevent scrolling.
+ if (event.hasOwnProperty('cancelBubble'))
+ event.cancelBubble = true;
+ if (event.stopPropagation)
+ event.stopPropagation();
+ if (event.preventDefault)
+ event.preventDefault();
+ }
+ };
+ }
+
+ componentDidUpdate() {
+ this.props.data.displayed = true;
+ }
+
+ componentWillUnmount() {
+ this.clearScheduleTimeout();
+ this.props.data.displayed = false;
+ document.onkeydown = null;
+ }
+
+}
diff --git a/diplomacy/web/src/gui/diplomacy/contents/content_games.jsx b/diplomacy/web/src/gui/diplomacy/contents/content_games.jsx
new file mode 100644
index 0000000..6a62d71
--- /dev/null
+++ b/diplomacy/web/src/gui/diplomacy/contents/content_games.jsx
@@ -0,0 +1,140 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import React from "react";
+import {Content} from "../../core/content";
+import {Tab, Tabs} from "../../core/tabs";
+import {Table} from "../../core/table";
+import {FindForm} from "../forms/find_form";
+import {CreateForm} from "../forms/create_form";
+import {InlineGameView} from "../utils/inline_game_view";
+import {STRINGS} from "../../../diplomacy/utils/strings";
+
+const TABLE_LOCAL_GAMES = {
+ game_id: ['Game ID', 0],
+ deadline: ['Deadline', 1],
+ rights: ['Rights', 2],
+ rules: ['Rules', 3],
+ players: ['Players/Expected', 4],
+ status: ['Status', 5],
+ phase: ['Phase', 6],
+ join: ['Join', 7],
+ my_games: ['My Games', 8],
+};
+
+export class ContentGames extends Content {
+
+ constructor(props) {
+ super(props);
+ this.state = {tab: null};
+ this.changeTab = this.changeTab.bind(this);
+ this.onFind = this.onFind.bind(this);
+ this.onCreate = this.onCreate.bind(this);
+ this.wrapGameData = this.wrapGameData.bind(this);
+ }
+
+ static builder(page, data) {
+ return {
+ title: 'Games',
+ navigation: [
+ ['load a game from disk', page.loadGameFromDisk],
+ ['logout', page.logout]
+ ],
+ component: <ContentGames page={page} data={data}/>
+ };
+ }
+
+ onFind(form) {
+ for (let field of ['game_id', 'status', 'include_protected', 'for_omniscience'])
+ if (!form[field])
+ form[field] = null;
+ this.getPage().channel.listGames(form)
+ .then((data) => {
+ this.getPage().success('Found ' + data.length + ' data.');
+ this.getPage().addGamesFound(data);
+ })
+ .catch((error) => {
+ this.getPage().error('Error when looking for distant games: ' + error);
+ });
+ }
+
+ onCreate(form) {
+ for (let key of Object.keys(form)) {
+ if (form[key] === '')
+ form[key] = null;
+ }
+ if (form.n_controls !== null)
+ form.n_controls = parseInt(form.n_controls, 10);
+ if (form.deadline !== null)
+ form.deadline = parseInt(form.deadline, 10);
+ form.rules = ['POWER_CHOICE'];
+ for (let rule of STRINGS.PUBLIC_RULES) {
+ const rule_id = `rule_${rule.toLowerCase()}`;
+ if (form.hasOwnProperty(rule_id)) {
+ if (form[rule_id])
+ form.rules.push(rule);
+ delete form[rule_id];
+ }
+ }
+ let networkGame = null;
+ this.getPage().channel.createGame(form)
+ .then((game) => {
+ this.getPage().addToMyGames(game.local);
+ networkGame = game;
+ return networkGame.getAllPossibleOrders();
+ })
+ .then(allPossibleOrders => {
+ networkGame.local.setPossibleOrders(allPossibleOrders);
+ this.getPage().loadGame(networkGame.local, {success: 'Game created.'});
+ })
+ .catch((error) => {
+ this.getPage().error('Error when creating a game: ' + error);
+ });
+ }
+
+ changeTab(tabIndex) {
+ this.setState({tab: tabIndex});
+ }
+
+ wrapGameData(gameData) {
+ return new InlineGameView(this.getPage(), gameData);
+ }
+
+ render() {
+ const myGames = this.getPage().getMyGames();
+ const tab = this.state.tab ? this.state.tab : (myGames.length ? 'my-games' : 'find');
+ return (
+ <main>
+ <Tabs menu={['create', 'find', 'my-games']} titles={['Create', 'Find', 'My Games']}
+ onChange={this.changeTab} active={tab}>
+ <Tab id="tab-games-create" display={tab === 'create'}>
+ <CreateForm onSubmit={this.onCreate}/>
+ </Tab>
+ <Tab id="tab-games-find" display={tab === 'find'}>
+ <FindForm onSubmit={this.onFind}/>
+ <Table className={"table table-striped"} caption={"Games"} columns={TABLE_LOCAL_GAMES}
+ data={this.getPage().getGamesFound()} wrapper={this.wrapGameData}/>
+ </Tab>
+ <Tab id={'tab-my-games'} display={tab === 'my-games'}>
+ <Table className={"table table-striped"} caption={"My games"} columns={TABLE_LOCAL_GAMES}
+ data={myGames} wrapper={this.wrapGameData}/>
+ </Tab>
+ </Tabs>
+ </main>
+ );
+ }
+
+}
diff --git a/diplomacy/web/src/gui/diplomacy/forms/connection_form.jsx b/diplomacy/web/src/gui/diplomacy/forms/connection_form.jsx
new file mode 100644
index 0000000..49ba381
--- /dev/null
+++ b/diplomacy/web/src/gui/diplomacy/forms/connection_form.jsx
@@ -0,0 +1,123 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import React from 'react';
+import {Forms} from "../../core/forms";
+import {UTILS} from "../../../diplomacy/utils/utils";
+import PropTypes from "prop-types";
+import {DipStorage} from "../utils/dipStorage";
+
+export class ConnectionForm extends React.Component {
+ constructor(props) {
+ super(props);
+ // Load fields values from local storage.
+ const initialState = this.initState();
+ const savedState = DipStorage.getConnectionForm();
+ if (savedState) {
+ if (savedState.hostname)
+ initialState.hostname = savedState.hostname;
+ if (savedState.port)
+ initialState.port = savedState.port;
+ if (savedState.username)
+ initialState.username = savedState.username;
+ if (savedState.showServerFields)
+ initialState.showServerFields = savedState.showServerFields;
+ }
+ this.state = initialState;
+ this.updateServerFieldsView = this.updateServerFieldsView.bind(this);
+ this.onChange = this.onChange.bind(this);
+ }
+
+ initState() {
+ return {
+ hostname: window.location.hostname,
+ port: (window.location.protocol.toLowerCase() === 'https:') ? 8433 : 8432,
+ username: '',
+ password: '',
+ showServerFields: false
+ };
+ }
+
+ updateServerFieldsView() {
+ DipStorage.setConnectionshowServerFields(!this.state.showServerFields);
+ this.setState({showServerFields: !this.state.showServerFields});
+ }
+
+ onChange(newState) {
+ const initialState = this.initState();
+ if (newState.hostname !== initialState.hostname)
+ DipStorage.setConnectionHostname(newState.hostname);
+ else
+ DipStorage.setConnectionHostname(null);
+ if (newState.port !== initialState.port)
+ DipStorage.setConnectionPort(newState.port);
+ else
+ DipStorage.setConnectionPort(null);
+ if (newState.username !== initialState.username)
+ DipStorage.setConnectionUsername(newState.username);
+ else
+ DipStorage.setConnectionUsername(null);
+ if (this.props.onChange)
+ this.props.onChange(newState);
+ }
+
+ render() {
+ const onChange = Forms.createOnChangeCallback(this, this.onChange);
+ const onSubmit = Forms.createOnSubmitCallback(this, this.props.onSubmit);
+ return (
+ <form>
+ {Forms.createRow(
+ Forms.createColLabel('username', 'username:'),
+ <input className={'form-control'} type={'text'} id={'username'}
+ value={Forms.getValue(this.state, 'username')} onChange={onChange}/>
+ )}
+ {Forms.createRow(
+ Forms.createColLabel('password', 'password:'),
+ <input className={'form-control'} type={'password'} id={'password'}
+ value={Forms.getValue(this.state, 'password')} onChange={onChange}/>
+ )}
+ <div>
+ <div className={this.state.showServerFields ? 'mb-2' : 'mb-4'}>
+ <span className={'button-server'} onClick={this.updateServerFieldsView}>
+ server settings {this.state.showServerFields ? UTILS.html.UNICODE_BOTTOM_ARROW : UTILS.html.UNICODE_TOP_ARROW}
+ </span>
+ </div>
+ {this.state.showServerFields && (
+ <div className={'mb-4'}>
+ {Forms.createRow(
+ <label className={'col'} htmlFor={'hostname'}>hostname:</label>,
+ <input className={'form-control'} type={'text'} id={'hostname'}
+ value={Forms.getValue(this.state, 'hostname')} onChange={onChange}/>
+ )}
+ {Forms.createRow(
+ <label className={'col'} htmlFor={'port'}>port:</label>,
+ <input className={'form-control'} type={'number'} id={'port'}
+ value={Forms.getValue(this.state, 'port')}
+ onChange={onChange}/>
+ )}
+ </div>
+ )}
+ </div>
+ {Forms.createRow('', Forms.createSubmit('connect', true, onSubmit))}
+ </form>
+ );
+ }
+}
+
+ConnectionForm.propTypes = {
+ onChange: PropTypes.func,
+ onSubmit: PropTypes.func
+};
diff --git a/diplomacy/web/src/gui/diplomacy/forms/create_form.jsx b/diplomacy/web/src/gui/diplomacy/forms/create_form.jsx
new file mode 100644
index 0000000..48c733e
--- /dev/null
+++ b/diplomacy/web/src/gui/diplomacy/forms/create_form.jsx
@@ -0,0 +1,95 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import React from 'react';
+import {Forms} from "../../core/forms";
+import {STRINGS} from "../../../diplomacy/utils/strings";
+import PropTypes from "prop-types";
+
+export class CreateForm extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = this.initState();
+ }
+
+ initState() {
+ const state = {
+ game_id: '',
+ power_name: '',
+ n_controls: 7,
+ deadline: 300,
+ registration_password: ''
+ };
+ for (let rule of STRINGS.PUBLIC_RULES)
+ state[`rule_${rule.toLowerCase()}`] = false;
+ return state;
+ }
+
+ render() {
+ const onChange = Forms.createOnChangeCallback(this, this.props.onChange);
+ const onSubmit = Forms.createOnSubmitCallback(this, this.props.onSubmit);
+ return (
+ <form>
+ {Forms.createRow(
+ Forms.createColLabel('game_id', 'Game ID (optional)'),
+ <input id={'game_id'} className={'form-control'} type={'text'}
+ value={Forms.getValue(this.state, 'game_id')} onChange={onChange}/>
+ )}
+ {Forms.createRow(
+ Forms.createColLabel('power_name', 'power:'),
+ <select id={'power_name'} className={'form-control custom-select'}
+ value={Forms.getValue(this.state, 'power_name')} onChange={onChange}>
+ {Forms.createSelectOptions(STRINGS.ALL_POWER_NAMES, true)}
+ </select>
+ )}
+ {Forms.createRow(
+ Forms.createColLabel('n_controls', 'number of required players:'),
+ <input id={'n_controls'} className={'form-control'} type={'number'}
+ value={Forms.getValue(this.state, 'n_controls')} onChange={onChange}/>
+ )}
+ {Forms.createRow(
+ Forms.createColLabel('deadline', 'deadline (in seconds)'),
+ <input id={'deadline'} className={'form-control'} type={'number'}
+ value={Forms.getValue(this.state, 'deadline')}
+ onChange={onChange}/>
+ )}
+ {Forms.createRow(
+ Forms.createColLabel('registration_password', 'registration password'),
+ <input id={'registration_password'} className={'form-control'} type={'password'}
+ value={Forms.getValue(this.state, 'registration_password')} onChange={onChange}/>
+ )}
+ <div><strong>RULES:</strong></div>
+ <div className={'mb-4'}>
+ {STRINGS.PUBLIC_RULES.map((rule, index) => (
+ <div key={index} className={'form-check-inline'}>
+ {Forms.createCheckbox(
+ `rule_${rule.toLowerCase()}`,
+ rule,
+ Forms.getValue(this.state, `rule_${rule.toLowerCase()}`),
+ onChange)}
+ </div>
+ ))}
+ </div>
+ {Forms.createRow('', Forms.createSubmit('create a game', true, onSubmit))}
+ </form>
+ );
+ }
+}
+
+CreateForm.propTypes = {
+ onChange: PropTypes.func,
+ onSubmit: PropTypes.func
+};
diff --git a/diplomacy/web/src/gui/diplomacy/forms/find_form.jsx b/diplomacy/web/src/gui/diplomacy/forms/find_form.jsx
new file mode 100644
index 0000000..c73d2b1
--- /dev/null
+++ b/diplomacy/web/src/gui/diplomacy/forms/find_form.jsx
@@ -0,0 +1,70 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import React from 'react';
+import {Forms} from "../../core/forms";
+import {STRINGS} from "../../../diplomacy/utils/strings";
+import PropTypes from "prop-types";
+
+export class FindForm extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = this.initState();
+ }
+
+ initState() {
+ return {
+ game_id: '',
+ status: '',
+ include_protected: false,
+ for_omniscience: false
+ };
+ }
+
+ render() {
+ const onChange = Forms.createOnChangeCallback(this, this.props.onChange);
+ const onSubmit = Forms.createOnSubmitCallback(this, this.props.onSubmit);
+ return (
+ <form>
+ {Forms.createRow(
+ Forms.createColLabel('game_id', 'game id (should contain):'),
+ <input className={'form-control'} id={'game_id'} type={'text'}
+ value={Forms.getValue(this.state, 'game_id')}
+ onChange={onChange}/>
+ )}
+ {Forms.createRow(
+ Forms.createColLabel('status', 'status:'),
+ (<select className={'form-control custom-select'}
+ id={'status'} value={Forms.getValue(this.state, 'status')} onChange={onChange}>
+ {Forms.createSelectOptions(STRINGS.ALL_GAME_STATUSES, true)}
+ </select>)
+ )}
+ <div className={'form-check'}>
+ {Forms.createCheckbox('include_protected', 'include protected games.', Forms.getValue(this.state, 'include_protected'), onChange)}
+ </div>
+ <div className={'form-check mb-4'}>
+ {Forms.createCheckbox('for_omniscience', 'for omniscience.', Forms.getValue(this.state, 'for_omniscience'), onChange)}
+ </div>
+ {Forms.createRow('', Forms.createSubmit('find games', true, onSubmit))}
+ </form>
+ );
+ }
+}
+
+FindForm.propTypes = {
+ onChange: PropTypes.func,
+ onSubmit: PropTypes.func
+};
diff --git a/diplomacy/web/src/gui/diplomacy/forms/join_form.jsx b/diplomacy/web/src/gui/diplomacy/forms/join_form.jsx
new file mode 100644
index 0000000..0447280
--- /dev/null
+++ b/diplomacy/web/src/gui/diplomacy/forms/join_form.jsx
@@ -0,0 +1,77 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import React from 'react';
+import {Forms} from "../../core/forms";
+import {STRINGS} from "../../../diplomacy/utils/strings";
+import PropTypes from "prop-types";
+
+export class JoinForm extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = this.initState();
+ }
+
+ initState() {
+ return {
+ [this.getPowerNameID()]: this.getDefaultPowerName(),
+ [this.getPasswordID()]: ''
+ };
+ }
+
+ getPowerNameID() {
+ return `power_name_${this.props.game_id}`;
+ }
+
+ getPasswordID() {
+ return `registration_password_${this.props.game_id}`;
+ }
+
+ getDefaultPowerName() {
+ return (this.props.powers && this.props.powers.length && this.props.powers[0]) || '';
+ }
+
+ render() {
+ const onChange = Forms.createOnChangeCallback(this, this.props.onChange);
+ const onSubmit = Forms.createOnSubmitCallback(this, this.props.onSubmit);
+ return (
+ <form className={'form-inline'}>
+ <div className={'form-group'}>
+ {Forms.createLabel(this.getPowerNameID(), 'Power:')}
+ <select id={this.getPowerNameID()} className={'from-control custom-select ml-2'}
+ value={Forms.getValue(this.state, this.getPowerNameID())} onChange={onChange}>
+ {Forms.createSelectOptions(STRINGS.ALL_POWER_NAMES, true)}
+ </select>
+ </div>
+ <div className={'form-group mx-2'}>
+ {Forms.createLabel(this.getPasswordID(), '', 'sr-only')}
+ <input id={this.getPasswordID()} type={'password'} className={'form-control'}
+ placeholder={'registration password'}
+ value={Forms.getValue(this.state, this.getPasswordID())}
+ onChange={onChange}/>
+ </div>
+ {Forms.createSubmit('join', false, onSubmit)}
+ </form>
+ );
+ }
+}
+
+JoinForm.propTypes = {
+ game_id: PropTypes.string.isRequired,
+ powers: PropTypes.arrayOf(PropTypes.string),
+ onChange: PropTypes.func,
+ onSubmit: PropTypes.func
+};
diff --git a/diplomacy/web/src/gui/diplomacy/forms/message_form.jsx b/diplomacy/web/src/gui/diplomacy/forms/message_form.jsx
new file mode 100644
index 0000000..a7c377a
--- /dev/null
+++ b/diplomacy/web/src/gui/diplomacy/forms/message_form.jsx
@@ -0,0 +1,53 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import React from 'react';
+import {Forms} from "../../core/forms";
+import {UTILS} from "../../../diplomacy/utils/utils";
+import PropTypes from "prop-types";
+
+export class MessageForm extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = this.initState();
+ }
+
+ initState() {
+ return {message: ''};
+ }
+
+ render() {
+ const onChange = Forms.createOnChangeCallback(this, this.props.onChange);
+ const onSubmit = Forms.createOnSubmitCallback(this, this.props.onSubmit, this.initState());
+ return (
+ <form>
+ <div className={'form-group'}>
+ {Forms.createLabel('message', '', 'sr-only')}
+ <textarea id={'message'} className={'form-control'}
+ value={Forms.getValue(this.state, 'message')} onChange={onChange}/>
+ </div>
+ {Forms.createSubmit(`send (${this.props.sender} ${UTILS.html.UNICODE_SMALL_RIGHT_ARROW} ${this.props.recipient})`, true, onSubmit)}
+ </form>
+ );
+ }
+}
+
+MessageForm.propTypes = {
+ sender: PropTypes.string,
+ recipient: PropTypes.string,
+ onChange: PropTypes.func,
+ onSubmit: PropTypes.func
+};
diff --git a/diplomacy/web/src/gui/diplomacy/forms/power_actions_form.jsx b/diplomacy/web/src/gui/diplomacy/forms/power_actions_form.jsx
new file mode 100644
index 0000000..33bd763
--- /dev/null
+++ b/diplomacy/web/src/gui/diplomacy/forms/power_actions_form.jsx
@@ -0,0 +1,120 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import React from 'react';
+import {Forms} from "../../core/forms";
+import {ORDER_BUILDER} from "../utils/order_building";
+import {STRINGS} from "../../../diplomacy/utils/strings";
+import PropTypes from "prop-types";
+import {Power} from "../../../diplomacy/engine/power";
+
+const HotKey = require('react-shortcut');
+
+export class PowerActionsForm extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = this.initState();
+ }
+
+ initState() {
+ return {order_type: this.props.orderType};
+ }
+
+ render() {
+ const onChange = Forms.createOnChangeCallback(this, this.props.onChange);
+ const onReset = Forms.createOnResetCallback(this, this.props.onChange, this.initState());
+ const onSetOrderType = (letter) => {
+ this.setState({order_type: letter}, () => {
+ if (this.props.onChange)
+ this.props.onChange(this.state);
+ });
+ };
+ let title = '';
+ let titleClass = 'mr-4';
+ const header = [];
+ const votes = [];
+ if (this.props.orderTypes.length) {
+ title = 'Create order:';
+ header.push(<strong key={'title'} className={titleClass}>{title}</strong>);
+ header.push(...this.props.orderTypes.map((orderLetter, index) => (
+ <div key={index} className={'form-check-inline'}>
+ {Forms.createRadio('order_type', orderLetter, ORDER_BUILDER[orderLetter].name, this.props.orderType, onChange)}
+ </div>
+ )));
+ header.push(Forms.createReset('reset', false, onReset));
+ } else if (this.props.power.order_is_set) {
+ title = 'Unorderable power (already locked on server).';
+ titleClass += ' neutral';
+ header.push(<strong key={'title'} className={titleClass}>{title}</strong>);
+ } else {
+ title = 'No orders available for this power.';
+ header.push(<strong key={'title'} className={titleClass}>{title}</strong>);
+ }
+ if (!this.props.power.order_is_set) {
+ header.push(Forms.createButton('pass', this.props.onNoOrders));
+ }
+
+ if (this.props.role !== STRINGS.OMNISCIENT_TYPE) {
+ votes.push(<strong key={0} className={'ml-4 mr-2'}>Vote for draw:</strong>);
+ switch (this.props.power.vote) {
+ case 'yes':
+ votes.push(Forms.createButton('no', () => this.props.onVote('no'), 'danger'));
+ votes.push(Forms.createButton('neutral', () => this.props.onVote('neutral'), 'info'));
+ break;
+ case 'no':
+ votes.push(Forms.createButton('yes', () => this.props.onVote('yes'), 'success'));
+ votes.push(Forms.createButton('neutral', () => this.props.onVote('neutral'), 'info'));
+ break;
+ case 'neutral':
+ votes.push(Forms.createButton('yes', () => this.props.onVote('yes'), 'success'));
+ votes.push(Forms.createButton('no', () => this.props.onVote('no'), 'danger'));
+ break;
+ default:
+ votes.push(Forms.createButton('yes', () => this.props.onVote('yes'), 'success'));
+ votes.push(Forms.createButton('no', () => this.props.onVote('no'), 'danger'));
+ votes.push(Forms.createButton('neutral', () => this.props.onVote('neutral'), 'info'));
+ break;
+ }
+ }
+ return (
+ <form className={'form-inline power-actions-form'}>
+ {header}
+ {Forms.createButton(
+ (this.props.power.wait ? 'no wait' : 'wait'),
+ this.props.onSetWaitFlag,
+ (this.props.power.wait ? 'success' : 'danger')
+ )}
+ {votes}
+ <HotKey keys={['escape']} onKeysCoincide={onReset}/>
+ {this.props.orderTypes.map((letter, index) => (
+ <HotKey key={index} keys={[letter.toLowerCase()]} onKeysCoincide={() => onSetOrderType(letter)}/>
+ ))}
+ </form>
+ );
+ }
+}
+
+PowerActionsForm.propTypes = {
+ orderType: PropTypes.oneOf(Object.keys(ORDER_BUILDER)),
+ orderTypes: PropTypes.arrayOf(PropTypes.oneOf(Object.keys(ORDER_BUILDER))),
+ power: PropTypes.instanceOf(Power),
+ role: PropTypes.string,
+ onChange: PropTypes.func,
+ onSubmit: PropTypes.func,
+ onNoOrders: PropTypes.func, // onNoOrders()
+ onVote: PropTypes.func, // onVote(voteString)
+ onSetWaitFlag: PropTypes.func, // onSetWaitFlag(),
+};
diff --git a/diplomacy/web/src/gui/diplomacy/forms/select_location_form.jsx b/diplomacy/web/src/gui/diplomacy/forms/select_location_form.jsx
new file mode 100644
index 0000000..3c55e49
--- /dev/null
+++ b/diplomacy/web/src/gui/diplomacy/forms/select_location_form.jsx
@@ -0,0 +1,36 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import React from "react";
+import PropTypes from "prop-types";
+import {Button} from "../../core/widgets";
+
+export class SelectLocationForm extends React.Component {
+ render() {
+ return (
+ <div>
+ {this.props.locations.map((location, index) => (
+ <Button key={index} title={location} large={true} onClick={() => this.props.onSelect(location)}/>
+ ))}
+ </div>
+ );
+ }
+}
+
+SelectLocationForm.propTypes = {
+ locations: PropTypes.arrayOf(PropTypes.string).isRequired,
+ onSelect: PropTypes.func.isRequired // onSelect(location)
+};
diff --git a/diplomacy/web/src/gui/diplomacy/forms/select_via_form.jsx b/diplomacy/web/src/gui/diplomacy/forms/select_via_form.jsx
new file mode 100644
index 0000000..cc62fe2
--- /dev/null
+++ b/diplomacy/web/src/gui/diplomacy/forms/select_via_form.jsx
@@ -0,0 +1,35 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import React from "react";
+import PropTypes from "prop-types";
+import {Button} from "../../core/widgets";
+
+export class SelectViaForm extends React.Component {
+ render() {
+ return (
+ <div>
+ <Button title={'regular move (M)'} large={true} onClick={() => this.props.onSelect('M')}/>
+ <Button title={'move via (V)'} large={true} onClick={() => this.props.onSelect('V')}/>
+ </div>
+ );
+ }
+}
+
+SelectViaForm.propTypes = {
+ onSelect: PropTypes.func.isRequired
+};
+
diff --git a/diplomacy/web/src/gui/diplomacy/map/dom_order_builder.js b/diplomacy/web/src/gui/diplomacy/map/dom_order_builder.js
new file mode 100644
index 0000000..8b7072e
--- /dev/null
+++ b/diplomacy/web/src/gui/diplomacy/map/dom_order_builder.js
@@ -0,0 +1,278 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import {UTILS} from "../../../diplomacy/utils/utils";
+import $ from "jquery";
+import {extendOrderBuilding} from "../utils/order_building";
+import {Diplog} from "../../../diplomacy/utils/diplog";
+
+function parseLocation(txt) {
+ if (txt.length > 2 && txt[1] === ' ' && ['A', 'F'].includes(txt[0]))
+ return txt.substr(2);
+ return txt;
+}
+
+export class DOMOrderBuilder {
+
+ constructor(svgElement, onOrderBuilding, onOrderBuilt, onSelectLocation, onSelectVia, onError) {
+ this.svg = svgElement;
+ this.cbOrderBuilding = onOrderBuilding;
+ this.cbOrderBuilt = onOrderBuilt;
+ this.cbSelectLocation = onSelectLocation;
+ this.cbSelectVia = onSelectVia;
+ this.cbError = onError;
+
+ this.game = null;
+ this.mapData = null;
+ this.orderBuilding = null;
+
+ this.provinceColors = {};
+ this.clickedID = null;
+ this.clickedNeighbors = [];
+
+ this.onProvinceClick = this.onProvinceClick.bind(this);
+ this.onLabelClick = this.onLabelClick.bind(this);
+ this.onUnitClick = this.onUnitClick.bind(this);
+ }
+
+ saveProvinceColors() {
+ // Get province colors.
+ const elements = this.svg.getElementsByTagName('path');
+ for (let element of elements) {
+ this.provinceColors[element.id] = element.getAttribute('class');
+ }
+ }
+
+ provinceNameToMapID(name) {
+ return `_${name.toLowerCase()}___${this.svg.parentNode.id}`;
+ }
+
+ mapID(id) {
+ return `${id}___${this.svg.parentNode.id}`;
+ }
+
+ onOrderBuilding(svgPath, powerName, orderPath) {
+ this.cbOrderBuilding(powerName, orderPath);
+ }
+
+ onOrderBuilt(svgPath, powerName, orderString) {
+ this.cbOrderBuilt(powerName, orderString);
+ }
+
+ onError(svgPath, error) {
+ this.cbError(error.toString());
+ }
+
+ handleSvgPath(svgPath) {
+ const orderBuilding = this.orderBuilding;
+ if (!orderBuilding.builder)
+ return this.onError(svgPath, 'No orderable locations.');
+
+ const province = this.mapData.getProvince(svgPath.id);
+ if (!province)
+ return;
+
+ const stepLength = orderBuilding.builder.steps.length;
+ if (orderBuilding.path.length >= stepLength)
+ throw new Error(`Order building: current steps count (${orderBuilding.path.length}) should be less than` +
+ ` expected steps count (${stepLength}) (${orderBuilding.path.join(', ')}).`);
+
+ const lengthAfterClick = orderBuilding.path.length + 1;
+ let validLocations = [];
+ const testedPath = [orderBuilding.type].concat(orderBuilding.path);
+ const value = UTILS.javascript.getTreeValue(this.game.ordersTree, testedPath);
+ if (value !== null) {
+ const checker = orderBuilding.builder.steps[lengthAfterClick - 1];
+ try {
+ const possibleLocations = checker(province, orderBuilding.power);
+ for (let possibleLocation of possibleLocations) {
+ possibleLocation = possibleLocation.toUpperCase();
+ if (value.includes(possibleLocation))
+ validLocations.push(possibleLocation);
+ }
+ } catch (error) {
+ return this.onError(svgPath, error);
+ }
+ }
+ if (!validLocations.length)
+ return this.onError(svgPath, 'Disallowed.');
+
+ if (validLocations.length > 1 && orderBuilding.type === 'S' && orderBuilding.path.length >= 2) {
+ // We are building a support order and we have a multiple choice for a location.
+ // Let's check if next location to choose is a coast. To have a coast:
+ // - all possible locations must start with same 3 characters.
+ // - we expect at least province name in possible locations (e.g. 'SPA' for 'SPA/NC').
+ // If we have a coast, we will remove province name from possible locations.
+ let isACoast = true;
+ let validLocationsNoProvinceName = [];
+ for (let i = 0; i < validLocations.length; ++i) {
+ let location = validLocations[i];
+ if (i > 0) {
+ // Compare 3 first letters with previous location.
+ if (validLocations[i - 1].substring(0, 3).toUpperCase() !== validLocations[i].substring(0, 3).toUpperCase()) {
+ // No same prefix with previous location. We does not have a coast.
+ isACoast = false;
+ break;
+ }
+ }
+ if (location.length !== 3)
+ validLocationsNoProvinceName.push(location);
+ }
+ if (validLocations.length === validLocationsNoProvinceName.length) {
+ // We have not found province name.
+ isACoast = false;
+ }
+ if (isACoast) {
+ // We want to choose location in a coastal province. Let's remove province name.
+ validLocations = validLocationsNoProvinceName;
+ }
+ }
+
+ if (validLocations.length > 1) {
+ if (this.cbSelectLocation) {
+ return this.cbSelectLocation(validLocations, orderBuilding.power, orderBuilding.type, orderBuilding.path);
+ } else {
+ Diplog.warn(`Forced to select first valid location.`);
+ validLocations = [validLocations[0]];
+ }
+ }
+ let orderBuildingType = orderBuilding.type;
+ if (lengthAfterClick === stepLength && orderBuildingType === 'M') {
+ const moveOrderPath = ['M'].concat(orderBuilding.path, validLocations[0]);
+ const moveTypes = UTILS.javascript.getTreeValue(this.game.ordersTree, moveOrderPath);
+ if (moveTypes !== null) {
+ if (moveTypes.length === 2) {
+ // This move can be done either regularly or VIA a fleet. Let user choose.
+ return this.cbSelectVia(validLocations[0], orderBuilding.power, orderBuilding.path);
+ } else {
+ orderBuildingType = moveTypes[0];
+ }
+ }
+ }
+ this.clickedID = svgPath.id;
+
+ this.cleanBuildingView();
+ if (lengthAfterClick < stepLength)
+ this.renderBuildingView(validLocations[0]);
+ extendOrderBuilding(
+ orderBuilding.power, orderBuildingType, orderBuilding.path, validLocations[0],
+ this.cbOrderBuilding, this.cbOrderBuilt, this.cbError
+ );
+
+ }
+
+ getPathFromProvince(province) {
+ let path = this.svg.getElementById(this.provinceNameToMapID(province.name));
+ if (!path) {
+ for (let alias of province.aliases) {
+ path = this.svg.getElementById(this.provinceNameToMapID(alias));
+ if (path)
+ break;
+ }
+ }
+ return path;
+ }
+
+ onProvinceClick(event) {
+ this.handleSvgPath(event.target);
+ }
+
+ onLabelClick(event) {
+ const province = this.mapData.getProvince(event.target.textContent);
+ if (province) {
+ const path = this.getPathFromProvince(province);
+ if (path)
+ this.handleSvgPath(path);
+ }
+ }
+
+ onUnitClick(event) {
+ const province = this.mapData.getProvince(event.target.getAttribute('diplomacyUnit'));
+ if (province) {
+ let path = this.getPathFromProvince(province);
+ if (!path && province.isCoast())
+ path = this.svg.getElementById(this.provinceNameToMapID(province.parent.name));
+ if (path) {
+ this.handleSvgPath(path);
+ }
+ }
+ }
+
+ cleanBuildingView() {
+ if (this.clickedID) {
+ const path = this.svg.getElementById(this.clickedID);
+ if (path)
+ path.setAttribute('class', this.provinceColors[this.clickedID]);
+ }
+ for (let neighborName of this.clickedNeighbors) {
+ const province = this.mapData.getProvince(neighborName);
+ if (!province)
+ continue;
+ const path = this.getPathFromProvince(province);
+ if (path)
+ path.setAttribute('class', this.provinceColors[path.id]);
+ }
+ this.clickedNeighbors = [];
+ }
+
+ renderBuildingView(extraLocation) {
+ if (this.clickedID) {
+ const path = this.svg.getElementById(this.clickedID);
+ if (path)
+ path.setAttribute('class', 'provinceRed');
+ }
+ const selectedPath = [this.orderBuilding.type].concat(this.orderBuilding.path);
+ if (extraLocation)
+ selectedPath.push(extraLocation);
+ const possibleNeighbors = UTILS.javascript.getTreeValue(this.game.ordersTree, selectedPath);
+ if (!possibleNeighbors)
+ return;
+ this.clickedNeighbors = possibleNeighbors.map(neighbor => parseLocation(neighbor));
+ if (this.clickedNeighbors.length) {
+ for (let neighbor of this.clickedNeighbors) {
+ let neighborProvince = this.mapData.getProvince(neighbor);
+ if (!neighborProvince)
+ throw new Error('Unknown neighbor province ' + neighbor);
+ let path = this.getPathFromProvince(neighborProvince);
+ if (!path && neighborProvince.isCoast())
+ path = this.getPathFromProvince(neighborProvince.parent);
+ if (!path)
+ throw new Error(`Unable to find SVG path related to province ${neighborProvince.name}.`);
+ path.setAttribute('class', neighborProvince.isWater() ? 'provinceBlue' : 'provinceGreen');
+ }
+ }
+ }
+
+ update(game, mapData, orderBuilding) {
+ this.game = game;
+ this.mapData = mapData;
+ this.orderBuilding = orderBuilding;
+ this.saveProvinceColors();
+ // If there is a building path, then we are building, so we don't clean anything.
+ this.cleanBuildingView();
+ if (this.orderBuilding.path.length)
+ this.renderBuildingView();
+ // I don't yet know why I should place this here. Maybe because unit are re-rendered manually at every reloading ?
+ $(`#${this.svg.parentNode.id} svg use[diplomacyUnit]`).click(this.onUnitClick);
+ }
+
+ init(game, mapData, orderBuilding) {
+ $(`#${this.svg.parentNode.id} svg path`).click(this.onProvinceClick);
+ $(`#${this.mapID('BriefLabelLayer')} text`).click(this.onLabelClick);
+ this.update(game, mapData, orderBuilding);
+ }
+
+}
diff --git a/diplomacy/web/src/gui/diplomacy/map/dom_past_map.js b/diplomacy/web/src/gui/diplomacy/map/dom_past_map.js
new file mode 100644
index 0000000..58fd6c8
--- /dev/null
+++ b/diplomacy/web/src/gui/diplomacy/map/dom_past_map.js
@@ -0,0 +1,112 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import $ from "jquery";
+
+export class DOMPastMap {
+
+ constructor(svgElement, onHover) {
+ this.svg = svgElement;
+ this.cbHover = onHover;
+ this.game = null;
+ this.orders = null;
+ this.mapData = null;
+ this.onProvinceHover = this.onProvinceHover.bind(this);
+ this.onLabelHover = this.onLabelHover.bind(this);
+ this.onUnitHover = this.onUnitHover.bind(this);
+ }
+
+ provinceNameToMapID(name) {
+ return `_${name.toLowerCase()}___${this.svg.parentNode.id}`;
+ }
+
+ mapID(id) {
+ return `${id}___${this.svg.parentNode.id}`;
+ }
+
+ onHover(name) {
+ const orders = [];
+ if (this.orders) {
+ for (let powerOrders of Object.values(this.orders)) {
+ for (let order of powerOrders) {
+ const pieces = order.split(/ +/);
+ if (pieces[1].slice(0, 3) === name.toUpperCase().slice(0, 3))
+ orders.push(order);
+ }
+ }
+ }
+ return orders;
+ }
+
+ handleSvgPath(svgPath) {
+ const province = this.mapData.getProvince(svgPath.id);
+ if (province) {
+ this.cbHover(province.name, this.onHover(province.name));
+ }
+ }
+
+ getPathFromProvince(province) {
+ let path = this.svg.getElementById(this.provinceNameToMapID(province.name));
+ if (!path) {
+ for (let alias of province.aliases) {
+ path = this.svg.getElementById(this.provinceNameToMapID(alias));
+ if (path)
+ break;
+ }
+ }
+ return path;
+ }
+
+ onProvinceHover(event) {
+ this.handleSvgPath(event.target);
+ }
+
+ onLabelHover(event) {
+ const province = this.mapData.getProvince(event.target.textContent);
+ if (province) {
+ const path = this.getPathFromProvince(province);
+ if (path)
+ this.handleSvgPath(path);
+ }
+ }
+
+ onUnitHover(event) {
+ const province = this.mapData.getProvince(event.target.getAttribute('diplomacyUnit'));
+ if (province) {
+ let path = this.getPathFromProvince(province);
+ if (!path && province.isCoast())
+ path = this.svg.getElementById(this.provinceNameToMapID(province.parent.name));
+ if (path) {
+ this.handleSvgPath(path);
+ }
+ }
+ }
+
+ update(game, mapData, orders) {
+ this.game = game;
+ this.mapData = mapData;
+ this.orders = orders;
+ // I don't yet know why I should place this here. Maybe because unit are re-rendered manually at every reloading ?
+ $(`#${this.svg.parentNode.id} svg use[diplomacyUnit]`).hover(this.onUnitHover);
+ }
+
+ init(game, mapData, orders) {
+ $(`#${this.svg.parentNode.id} svg path`).hover(this.onProvinceHover).mouseleave(() => this.cbHover(null, null));
+ $(`#${this.mapID('BriefLabelLayer')} text`).hover(this.onLabelHover);
+ this.update(game, mapData, orders);
+ }
+
+}
diff --git a/diplomacy/web/src/gui/diplomacy/map/map.jsx b/diplomacy/web/src/gui/diplomacy/map/map.jsx
new file mode 100644
index 0000000..2a2949f
--- /dev/null
+++ b/diplomacy/web/src/gui/diplomacy/map/map.jsx
@@ -0,0 +1,94 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import React from "react";
+import SVG from 'react-inlinesvg';
+import mapSVG from '../../../standard.svg';
+import {Renderer} from "./renderer";
+import {MapData} from "../utils/map_data";
+import {DOMOrderBuilder} from "./dom_order_builder";
+import PropTypes from 'prop-types';
+import {DOMPastMap} from "./dom_past_map";
+
+export class Map extends React.Component {
+ // id: ID of div wrapping SVG map.
+ // mapInfo: dict
+ // game: game engine
+ // onError: callback(error)
+ // showOrders: bool
+
+ // orderBuilding: dict
+ // onOrderBuilding: callback(powerName, orderBuildingPath)
+ // onOrderBuilt: callback(powerName, orderString)
+
+ constructor(props) {
+ super(props);
+ this.renderer = null;
+ this.domOrderBuilder = null;
+ this.domPastMap = null;
+ this.initSVG = this.initSVG.bind(this);
+ }
+
+ initSVG() {
+ const svg = document.getElementById(this.props.id).getElementsByTagName('svg')[0];
+
+ const game = this.props.game;
+ const mapData = new MapData(this.props.mapInfo, game);
+ this.renderer = new Renderer(svg, game, mapData);
+ this.renderer.render(this.props.showOrders, this.props.orders);
+ if (this.props.orderBuilding) {
+ this.domOrderBuilder = new DOMOrderBuilder(
+ svg,
+ this.props.onOrderBuilding, this.props.onOrderBuilt, this.props.onSelectLocation, this.props.onSelectVia,
+ this.props.onError
+ );
+ this.domOrderBuilder.init(game, mapData, this.props.orderBuilding);
+ } else if (this.props.onHover) {
+ this.domPastMap = new DOMPastMap(svg, this.props.onHover);
+ this.domPastMap.init(game, mapData, this.props.orders);
+ }
+ }
+
+ render() {
+ if (this.renderer) {
+ const game = this.props.game;
+ const mapData = new MapData(this.props.mapInfo, game);
+ this.renderer.update(game, mapData, this.props.showOrders, this.props.orders);
+ if (this.domOrderBuilder)
+ this.domOrderBuilder.update(game, mapData, this.props.orderBuilding);
+ else if (this.domPastMap)
+ this.domPastMap.update(game, mapData, this.props.orders);
+ }
+ const divFactory = ((props, children) => <div id={this.props.id} {...props}>{children}</div>);
+ return <SVG wrapper={divFactory} uniquifyIDs={true} uniqueHash={this.props.id} src={mapSVG}
+ onLoad={this.initSVG} onError={err => this.props.onError(err.message)}>Game map</SVG>;
+ }
+}
+
+Map.propTypes = {
+ id: PropTypes.string,
+ showOrders: PropTypes.bool,
+ orders: PropTypes.objectOf(PropTypes.arrayOf(PropTypes.string)),
+ onSelectLocation: PropTypes.func,
+ onSelectVia: PropTypes.func,
+ game: PropTypes.object,
+ mapInfo: PropTypes.object,
+ orderBuilding: PropTypes.object,
+ onOrderBuilding: PropTypes.func,
+ onOrderBuilt: PropTypes.func,
+ onError: PropTypes.func,
+ onHover: PropTypes.func,
+};
diff --git a/diplomacy/web/src/gui/diplomacy/map/renderer.js b/diplomacy/web/src/gui/diplomacy/map/renderer.js
new file mode 100644
index 0000000..e2586af
--- /dev/null
+++ b/diplomacy/web/src/gui/diplomacy/map/renderer.js
@@ -0,0 +1,615 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import $ from "jquery";
+
+const ARMY = 'Army';
+const FLEET = 'Fleet';
+// SVG tag names.
+const PREFIX_TAG = 'jdipNS'.toLowerCase();
+const TAG_ORDERDRAWING = 'jdipNS:ORDERDRAWING'.toLowerCase();
+const TAG_POWERCOLORS = 'jdipNS:POWERCOLORS'.toLowerCase();
+const TAG_POWERCOLOR = 'jdipNS:POWERCOLOR'.toLowerCase();
+const TAG_SYMBOLSIZE = 'jdipNS:SYMBOLSIZE'.toLowerCase();
+const TAG_PROVINCE_DATA = 'jdipNS:PROVINCE_DATA'.toLowerCase();
+const TAG_PROVINCE = 'jdipNS:PROVINCE'.toLowerCase();
+const TAG_UNIT = 'jdipNS:UNIT'.toLowerCase();
+const TAG_DISLODGED_UNIT = 'jdipNS:DISLODGED_UNIT'.toLowerCase();
+const TAG_SUPPLY_CENTER = 'jdipNS:SUPPLY_CENTER'.toLowerCase();
+const TAG_DISPLAY = 'jdipNS:DISPLAY'.toLowerCase();
+
+function attr(node, name) {
+ return node.attributes[name].value;
+}
+
+function offset(floatString, offset) {
+ return "" + (parseFloat(floatString) + offset);
+}
+
+export class Renderer {
+ constructor(svgDomElement, game, mapData) {
+ this.svg = svgDomElement;
+ this.game = game;
+ this.mapData = mapData;
+ this.metadata = {
+ color: {},
+ symbol_size: {},
+ orders: {},
+ coord: {}
+ };
+ this.initialInfluences = {};
+ this.__load_metadata();
+ this.__save_initial_influences();
+ }
+
+ __hashed_id(id) {
+ return `${id}___${this.svg.parentNode.id}`;
+ }
+
+ __svg_element_from_id(id) {
+ const hashedID = this.__hashed_id(id);
+ const element = this.svg.getElementById(hashedID);
+ if (!element)
+ throw new Error(`Unable to find ID ${id} (looked for hashed ID ${hashedID})`);
+ return element;
+ }
+
+ __load_metadata() {
+ // Order drawings.
+ const order_drawings = this.svg.getElementsByTagName(TAG_ORDERDRAWING);
+ if (!order_drawings.length)
+ throw new Error('Unable to find order drawings (tag ' + TAG_ORDERDRAWING + ') in SVG map.');
+ for (let order_drawing of order_drawings) {
+ for (let child_node of order_drawing.childNodes) {
+ if (child_node.nodeName === TAG_POWERCOLORS) {
+ // Power colors.
+ for (let power_color of child_node.childNodes) {
+ if (power_color.nodeName === TAG_POWERCOLOR) {
+ this.metadata.color[attr(power_color, 'power').toUpperCase()] = attr(power_color, 'color');
+ }
+ }
+ } else if (child_node.nodeName === TAG_SYMBOLSIZE) {
+ // Symbol size.
+ this.metadata.symbol_size[attr(child_node, 'name')] = [attr(child_node, 'height'), attr(child_node, 'width')];
+ } else if (child_node.nodeName.startsWith(PREFIX_TAG)) {
+ // Order type.
+ const order_type = child_node.nodeName.replace(PREFIX_TAG + ':', '');
+ this.metadata.orders[order_type] = {};
+ for (let attribute of child_node.attributes) {
+ if (!attribute.name.includes(':')) {
+ this.metadata.orders[order_type][attribute.name] = attribute.value;
+ }
+ }
+ }
+ }
+ }
+ // Object coordinates.
+ const all_province_data = this.svg.getElementsByTagName(TAG_PROVINCE_DATA);
+ if (!all_province_data.length)
+ throw new Error('Unable to find province data in SVG map (tag ' + TAG_PROVINCE_DATA + ').');
+ for (let province_data of all_province_data) {
+ for (let child_node of province_data.childNodes) {
+ // Province.
+ if (child_node.nodeName === TAG_PROVINCE) {
+ const province = attr(child_node, 'name').toUpperCase().replace('-', '/');
+ this.metadata.coord[province] = {};
+ for (let coord_node of child_node.childNodes) {
+ if (coord_node.nodeName === TAG_UNIT) {
+ this.metadata.coord[province].unit = [attr(coord_node, 'x'), attr(coord_node, 'y')];
+ } else if (coord_node.nodeName === TAG_DISLODGED_UNIT) {
+ this.metadata.coord[province].disl = [attr(coord_node, 'x'), attr(coord_node, 'y')];
+ } else if (coord_node.nodeName === TAG_SUPPLY_CENTER) {
+ this.metadata.coord[province].sc = [attr(coord_node, 'x'), attr(coord_node, 'y')];
+ }
+ }
+ }
+ }
+ }
+ // Deleting.
+ this.svg.removeChild(this.svg.getElementsByTagName(TAG_DISPLAY)[0]);
+ this.svg.removeChild(this.svg.getElementsByTagName(TAG_ORDERDRAWING)[0]);
+ this.svg.removeChild(this.svg.getElementsByTagName(TAG_PROVINCE_DATA)[0]);
+
+ // (this code was previously in render())
+ // Removing mouse layer.
+ this.svg.removeChild(this.__svg_element_from_id('MouseLayer'));
+ }
+
+ __save_initial_influences() {
+ const mapLayer = this.__svg_element_from_id('MapLayer');
+ if (!mapLayer)
+ throw new Error('Unable to find map layer.');
+ for (let element of mapLayer.childNodes) {
+ if (element.tagName === 'path') {
+ this.initialInfluences[element.id] = element.getAttribute('class');
+ }
+ }
+ }
+
+ __restore_initial_influences() {
+ for (let id of Object.keys(this.initialInfluences)) {
+ const className = this.initialInfluences[id];
+ this.svg.getElementById(id).setAttribute('class', className);
+ }
+ }
+
+ __set_current_phase() {
+ const current_phase = (this.game.phase[0] === '?' || this.game.phase === 'COMPLETED') ? 'FINAL' : this.game.phase;
+ const phase_display = this.__svg_element_from_id('CurrentPhase');
+ if (phase_display) {
+ phase_display.childNodes[0].nodeValue = current_phase;
+ }
+ }
+
+ __set_note(note1, note2) {
+ note1 = note1 || '';
+ note2 = note2 || '';
+ const display_note1 = this.__svg_element_from_id('CurrentNote');
+ const display_note2 = this.__svg_element_from_id('CurrentNote2');
+ if (display_note1)
+ display_note1.childNodes[0].nodeValue = note1;
+ if (display_note2)
+ display_note2.childNodes[0].nodeValue = note2;
+ }
+
+ __add_unit(unit, power_name, is_dislogged) {
+ const split_unit = unit.split(/ +/);
+ const unit_type = split_unit[0];
+ const loc = split_unit[1];
+ const dislogged_type = is_dislogged ? 'disl' : 'unit';
+ const symbol = unit_type === 'F' ? FLEET : ARMY;
+ const loc_x = offset(this.metadata.coord[loc][dislogged_type][0], -11.5);
+ const loc_y = offset(this.metadata.coord[loc][dislogged_type][1], -10.0);
+ // Helpful link about creating SVG elements: https://stackoverflow.com/a/25949237
+ const node = document.createElementNS("http://www.w3.org/2000/svg", 'use');
+ node.setAttributeNS('http://www.w3.org/1999/xlink', 'href', '#' + this.__hashed_id((is_dislogged ? 'Dislodged' : '') + symbol));
+ node.setAttribute('x', loc_x);
+ node.setAttribute('y', loc_y);
+ node.setAttribute('height', this.metadata.symbol_size[symbol][0]);
+ node.setAttribute('width', this.metadata.symbol_size[symbol][1]);
+ node.setAttribute('class', 'unit' + power_name.toLowerCase());
+ node.setAttribute('diplomacyUnit', loc);
+ const parent_node = this.__svg_element_from_id(is_dislogged ? 'DislodgedUnitLayer' : 'UnitLayer');
+ if (parent_node)
+ parent_node.appendChild(node);
+ }
+
+ __add_supply_center(loc, power_name) {
+ const symbol = 'SupplyCenter';
+ const loc_x = offset(this.metadata.coord[loc]['sc'][0], -8.5);
+ const loc_y = offset(this.metadata.coord[loc]['sc'][1], -11.0);
+ const node = document.createElementNS("http://www.w3.org/2000/svg", 'use');
+ node.setAttributeNS('http://www.w3.org/1999/xlink', 'href', '#' + this.__hashed_id(symbol));
+ node.setAttribute('x', loc_x);
+ node.setAttribute('y', loc_y);
+ node.setAttribute('height', this.metadata.symbol_size[symbol][0]);
+ node.setAttribute('width', this.metadata.symbol_size[symbol][1]);
+ node.setAttribute('class', power_name ? ('sc' + power_name.toLowerCase()) : 'scnopower');
+ const parent_node = this.__svg_element_from_id('SupplyCenterLayer');
+ if (parent_node)
+ parent_node.appendChild(node);
+ }
+
+ __set_influence(loc, power_name) {
+ loc = loc.toUpperCase().substr(0, 3);
+ if (!['LAND', 'COAST'].includes(this.mapData.getProvince(loc).type))
+ return;
+ const path = this.__svg_element_from_id('_' + loc.toLowerCase());
+ if (!path || path.nodeName !== 'path') {
+ throw new Error(`Unable to find SVG path for loc ${loc}, got ${path ? path.nodeName : '(nothing)'}`);
+ }
+ path.setAttribute('class', power_name ? power_name.toLowerCase() : 'nopower');
+ }
+
+ issueHoldOrder(loc, power_name) {
+ const polygon_coord = [];
+ const loc_x = offset(this.metadata['coord'][loc]['unit'][0], 8.5);
+ const loc_y = offset(this.metadata['coord'][loc]['unit'][1], 9.5);
+ for (let ofs of [
+ [13.8, -33.3], [33.3, -13.8], [33.3, 13.8], [13.8, 33.3], [-13.8, 33.3],
+ [-33.3, 13.8], [-33.3, -13.8], [-13.8, -33.3]]
+ ) {
+ polygon_coord.push(offset(loc_x, ofs[0]) + ',' + offset(loc_y, ofs[1]));
+ }
+ const g_node = document.createElementNS("http://www.w3.org/2000/svg", 'g');
+ const poly_1 = document.createElementNS("http://www.w3.org/2000/svg", 'polygon');
+ const poly_2 = document.createElementNS("http://www.w3.org/2000/svg", 'polygon');
+ poly_1.setAttribute('stroke-width', '10');
+ poly_1.setAttribute('class', 'varwidthshadow');
+ poly_1.setAttribute('points', polygon_coord.join(' '));
+ poly_2.setAttribute('stroke-width', '6');
+ poly_2.setAttribute('class', 'varwidthorder');
+ poly_2.setAttribute('points', polygon_coord.join(' '));
+ poly_2.setAttribute('stroke', this.metadata['color'][power_name]);
+ g_node.appendChild(poly_1);
+ g_node.appendChild(poly_2);
+ const orderLayer = this.__svg_element_from_id('Layer1');
+ if (!orderLayer)
+ throw new Error(`Unable to find svg order layer.`);
+ orderLayer.appendChild(g_node);
+ }
+
+ issueMoveOrder(src_loc, dest_loc, power_name) {
+ let src_loc_x = 0;
+ let src_loc_y = 0;
+ const phaseType = this.game.getPhaseType();
+ if (phaseType === 'R') {
+ src_loc_x = offset(this.metadata.coord[src_loc]['unit'][0], -2.5);
+ src_loc_y = offset(this.metadata.coord[src_loc]['unit'][1], -2.5);
+ } else {
+ src_loc_x = offset(this.metadata.coord[src_loc]['unit'][0], 10);
+ src_loc_y = offset(this.metadata.coord[src_loc]['unit'][1], 10);
+ }
+ let dest_loc_x = offset(this.metadata.coord[dest_loc]['unit'][0], 10);
+ let dest_loc_y = offset(this.metadata.coord[dest_loc]['unit'][1], 10);
+
+ // Adjusting destination
+ const delta_x = parseFloat(dest_loc_x) - parseFloat(src_loc_x);
+ const delta_y = parseFloat(dest_loc_y) - parseFloat(src_loc_y);
+ const vector_length = Math.sqrt(delta_x * delta_x + delta_y * delta_y);
+ dest_loc_x = '' + Math.round((parseFloat(src_loc_x) + (vector_length - 30.) / vector_length * delta_x) * 100.) / 100.;
+ dest_loc_y = '' + Math.round((parseFloat(src_loc_y) + (vector_length - 30.) / vector_length * delta_y) * 100.) / 100.;
+
+ // Creating nodes.
+ const g_node = document.createElementNS("http://www.w3.org/2000/svg", 'g');
+ const line_with_shadow = document.createElementNS("http://www.w3.org/2000/svg", 'line');
+ const line_with_arrow = document.createElementNS("http://www.w3.org/2000/svg", 'line');
+ line_with_shadow.setAttribute('x1', src_loc_x);
+ line_with_shadow.setAttribute('y1', src_loc_y);
+ line_with_shadow.setAttribute('x2', dest_loc_x);
+ line_with_shadow.setAttribute('y2', dest_loc_y);
+ line_with_shadow.setAttribute('class', 'varwidthshadow');
+ line_with_shadow.setAttribute('stroke-width', '10');
+ line_with_arrow.setAttribute('x1', src_loc_x);
+ line_with_arrow.setAttribute('y1', src_loc_y);
+ line_with_arrow.setAttribute('x2', dest_loc_x);
+ line_with_arrow.setAttribute('y2', dest_loc_y);
+ line_with_arrow.setAttribute('class', 'varwidthorder');
+ line_with_arrow.setAttribute('marker-end', 'url(#' + this.__hashed_id('arrow') + ')');
+ line_with_arrow.setAttribute('stroke', this.metadata.color[power_name]);
+ line_with_arrow.setAttribute('stroke-width', '6');
+ g_node.appendChild(line_with_shadow);
+ g_node.appendChild(line_with_arrow);
+ const orderLayer = this.__svg_element_from_id('Layer1');
+ if (!orderLayer)
+ throw new Error(`Unable to find svg order layer.`);
+ orderLayer.appendChild(g_node);
+ }
+
+ issueSupportMoveOrder(loc, src_loc, dest_loc, power_name) {
+ const loc_x = offset(this.metadata['coord'][loc]['unit'][0], 10);
+ const loc_y = offset(this.metadata['coord'][loc]['unit'][1], 10);
+ const src_loc_x = offset(this.metadata['coord'][src_loc]['unit'][0], 10);
+ const src_loc_y = offset(this.metadata['coord'][src_loc]['unit'][1], 10);
+ let dest_loc_x = offset(this.metadata['coord'][dest_loc]['unit'][0], 10);
+ let dest_loc_y = offset(this.metadata['coord'][dest_loc]['unit'][1], 10);
+
+ // Adjusting destination
+ const delta_x = parseFloat(dest_loc_x) - parseFloat(src_loc_x);
+ const delta_y = parseFloat(dest_loc_y) - parseFloat(src_loc_y);
+ const vector_length = Math.sqrt(delta_x * delta_x + delta_y * delta_y);
+ dest_loc_x = '' + Math.round((parseFloat(src_loc_x) + (vector_length - 30.) / vector_length * delta_x) * 100.) / 100.;
+ dest_loc_y = '' + Math.round((parseFloat(src_loc_y) + (vector_length - 30.) / vector_length * delta_y) * 100.) / 100.;
+
+ const g_node = document.createElementNS("http://www.w3.org/2000/svg", 'g');
+ const path_with_shadow = document.createElementNS("http://www.w3.org/2000/svg", 'path');
+ const path_with_arrow = document.createElementNS("http://www.w3.org/2000/svg", 'path');
+ path_with_shadow.setAttribute('class', 'shadowdash');
+ path_with_shadow.setAttribute('d', `M ${loc_x},${loc_y} C ${src_loc_x},${src_loc_y} ${src_loc_x},${src_loc_y} ${dest_loc_x},${dest_loc_y}`);
+ path_with_arrow.setAttribute('class', 'supportorder');
+ path_with_arrow.setAttribute('marker-end', 'url(#' + this.__hashed_id('arrow') + ')');
+ path_with_arrow.setAttribute('stroke', this.metadata['color'][power_name]);
+ path_with_arrow.setAttribute('d', `M ${loc_x},${loc_y} C ${src_loc_x},${src_loc_y} ${src_loc_x},${src_loc_y} ${dest_loc_x},${dest_loc_y}`);
+ g_node.appendChild(path_with_shadow);
+ g_node.appendChild(path_with_arrow);
+ const orderLayer = this.__svg_element_from_id('Layer2');
+ if (!orderLayer)
+ throw new Error(`Unable to find svg order layer.`);
+ orderLayer.appendChild(g_node);
+ }
+
+ issueSupportHoldOrder(loc, dest_loc, power_name) {
+ const loc_x = offset(this.metadata['coord'][loc]['unit'][0], 10);
+ const loc_y = offset(this.metadata['coord'][loc]['unit'][1], 10);
+ let dest_loc_x = offset(this.metadata['coord'][dest_loc]['unit'][0], 10);
+ let dest_loc_y = offset(this.metadata['coord'][dest_loc]['unit'][1], 10);
+
+ const delta_x = parseFloat(dest_loc_x) - parseFloat(loc_x);
+ const delta_y = parseFloat(dest_loc_y) - parseFloat(loc_y);
+ const vector_length = Math.sqrt(delta_x * delta_x + delta_y * delta_y);
+ dest_loc_x = '' + Math.round((parseFloat(loc_x) + (vector_length - 35.) / vector_length * delta_x) * 100.) / 100.;
+ dest_loc_y = '' + Math.round((parseFloat(loc_y) + (vector_length - 35.) / vector_length * delta_y) * 100.) / 100.;
+
+ const polygon_coord = [];
+ const poly_loc_x = offset(this.metadata['coord'][dest_loc]['unit'][0], 8.5);
+ const poly_loc_y = offset(this.metadata['coord'][dest_loc]['unit'][1], 9.5);
+ for (let ofs of [
+ [15.9, -38.3], [38.3, -15.9], [38.3, 15.9], [15.9, 38.3], [-15.9, 38.3], [-38.3, 15.9],
+ [-38.3, -15.9], [-15.9, -38.3]
+ ]) {
+ polygon_coord.push(offset(poly_loc_x, ofs[0]) + ',' + offset(poly_loc_y, ofs[1]));
+ }
+ const g_node = document.createElementNS("http://www.w3.org/2000/svg", 'g');
+ const shadow_line = document.createElementNS("http://www.w3.org/2000/svg", 'line');
+ const support_line = document.createElementNS("http://www.w3.org/2000/svg", 'line');
+ const shadow_poly = document.createElementNS("http://www.w3.org/2000/svg", 'polygon');
+ const support_poly = document.createElementNS("http://www.w3.org/2000/svg", 'polygon');
+ shadow_line.setAttribute('x1', loc_x);
+ shadow_line.setAttribute('y1', loc_y);
+ shadow_line.setAttribute('x2', dest_loc_x);
+ shadow_line.setAttribute('y2', dest_loc_y);
+ shadow_line.setAttribute('class', 'shadowdash');
+ support_line.setAttribute('x1', loc_x);
+ support_line.setAttribute('y1', loc_y);
+ support_line.setAttribute('x2', dest_loc_x);
+ support_line.setAttribute('y2', dest_loc_y);
+ support_line.setAttribute('class', 'supportorder');
+ support_line.setAttribute('stroke', this.metadata['color'][power_name]);
+ shadow_poly.setAttribute('class', 'shadowdash');
+ shadow_poly.setAttribute('points', polygon_coord.join(' '));
+ support_poly.setAttribute('class', 'supportorder');
+ support_poly.setAttribute('points', polygon_coord.join(' '));
+ support_poly.setAttribute('stroke', this.metadata['color'][power_name]);
+ g_node.appendChild(shadow_line);
+ g_node.appendChild(support_line);
+ g_node.appendChild(shadow_poly);
+ g_node.appendChild(support_poly);
+ const orderLayer = this.__svg_element_from_id('Layer2');
+ if (!orderLayer)
+ throw new Error(`Unable to find svg order layer.`);
+ orderLayer.appendChild(g_node);
+ }
+
+ issueConvoyOrder(loc, src_loc, dest_loc, power_name) {
+ const loc_x = offset(this.metadata['coord'][loc]['unit'][0], 10);
+ const loc_y = offset(this.metadata['coord'][loc]['unit'][1], 10);
+ const src_loc_x = offset(this.metadata['coord'][src_loc]['unit'][0], 10);
+ const src_loc_y = offset(this.metadata['coord'][src_loc]['unit'][1], 10);
+ let dest_loc_x = offset(this.metadata['coord'][dest_loc]['unit'][0], 10);
+ let dest_loc_y = offset(this.metadata['coord'][dest_loc]['unit'][1], 10);
+
+ const src_delta_x = parseFloat(src_loc_x) - parseFloat(loc_x);
+ const src_delta_y = parseFloat(src_loc_y) - parseFloat(loc_y);
+ const src_vector_length = Math.sqrt(src_delta_x * src_delta_x + src_delta_y * src_delta_y);
+ const src_loc_x_1 = '' + Math.round((parseFloat(loc_x) + (src_vector_length - 30.) / src_vector_length * src_delta_x) * 100.) / 100.;
+ const src_loc_y_1 = '' + Math.round((parseFloat(loc_y) + (src_vector_length - 30.) / src_vector_length * src_delta_y) * 100.) / 100.;
+
+ let dest_delta_x = parseFloat(src_loc_x) - parseFloat(dest_loc_x);
+ let dest_delta_y = parseFloat(src_loc_y) - parseFloat(dest_loc_y);
+ let dest_vector_length = Math.sqrt(dest_delta_x * dest_delta_x + dest_delta_y * dest_delta_y);
+ const src_loc_x_2 = '' + Math.round((parseFloat(dest_loc_x) + (dest_vector_length - 30.) / dest_vector_length * dest_delta_x) * 100.) / 100.;
+ const src_loc_y_2 = '' + Math.round((parseFloat(dest_loc_y) + (dest_vector_length - 30.) / dest_vector_length * dest_delta_y) * 100.) / 100.;
+
+ dest_delta_x = parseFloat(dest_loc_x) - parseFloat(src_loc_x);
+ dest_delta_y = parseFloat(dest_loc_y) - parseFloat(src_loc_y);
+ dest_vector_length = Math.sqrt(dest_delta_x * dest_delta_x + dest_delta_y * dest_delta_y);
+ dest_loc_x = '' + Math.round((parseFloat(src_loc_x) + (dest_vector_length - 30.) / dest_vector_length * dest_delta_x) * 100.) / 100.;
+ dest_loc_y = '' + Math.round((parseFloat(src_loc_y) + (dest_vector_length - 30.) / dest_vector_length * dest_delta_y) * 100.) / 100.;
+
+ const triangle_coord = [];
+ const triangle_loc_x = offset(this.metadata['coord'][src_loc]['unit'][0], 10);
+ const triangle_loc_y = offset(this.metadata['coord'][src_loc]['unit'][1], 10);
+ for (let ofs of [[0, -38.3], [33.2, 19.1], [-33.2, 19.1]]) {
+ triangle_coord.push(offset(triangle_loc_x, ofs[0]) + ',' + offset(triangle_loc_y, ofs[1]));
+ }
+
+ const g_node = document.createElementNS("http://www.w3.org/2000/svg", 'g');
+ const src_shadow_line = document.createElementNS("http://www.w3.org/2000/svg", 'line');
+ const dest_shadow_line = document.createElementNS("http://www.w3.org/2000/svg", 'line');
+ const src_convoy_line = document.createElementNS("http://www.w3.org/2000/svg", 'line');
+ const dest_convoy_line = document.createElementNS("http://www.w3.org/2000/svg", 'line');
+ const shadow_poly = document.createElementNS("http://www.w3.org/2000/svg", 'polygon');
+ const convoy_poly = document.createElementNS("http://www.w3.org/2000/svg", 'polygon');
+ src_shadow_line.setAttribute('x1', loc_x);
+ src_shadow_line.setAttribute('y1', loc_y);
+ src_shadow_line.setAttribute('x2', src_loc_x_1);
+ src_shadow_line.setAttribute('y2', src_loc_y_1);
+ src_shadow_line.setAttribute('class', 'shadowdash');
+
+ dest_shadow_line.setAttribute('x1', src_loc_x_2);
+ dest_shadow_line.setAttribute('y1', src_loc_y_2);
+ dest_shadow_line.setAttribute('x2', dest_loc_x);
+ dest_shadow_line.setAttribute('y2', dest_loc_y);
+ dest_shadow_line.setAttribute('class', 'shadowdash');
+
+ src_convoy_line.setAttribute('x1', loc_x);
+ src_convoy_line.setAttribute('y1', loc_y);
+ src_convoy_line.setAttribute('x2', src_loc_x_1);
+ src_convoy_line.setAttribute('y2', src_loc_y_1);
+ src_convoy_line.setAttribute('class', 'convoyorder');
+ src_convoy_line.setAttribute('stroke', this.metadata['color'][power_name]);
+
+ dest_convoy_line.setAttribute('x1', src_loc_x_2);
+ dest_convoy_line.setAttribute('y1', src_loc_y_2);
+ dest_convoy_line.setAttribute('x2', dest_loc_x);
+ dest_convoy_line.setAttribute('y2', dest_loc_y);
+ dest_convoy_line.setAttribute('class', 'convoyorder');
+ dest_convoy_line.setAttribute('marker-end', 'url(#' + this.__hashed_id('arrow') + ')');
+
+ dest_convoy_line.setAttribute('stroke', this.metadata['color'][power_name]);
+
+ shadow_poly.setAttribute('class', 'shadowdash');
+ shadow_poly.setAttribute('points', triangle_coord.join(' '));
+
+ convoy_poly.setAttribute('class', 'convoyorder');
+ convoy_poly.setAttribute('points', triangle_coord.join(' '));
+ convoy_poly.setAttribute('stroke', this.metadata['color'][power_name]);
+
+ g_node.appendChild(src_shadow_line);
+ g_node.appendChild(dest_shadow_line);
+ g_node.appendChild(src_convoy_line);
+ g_node.appendChild(dest_convoy_line);
+ g_node.appendChild(shadow_poly);
+ g_node.appendChild(convoy_poly);
+
+ const orderLayer = this.__svg_element_from_id('Layer2');
+ if (!orderLayer)
+ throw new Error(`Unable to find svg order layer.`);
+ orderLayer.appendChild(g_node);
+ }
+
+ issueBuildOrder(unit_type, loc, power_name) {
+ const loc_x = offset(this.metadata['coord'][loc]['unit'][0], -11.5);
+ const loc_y = offset(this.metadata['coord'][loc]['unit'][1], -10.);
+ const build_loc_x = offset(this.metadata['coord'][loc]['unit'][0], -20.5);
+ const build_loc_y = offset(this.metadata['coord'][loc]['unit'][1], -20.5);
+ const symbol = unit_type === 'A' ? ARMY : FLEET;
+ const build_symbol = 'BuildUnit';
+ const g_node = document.createElementNS("http://www.w3.org/2000/svg", 'g');
+ const symbol_node = document.createElementNS("http://www.w3.org/2000/svg", 'use');
+ const build_node = document.createElementNS("http://www.w3.org/2000/svg", 'use');
+ symbol_node.setAttribute('x', loc_x);
+ symbol_node.setAttribute('y', loc_y);
+ symbol_node.setAttribute('height', this.metadata['symbol_size'][symbol][0]);
+ symbol_node.setAttribute('width', this.metadata['symbol_size'][symbol][1]);
+ symbol_node.setAttributeNS('http://www.w3.org/1999/xlink', 'href', '#' + this.__hashed_id(symbol));
+ symbol_node.setAttribute('class', `unit${power_name.toLowerCase()}`);
+ build_node.setAttribute('x', build_loc_x);
+ build_node.setAttribute('y', build_loc_y);
+ build_node.setAttribute('height', this.metadata['symbol_size'][build_symbol][0]);
+ build_node.setAttribute('width', this.metadata['symbol_size'][build_symbol][1]);
+ build_node.setAttributeNS('http://www.w3.org/1999/xlink', 'href', '#' + this.__hashed_id(build_symbol));
+ g_node.appendChild(build_node);
+ g_node.appendChild(symbol_node);
+ const orderLayer = this.__svg_element_from_id('HighestOrderLayer');
+ if (!orderLayer)
+ throw new Error(`Unable to find svg order layer.`);
+ orderLayer.appendChild(g_node);
+ }
+
+ issueDisbandOrder(loc) {
+ const phaseType = this.game.getPhaseType();
+ let loc_x = 0;
+ let loc_y = 0;
+ if (phaseType === 'R') {
+ loc_x = offset(this.metadata['coord'][loc]['unit'][0], -29.);
+ loc_y = offset(this.metadata['coord'][loc]['unit'][1], -27.5);
+ } else {
+ loc_x = offset(this.metadata['coord'][loc]['unit'][0], -16.5);
+ loc_y = offset(this.metadata['coord'][loc]['unit'][1], -15.);
+ }
+ const symbol = 'RemoveUnit';
+ const g_node = document.createElementNS("http://www.w3.org/2000/svg", 'g');
+ const symbol_node = document.createElementNS("http://www.w3.org/2000/svg", 'use');
+ symbol_node.setAttribute('x', loc_x);
+ symbol_node.setAttribute('y', loc_y);
+ symbol_node.setAttribute('height', this.metadata['symbol_size'][symbol][0]);
+ symbol_node.setAttribute('width', this.metadata['symbol_size'][symbol][1]);
+ symbol_node.setAttributeNS('http://www.w3.org/1999/xlink', 'href', '#' + this.__hashed_id(symbol));
+ g_node.appendChild(symbol_node);
+ const orderLayer = this.__svg_element_from_id('HighestOrderLayer');
+ if (!orderLayer)
+ throw new Error(`Unable to find svg order layer.`);
+ orderLayer.appendChild(g_node);
+ }
+
+ clear() {
+ this.__set_note('', '');
+ $(`#${this.__hashed_id('DislodgedUnitLayer')} use`).remove();
+ $(`#${this.__hashed_id('UnitLayer')} use`).remove();
+ $(`#${this.__hashed_id('SupplyCenterLayer')} use`).remove();
+ $(`#${this.__hashed_id('Layer1')} g`).remove();
+ $(`#${this.__hashed_id('Layer2')} g`).remove();
+ $(`#${this.__hashed_id('HighestOrderLayer')} g`).remove();
+ this.__restore_initial_influences();
+ }
+
+ render(includeOrders, orders) {
+ // Setting phase and note.
+ const nb_centers = [];
+ for (let power of Object.values(this.game.powers)) {
+ if (!power.isEliminated())
+ nb_centers.push([power.name.substr(0, 3), power.centers.length]);
+ }
+ // Sort nb_centers by descending number of centers.
+ nb_centers.sort((a, b) => {
+ return -(a[1] - b[1]) || a[0].localeCompare(b[0]);
+ });
+ const nb_centers_per_power = nb_centers.map((couple) => (couple[0] + ': ' + couple[1])).join(' ');
+ this.__set_current_phase();
+ this.__set_note(nb_centers_per_power, this.game.note);
+
+ // Adding units, supply centers, influence and orders.
+ const scs = new Set(this.mapData.supplyCenters);
+ for (let power of Object.values(this.game.powers)) {
+ for (let unit of power.units)
+ this.__add_unit(unit, power.name, false);
+ for (let unit of Object.keys(power.retreats))
+ this.__add_unit(unit, power.name, true);
+ for (let center of power.centers) {
+ this.__add_supply_center(center, power.name);
+ this.__set_influence(center, power.name);
+ scs.delete(center);
+ }
+ if (!power.isEliminated()) {
+ for (let loc of power.influence) {
+ if (!this.mapData.supplyCenters.has(loc))
+ this.__set_influence(loc, power.name);
+ }
+ }
+
+ if (includeOrders) {
+ const powerOrders = (orders && orders.hasOwnProperty(power.name) && orders[power.name]) || [];
+ for (let order of powerOrders) {
+ const tokens = order.split(/ +/);
+ if (!tokens || tokens.length < 3)
+ continue;
+ const unit_loc = tokens[1];
+ if (tokens[2] === 'H')
+ this.issueHoldOrder(unit_loc, power.name);
+ else if (tokens[2] === '-') {
+ const destLoc = tokens[tokens.length - (tokens[tokens.length - 1] === 'VIA' ? 2 : 1)];
+ this.issueMoveOrder(unit_loc, destLoc, power.name);
+ } else if (tokens[2] === 'S') {
+ const destLoc = tokens[tokens.length - 1];
+ if (tokens.includes('-')) {
+ const srcLoc = tokens[4];
+ this.issueSupportMoveOrder(unit_loc, srcLoc, destLoc, power.name);
+ } else {
+ this.issueSupportHoldOrder(unit_loc, destLoc, power.name);
+ }
+ } else if (tokens[2] === 'C') {
+ const srcLoc = tokens[4];
+ const destLoc = tokens[tokens.length - 1];
+ if ((srcLoc !== destLoc) && (tokens.includes('-'))) {
+ this.issueConvoyOrder(unit_loc, srcLoc, destLoc, power.name);
+ }
+ } else if (tokens[2] === 'B') {
+ this.issueBuildOrder(tokens[0], unit_loc, power.name);
+ } else if (tokens[2] === 'D') {
+ this.issueDisbandOrder(unit_loc);
+ } else if (tokens[2] === 'R') {
+ const srcLoc = tokens[1];
+ const destLoc = tokens[3];
+ this.issueMoveOrder(srcLoc, destLoc, power.name);
+ } else {
+ throw new Error(`Unknown error to render (${order}).`);
+ }
+ }
+ }
+ }
+ // Adding remaining supply centers.
+ for (let remainingCenter of scs)
+ this.__add_supply_center(remainingCenter, null);
+ }
+
+ update(game, mapData, showOrders, orders) {
+ this.game = game;
+ this.mapData = mapData;
+ this.clear();
+ this.render(showOrders, orders);
+ }
+}
diff --git a/diplomacy/web/src/gui/diplomacy/utils/dipStorage.jsx b/diplomacy/web/src/gui/diplomacy/utils/dipStorage.jsx
new file mode 100644
index 0000000..db5baad
--- /dev/null
+++ b/diplomacy/web/src/gui/diplomacy/utils/dipStorage.jsx
@@ -0,0 +1,140 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+/* DipStorage scheme:
+global
+- connection
+ - username
+ - hostname
+ - port
+ - showServerFields
+users
+- (username)
+ - games
+ - (game_id)
+ - phase: string
+ - local_orders: {power_name => [orders]}
+*/
+
+let STORAGE = null;
+
+export class DipStorage {
+ static load() {
+ if (!STORAGE) {
+ const global = window.localStorage.global;
+ const users = window.localStorage.users;
+ STORAGE = {
+ global: (global && JSON.parse(global)) || {
+ connection: {
+ username: null,
+ hostname: null,
+ port: null,
+ showServerFields: null
+ }
+ },
+ users: (users && JSON.parse(users)) || {}
+ };
+ }
+ }
+
+ static save() {
+ if (STORAGE) {
+ window.localStorage.global = JSON.stringify(STORAGE.global);
+ window.localStorage.users = JSON.stringify(STORAGE.users);
+ }
+ }
+
+ static getConnectionForm() {
+ DipStorage.load();
+ return Object.assign({}, STORAGE.global.connection);
+ }
+
+ static getUserGames(username) {
+ DipStorage.load();
+ if (STORAGE.users[username])
+ return Object.keys(STORAGE.users[username].games);
+ return null;
+ }
+
+ static getUserGameOrders(username, gameID, gamePhase) {
+ DipStorage.load();
+ if (STORAGE.users[username] && STORAGE.users[username].games[gameID]
+ && STORAGE.users[username].games[gameID].phase === gamePhase)
+ return Object.assign({}, STORAGE.users[username].games[gameID].local_orders);
+ return null;
+ }
+
+ static setConnectionUsername(username) {
+ DipStorage.load();
+ STORAGE.global.connection.username = username;
+ DipStorage.save();
+ }
+
+ static setConnectionHostname(hostname) {
+ DipStorage.load();
+ STORAGE.global.connection.hostname = hostname;
+ DipStorage.save();
+ }
+
+ static setConnectionPort(port) {
+ DipStorage.load();
+ STORAGE.global.connection.port = port;
+ DipStorage.save();
+ }
+
+ static setConnectionshowServerFields(showServerFields) {
+ DipStorage.load();
+ STORAGE.global.connection.showServerFields = showServerFields;
+ DipStorage.save();
+ }
+
+ static addUserGame(username, gameID) {
+ DipStorage.load();
+ if (!STORAGE.users[username])
+ STORAGE.users[username] = {games: {}};
+ if (!STORAGE.users[username].games[gameID])
+ STORAGE.users[username].games[gameID] = {phase: null, local_orders: {}};
+ DipStorage.save();
+ }
+
+ static addUserGameOrders(username, gameID, gamePhase, powerName, orders) {
+ DipStorage.addUserGame(username, gameID);
+ if (STORAGE.users[username].games[gameID].phase !== gamePhase)
+ STORAGE.users[username].games[gameID] = {phase: null, local_orders: {}};
+ STORAGE.users[username].games[gameID].phase = gamePhase;
+ STORAGE.users[username].games[gameID].local_orders[powerName] = orders;
+ DipStorage.save();
+ }
+
+ static removeUserGame(username, gameID) {
+ DipStorage.load();
+ if (STORAGE.users[username] && STORAGE.users[username].games[gameID]) {
+ delete STORAGE.users[username].games[gameID];
+ DipStorage.save();
+ }
+ }
+
+ static clearUserGameOrders(username, gameID, powerName) {
+ DipStorage.addUserGame(username, gameID);
+ if (powerName) {
+ if (STORAGE.users[username].games[gameID].local_orders[powerName])
+ delete STORAGE.users[username].games[gameID].local_orders[powerName];
+ } else {
+ STORAGE.users[username].games[gameID] = {phase: null, local_orders: {}};
+ }
+ DipStorage.save();
+ }
+}
diff --git a/diplomacy/web/src/gui/diplomacy/utils/inline_game_view.jsx b/diplomacy/web/src/gui/diplomacy/utils/inline_game_view.jsx
new file mode 100644
index 0000000..0ada4c9
--- /dev/null
+++ b/diplomacy/web/src/gui/diplomacy/utils/inline_game_view.jsx
@@ -0,0 +1,129 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import React from "react";
+import {Button} from "../../core/widgets";
+import {JoinForm} from "../forms/join_form";
+import {STRINGS} from "../../../diplomacy/utils/strings";
+
+export class InlineGameView {
+ constructor(page, gameData) {
+ this.page = page;
+ this.game = gameData;
+ this.get = this.get.bind(this);
+ this.joinGame = this.joinGame.bind(this);
+ this.showGame = this.showGame.bind(this);
+ }
+
+ joinGame(formData) {
+ const form = {
+ power_name: formData[`power_name_${this.game.game_id}`],
+ registration_password: formData[`registration_password_${this.game.game_id}`]
+ };
+ if (!form.power_name)
+ form.power_name = null;
+ if (!form.registration_password)
+ form.registration_password = null;
+ form.game_id = this.game.game_id;
+ this.page.channel.joinGame(form)
+ .then((networkGame) => {
+ this.game = networkGame.local;
+ this.page.addToMyGames(this.game);
+ return networkGame.getAllPossibleOrders();
+ })
+ .then(allPossibleOrders => {
+ this.game.setPossibleOrders(allPossibleOrders);
+ this.page.loadGame(this.game, {success: 'Game joined.'});
+ })
+ .catch((error) => {
+ this.page.error('Error when joining game ' + this.game.game_id + ': ' + error);
+ });
+ }
+
+ showGame() {
+ this.page.loadGame(this.game);
+ }
+
+ getJoinUI() {
+ if (this.game.role) {
+ // Game already joined.
+ return (
+ <div className={'games-form'}>
+ <Button key={'button-show-' + this.game.game_id} title={'show'} onClick={this.showGame}/>
+ <Button key={'button-leave-' + this.game.game_id} title={'leave'}
+ onClick={() => this.page.leaveGame(this.game.game_id)}/>
+ </div>
+ );
+ } else {
+ // Game not yet joined.
+ return <JoinForm key={this.game.game_id} game_id={this.game.game_id} powers={this.game.controlled_powers}
+ onSubmit={this.joinGame}/>;
+ }
+ }
+
+ getMyGamesButton() {
+ if (this.page.hasMyGame(this.game.game_id)) {
+ if (!this.game.client) {
+ // Game in My Games and not joined. We can remove it.
+ return <Button key={`my-game-remove`} title={'Remove from My Games'}
+ onClick={() => this.page.removeFromMyGames(this.game.game_id)}/>;
+ }
+ } else {
+ // Game not in My Games, we can add it.
+ return <Button key={`my-game-add`} title={'Add to My Games'}
+ onClick={() => this.page.addToMyGames(this.game)}/>;
+ }
+ return '';
+ }
+
+ get(name) {
+ if (name === 'players') {
+ return `${this.game.n_players} / ${this.game.n_controls}`;
+ }
+ if (name === 'rights') {
+ const elements = [];
+ if (this.game.observer_level) {
+ let levelName = '';
+ if (this.game.observer_level === STRINGS.MASTER_TYPE)
+ levelName = 'master';
+ else if (this.game.observer_level === STRINGS.OMNISCIENT_TYPE)
+ levelName = 'omniscient';
+ else
+ levelName = 'observer';
+ elements.push((<p key={0}><strong>Observer right:</strong><br/>{levelName}</p>));
+ }
+ if (this.game.controlled_powers && this.game.controlled_powers.length) {
+ const powers = this.game.controlled_powers.slice();
+ powers.sort();
+ elements.push((
+ <div key={1}><strong>Currently handled power{powers.length === 1 ? '' : 's'}</strong></div>));
+ for (let power of powers)
+ elements.push((<div key={power}>{power}</div>));
+ }
+ return elements.length ? (<div>{elements}</div>) : '';
+ }
+ if (name === 'rules') {
+ if (this.game.rules)
+ return <div>{this.game.rules.map(rule => <div key={rule}>{rule}</div>)}</div>;
+ return '';
+ }
+ if (name === 'join')
+ return this.getJoinUI();
+ if (name === 'my_games')
+ return this.getMyGamesButton();
+ return this.game[name];
+ }
+}
diff --git a/diplomacy/web/src/gui/diplomacy/utils/map_data.js b/diplomacy/web/src/gui/diplomacy/utils/map_data.js
new file mode 100644
index 0000000..73d5338
--- /dev/null
+++ b/diplomacy/web/src/gui/diplomacy/utils/map_data.js
@@ -0,0 +1,98 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import {Province} from "./province";
+
+export class MapData {
+ constructor(mapInfo, game) {
+ // mapInfo: {powers: [], supply_centers: [], aliases: {alias: name}, loc_type: {loc => type}, loc_abut: {loc => [abuts]}}
+ // game: a NetworkGame object.
+ this.game = game;
+ this.powers = new Set(mapInfo.powers);
+ this.supplyCenters = new Set(mapInfo.supply_centers);
+ this.aliases = Object.assign({}, mapInfo.aliases);
+ this.provinces = {};
+ for (let entry of Object.entries(mapInfo.loc_type)) {
+ const provinceName = entry[0];
+ const provinceType = entry[1];
+ this.provinces[provinceName] = new Province(provinceName, provinceType, this.supplyCenters.has(provinceName));
+ }
+ for (let entry of Object.entries(mapInfo.loc_abut)) {
+ this.getProvince(entry[0]).setNeighbors(entry[1].map(name => this.getProvince(name)));
+ }
+ for (let province of Object.values(this.provinces)) {
+ province.setCoasts(this.provinces);
+ }
+ for (let power of Object.values(this.game.powers)) {
+ for (let center of power.centers) {
+ this.getProvince(center).setController(power.name, 'C');
+ }
+ for (let loc of power.influence) {
+ this.getProvince(loc).setController(power.name, 'I');
+ }
+ for (let unit of power.units) {
+ this.__add_unit(unit, power.name);
+ }
+ for (let unit of Object.keys(power.retreats)) {
+ this.__add_retreat(unit, power.name);
+ }
+ }
+ for (let entry of Object.entries(this.aliases)) {
+ const alias = entry[0];
+ const provinceName = entry[1];
+ const province = this.getProvince(provinceName);
+ if (province)
+ province.aliases.push(alias);
+ }
+ }
+
+ __add_unit(unit, power_name) {
+ const splitUnit = unit.split(/ +/);
+ const unitType = splitUnit[0];
+ const location = splitUnit[1];
+ const province = this.getProvince(location);
+ province.setController(power_name, 'U');
+ province.unit = unitType;
+ }
+
+ __add_retreat(unit, power_name) {
+ const splitUnit = unit.split(/ +/);
+ const location = splitUnit[1];
+ const province = this.getProvince(location);
+ province.retreatController = power_name;
+ province.retreatUnit = unit;
+ }
+
+ getProvince(abbr) {
+ if (abbr === '')
+ return null;
+ if (abbr[0] === '_')
+ abbr = abbr.substr(1, 3);
+ if (!abbr)
+ return null;
+ if (!this.provinces.hasOwnProperty(abbr)) {
+ const firstLetter = abbr[0];
+ if (firstLetter === firstLetter.toLowerCase()) {
+ abbr = abbr.toUpperCase();
+ } else {
+ abbr = abbr.toLowerCase();
+ }
+ }
+ if (!this.provinces.hasOwnProperty(abbr))
+ abbr = this.aliases[abbr];
+ return this.provinces[abbr];
+ }
+}
diff --git a/diplomacy/web/src/gui/diplomacy/utils/order.js b/diplomacy/web/src/gui/diplomacy/utils/order.js
new file mode 100644
index 0000000..e314b9f
--- /dev/null
+++ b/diplomacy/web/src/gui/diplomacy/utils/order.js
@@ -0,0 +1,24 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+export class Order {
+ constructor(orderString, isLocal) {
+ const pieces = orderString.split(/ +/);
+ this.loc = pieces[1];
+ this.order = orderString;
+ this.local = Boolean(isLocal);
+ }
+}
diff --git a/diplomacy/web/src/gui/diplomacy/utils/order_building.js b/diplomacy/web/src/gui/diplomacy/utils/order_building.js
new file mode 100644
index 0000000..3758898
--- /dev/null
+++ b/diplomacy/web/src/gui/diplomacy/utils/order_building.js
@@ -0,0 +1,211 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+/*eslint no-unused-vars: ["error", { "args": "none" }]*/
+
+function assertLength(expected, given) {
+ if (expected !== given)
+ throw new Error(`Length error: expected ${expected}, given ${given}.`);
+}
+
+export class ProvinceCheck {
+
+ static retreated(province, powerName) {
+ const retreatProvince = province.getRetreated(powerName);
+ if (!retreatProvince)
+ throw new Error(`No retreated location at province ${province.name}.`);
+ // No confusion possible, we select the only occupied location at this province.
+ return [retreatProvince.retreatUnit];
+ }
+
+ static present(province, powerName) {
+ let unit = null;
+ let presenceProvince = province.getOccupied(powerName);
+ if (presenceProvince) {
+ unit = `${presenceProvince.unit} ${presenceProvince.name}`;
+ } else {
+ presenceProvince = province.getRetreated(powerName);
+ if (!presenceProvince)
+ throw new Error(`No unit or retreat at province ${province.name}.`);
+ unit = presenceProvince.retreatUnit;
+ }
+ return [unit];
+ }
+
+ static occupied(province, powerName) {
+ const occupiedProvince = province.getOccupied(powerName);
+ if (!occupiedProvince)
+ throw new Error(`No occupied location at province ${province.name}.`);
+ // No confusion possible, we select the only occupied location at this province.
+ const unit = occupiedProvince.unit;
+ const name = occupiedProvince.name.toUpperCase();
+ return [`${unit} ${name}`];
+ }
+
+ static occupiedByAny(province, unusedPowerName) {
+ return ProvinceCheck.occupied(province, null);
+ }
+
+ static any(province, unusedPowerName) {
+ // There may be many locations available for a province (e.g. many coasts).
+ return province.getLocationNames();
+ }
+
+ static buildOrder(path) {
+ switch (path[0]) {
+ case 'H':
+ return ProvinceCheck.holdToString(path);
+ case 'M':
+ return ProvinceCheck.moveToString(path);
+ case 'V':
+ return ProvinceCheck.moveViaToString(path);
+ case 'S':
+ return ProvinceCheck.supportToString(path);
+ case 'C':
+ return ProvinceCheck.convoyToString(path);
+ case 'R':
+ return ProvinceCheck.retreatToString(path);
+ case 'D':
+ return ProvinceCheck.disbandToString(path);
+ case 'A':
+ return ProvinceCheck.buildArmyToString(path);
+ case 'F':
+ return ProvinceCheck.buildFleetToString(path);
+ default:
+ throw new Error('Unable to build order from path ' + JSON.stringify(path));
+ }
+ }
+
+ static holdToString(path) {
+ assertLength(2, path.length);
+ return `${path[1]} ${path[0]}`;
+ }
+
+ static moveToString(path) {
+ assertLength(3, path.length);
+ return `${path[1]} - ${path[2]}`;
+ }
+
+ static moveViaToString(path) {
+ return ProvinceCheck.moveToString(path) + ' VIA';
+ }
+
+ static supportToString(path) {
+ assertLength(4, path.length);
+ let order = `${path[1]} ${path[0]} ${path[2]}`;
+ if (path[2].substr(2) !== path[3])
+ order += ` - ${path[3]}`;
+ return order;
+ }
+
+ static convoyToString(path) {
+ assertLength(4, path.length);
+ return `${path[1]} ${path[0]} ${path[2]} - ${path[3]}`;
+ }
+
+ static retreatToString(path) {
+ assertLength(3, path.length);
+ return `${path[1]} ${path[0]} ${path[2]}`;
+ }
+
+ static disbandToString(path) {
+ assertLength(2, path.length);
+ return `${path[1]} ${path[0]}`;
+ }
+
+ static buildArmyToString(path) {
+ assertLength(2, path.length);
+ return `${path[0]} ${path[1]} B`;
+ }
+
+ static buildFleetToString(path) {
+ assertLength(2, path.length);
+ return `${path[0]} ${path[1]} B`;
+ }
+
+}
+
+export const ORDER_BUILDER = {
+ H: {
+ name: 'hold (H)',
+ steps: [ProvinceCheck.occupied]
+ },
+ M: {
+ name: 'move (M)',
+ steps: [ProvinceCheck.occupied, ProvinceCheck.any]
+ },
+ V: {
+ name: 'move VIA (V)',
+ steps: [ProvinceCheck.occupied, ProvinceCheck.any]
+ },
+ S: {
+ name: 'support (S)',
+ steps: [ProvinceCheck.occupied, ProvinceCheck.occupiedByAny, ProvinceCheck.any]
+ },
+ C: {
+ name: 'convoy (C)',
+ steps: [ProvinceCheck.occupied, ProvinceCheck.occupiedByAny, ProvinceCheck.any]
+ },
+ R: {
+ name: 'retreat (R)',
+ steps: [ProvinceCheck.retreated, ProvinceCheck.any]
+ },
+ D: {
+ name: 'disband (D)',
+ steps: [ProvinceCheck.present]
+ },
+ A: {
+ name: 'build army (A)',
+ steps: [ProvinceCheck.any]
+ },
+ F: {
+ name: 'build fleet (F)',
+ steps: [ProvinceCheck.any]
+ },
+};
+
+export const POSSIBLE_ORDERS = {
+ // Allowed orders for movement phase step.
+ M: ['H', 'M', 'V', 'S', 'C'],
+ // Allowed orders for retreat phase step.
+ R: ['R', 'D'],
+ // Allowed orders for adjustment phase step.
+ A: ['D', 'A', 'F'],
+ sorting: {
+ M: {M: 0, V: 1, S: 2, C: 3, H: 4},
+ R: {R: 0, D: 1},
+ A: {A: 0, F: 1, D: 2}
+ },
+ sortOrderTypes: function (arr, phaseType) {
+ arr.sort((a, b) => POSSIBLE_ORDERS.sorting[phaseType][a] - POSSIBLE_ORDERS.sorting[phaseType][b]);
+ }
+};
+
+export function extendOrderBuilding(powerName, orderType, currentOrderPath, location, onBuilding, onBuilt, onError) {
+ const selectedPath = [orderType].concat(currentOrderPath, location);
+ if (selectedPath.length - 1 < ORDER_BUILDER[orderType].steps.length) {
+ // Checker OK, update.
+ onBuilding(powerName, selectedPath);
+ } else {
+ try {
+ // Order created.
+ const orderString = ProvinceCheck.buildOrder(selectedPath);
+ onBuilt(powerName, orderString);
+ } catch (error) {
+ onError(error.toString());
+ }
+ }
+}
diff --git a/diplomacy/web/src/gui/diplomacy/utils/power_view.jsx b/diplomacy/web/src/gui/diplomacy/utils/power_view.jsx
new file mode 100644
index 0000000..1796b1b
--- /dev/null
+++ b/diplomacy/web/src/gui/diplomacy/utils/power_view.jsx
@@ -0,0 +1,59 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import {STRINGS} from "../../../diplomacy/utils/strings";
+import React from "react";
+
+function getName(power) {
+ if (power.isEliminated())
+ return <em><s>{power.name.toLowerCase()}</s> (eliminated)</em>;
+ return power.name;
+}
+
+function getController(power) {
+ const controller = power.getController();
+ return <span className={controller === STRINGS.DUMMY ? 'dummy' : 'controller'}>{controller}</span>;
+}
+
+function getOrderFlag(power) {
+ const value = ['no', 'empty', 'yes'][power.order_is_set];
+ return <span className={value}>{value}</span>;
+}
+
+function getWaitFlag(power) {
+ return <span className={power.wait ? 'wait' : 'no-wait'}>{power.wait ? 'yes' : 'no'}</span>;
+}
+
+const GETTERS = {
+ name: getName,
+ controller: getController,
+ order_is_set: getOrderFlag,
+ wait: getWaitFlag
+};
+
+export class PowerView {
+ constructor(power) {
+ this.power = power;
+ }
+
+ static wrap(power) {
+ return new PowerView(power);
+ }
+
+ get(key) {
+ return GETTERS[key](this.power);
+ }
+}
diff --git a/diplomacy/web/src/gui/diplomacy/utils/province.js b/diplomacy/web/src/gui/diplomacy/utils/province.js
new file mode 100644
index 0000000..fc48ac7
--- /dev/null
+++ b/diplomacy/web/src/gui/diplomacy/utils/province.js
@@ -0,0 +1,117 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+const ProvinceType = {
+ WATER: 'WATER',
+ COAST: 'COAST',
+ PORT: 'PORT',
+ LAND: 'LAND'
+};
+
+export class Province {
+ constructor(name, type, isSupplyCenter) {
+ this.name = name;
+ this.type = type;
+ this.coasts = {};
+ this.parent = null;
+ this.neighbors = {};
+ this.isSupplyCenter = isSupplyCenter;
+ this.controller = null; // null or power name.
+ this.controlType = null; // null, C (center), I (influence) or U (unit).
+ this.unit = null; // null, A or F
+ this.retreatController = null;
+ this.retreatUnit = null; // null or `{unit type} {loc}`
+ this.aliases = [];
+ }
+
+ compareControlType(a, b) {
+ const controlTypeLevels = {C: 0, I: 1, U: 2};
+ return controlTypeLevels[a] - controlTypeLevels[b];
+ }
+
+ __set_controller(controller, controlType) {
+ this.controller = controller;
+ this.controlType = controlType;
+ for (let coast of Object.values(this.coasts))
+ coast.setController(controller, controlType);
+ }
+
+ setController(controller, controlType) {
+ if (!['C', 'I', 'U'].includes(controlType))
+ throw new Error(`Invalid province control type (${controlType}), expected 'C', 'I' or 'U'.`);
+ if (this.controller) {
+ const controlTypeComparison = this.compareControlType(controlType, this.controlType);
+ if (controlTypeComparison === 0)
+ throw new Error(`Found 2 powers trying to control same province (${this.name}) with same ` +
+ `control type (${controlType} VS ${this.controlType}).`);
+ if (controlTypeComparison > 0)
+ this.__set_controller(controller, controlType);
+ } else
+ this.__set_controller(controller, controlType);
+ }
+
+ setCoasts(provinces) {
+ const name = this.name.toUpperCase();
+ for (let entry of Object.entries(provinces)) {
+ const pieces = entry[0].split(/[^A-Za-z0-9]+/);
+ if (pieces.length > 1 && pieces[0].toUpperCase() === name) {
+ this.coasts[entry[0]] = entry[1];
+ entry[1].parent = this;
+ }
+ }
+ }
+
+ setNeighbors(neighborProvinces) {
+ for (let province of neighborProvinces)
+ this.neighbors[province.name] = province;
+ }
+
+ getLocationNames() {
+ const arr = Object.keys(this.coasts);
+ arr.splice(0, 0, this.name);
+ return arr;
+ }
+
+ getOccupied(powerName) {
+ if (!this.controller)
+ return null;
+ if (powerName && this.controller !== powerName)
+ return null;
+ if (this.unit)
+ return this;
+ for (let coast of Object.values(this.coasts))
+ if (coast.unit)
+ return coast;
+ return null;
+ }
+
+ getRetreated(powerName) {
+ if (this.retreatController === powerName)
+ return this;
+ for (let coast of Object.values(this.coasts))
+ if (coast.retreatController === powerName)
+ return coast;
+ return null;
+ }
+
+ isCoast() {
+ return this.type === ProvinceType.COAST;
+ }
+
+ isWater() {
+ return this.type === ProvinceType.WATER;
+ }
+}
diff --git a/diplomacy/web/src/gui/diplomacy/widgets/message_view.jsx b/diplomacy/web/src/gui/diplomacy/widgets/message_view.jsx
new file mode 100644
index 0000000..045a108
--- /dev/null
+++ b/diplomacy/web/src/gui/diplomacy/widgets/message_view.jsx
@@ -0,0 +1,57 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import React from "react";
+import {UTILS} from "../../../diplomacy/utils/utils";
+import PropTypes from 'prop-types';
+
+export class MessageView extends React.Component {
+ // message
+ render() {
+ const message = this.props.message;
+ const owner = this.props.owner;
+ const id = this.props.id ? {id: this.props.id} : {};
+ const messagesLines = message.message.replace('\r\n', '\n').replace('\r', '\n').split('\n');
+ let onClick = null;
+ const classNames = ['game-message'];
+ if (owner === message.sender)
+ classNames.push('message-sender');
+ else {
+ classNames.push('message-recipient');
+ if (message.read || this.props.read)
+ classNames.push('message-read');
+ onClick = this.props.onClick ? {onClick: () => this.props.onClick(message)} : {};
+ }
+ return (
+ <div className={'game-message-wrapper'} {...id}>
+ <div className={classNames.join(' ')} {...onClick}>
+ <div className={'message-header'}>
+ {message.sender} {UTILS.html.UNICODE_SMALL_RIGHT_ARROW} {message.recipient}
+ </div>
+ <div className={'message-content'}>{messagesLines.map((line, lineIndex) => <div key={lineIndex}>{line}</div>)}</div>
+ </div>
+ </div>
+ );
+ }
+}
+
+MessageView.propTypes = {
+ message: PropTypes.object,
+ owner: PropTypes.string,
+ onClick: PropTypes.func,
+ id: PropTypes.string,
+ read: PropTypes.bool
+};
diff --git a/diplomacy/web/src/gui/diplomacy/widgets/power_order.jsx b/diplomacy/web/src/gui/diplomacy/widgets/power_order.jsx
new file mode 100644
index 0000000..28a5421
--- /dev/null
+++ b/diplomacy/web/src/gui/diplomacy/widgets/power_order.jsx
@@ -0,0 +1,79 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import React from "react";
+import {Button} from "../../core/widgets";
+import PropTypes from 'prop-types';
+
+export class PowerOrder extends React.Component {
+ render() {
+ const orderEntries = this.props.orders ? Object.entries(this.props.orders) : null;
+ let display = null;
+ if (orderEntries) {
+ if (orderEntries.length) {
+ orderEntries.sort((a, b) => a[1].order.localeCompare(b[1].order));
+ display = (
+ <div className={'container order-list'}>
+ {orderEntries.map((entry, index) => (
+ <div
+ className={`row order-entry entry-${1 + index % 2} ` + (entry[1].local ? 'local' : 'server')}
+ key={index}>
+ <div className={'col align-self-center order'}>
+ <span className={'order-string'}>{entry[1].order}</span>
+ {entry[1].local ? '' : <span className={'order-mark'}> [S]</span>}
+ </div>
+ <div className={'col remove-button'}>
+ <Button title={'-'} onClick={() => this.props.onRemove(this.props.name, entry[1])}/>
+ </div>
+ </div>
+ ))}
+ </div>
+ );
+ } else if (this.props.serverCount === 0) {
+ display = (<div className={'empty-orders'}>Empty orders set</div>);
+ } else {
+ display = (<div className={'empty-orders'}>Local empty orders set</div>);
+ }
+ } else {
+ if (this.props.serverCount < 0) {
+ display = <div className={'no-orders'}>No orders!</div>;
+ } else if (this.props.serverCount === 0) {
+ display = <div className={'empty-orders'}>Empty orders set</div>;
+ } else {
+ display = (<div className={'empty-orders'}>Local empty orders set</div>);
+ }
+ }
+ return (
+ <div className={'power-orders'}>
+ <div className={'title'}>
+ <span className={'name'}>{this.props.name}</span>
+ <span className={this.props.wait ? 'wait' : 'no-wait'}>
+ {(this.props.wait ? ' ' : ' not') + ' waiting'}
+ </span>
+ </div>
+ {display}
+ </div>
+ );
+ }
+}
+
+PowerOrder.propTypes = {
+ wait: PropTypes.bool,
+ name: PropTypes.string,
+ orders: PropTypes.object,
+ serverCount: PropTypes.number,
+ onRemove: PropTypes.func,
+};
diff --git a/diplomacy/web/src/index.css b/diplomacy/web/src/index.css
new file mode 100644
index 0000000..f33b116
--- /dev/null
+++ b/diplomacy/web/src/index.css
@@ -0,0 +1,401 @@
+/** Bootstrap. **/
+/** Common. **/
+
+a.dropdown-item {
+ cursor: pointer;
+}
+
+.top-msg {
+ border-bottom: 1px solid black;
+ font-weight: bold;
+ text-align: center;
+ position: -webkit-sticky;
+ position: sticky;
+ top: 0;
+ z-index: 1;
+ background-color: white;
+}
+
+.top-msg .msg {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.top-msg .with-msg {
+ cursor: pointer;
+}
+
+.top-msg .no-msg {
+ text-overflow: initial;
+}
+
+.top-msg .msg + .msg {
+ border-left: 1px solid black;
+}
+
+.top-msg .error {
+ color: red;
+}
+
+.top-msg .info {
+ color: blue;
+}
+
+.top-msg .success {
+ color: green;
+}
+
+#past-map svg, #current-map svg {
+ display: block;
+ width: 100%;
+ height: auto;
+}
+
+.history-current-orders {
+ background-color: red;
+ color: white;
+ font-weight: bold;
+ position: absolute;
+ top: 0;
+ right: 0;
+ border: 4px solid black;
+ margin: 5px 24px;
+ padding: 5px 10px 5px 10px;
+}
+
+table caption {
+ caption-side: top;
+}
+
+main {
+ padding: 10px;
+}
+
+.power-actions-form button + button, .panel-orders .bar button + button, .games-form button + button {
+ margin-left: 0.5rem;
+}
+
+.link-unread-message {
+ display: block;
+ text-align: center;
+ font-weight: bold;
+ text-decoration: underline;
+ margin-bottom: 1rem;
+}
+
+.link-unread-message:hover {
+ text-decoration: none;
+}
+
+.power-name {
+ font-weight: bold;
+ color: red;
+ text-align: center;
+}
+
+#current-power {
+ color: red;
+ font-weight: bold;
+ text-align: center;
+}
+
+.page-messages {
+ position: fixed;
+ bottom: 0;
+ right: 0;
+ z-index: 1;
+ width: 30%;
+}
+
+.page-message {
+ border: 8px solid;
+ padding: 10px;
+ cursor: pointer;
+ font-size: 1.3rem;
+ font-weight: bold;
+}
+
+.page-message.error {
+ border-color: rgb(245, 205, 205);
+ background-color: rgba(255, 215, 215, 0.9);
+ color: rgb(200, 120, 120);
+}
+
+.page-message.info {
+ border-color: rgb(245, 245, 205);
+ background-color: rgba(255, 255, 215, 0.9);
+ color: rgb(200, 200, 120);
+}
+
+.page-message.success {
+ border-color: rgb(205, 245, 205);
+ background-color: rgba(215, 255, 215, 0.9);
+ color: rgb(120, 200, 120);
+}
+
+.order-result {
+ font-weight: bold;
+}
+
+.order-result .bounce {
+ color: red;
+}
+
+.order-result .success {
+ color: green;
+}
+
+.past-orders {
+ font-size: 0.9rem;
+ max-height: 500px;
+ overflow: auto;
+}
+
+.past-orders .row:nth-child(odd) {
+ background-color: rgb(244, 244, 245);
+}
+
+.past-orders .row .past-power-name, .past-orders .row .past-power-orders {
+ padding: 5px;
+}
+
+.past-orders .row .past-power-name {
+ font-weight: bold;
+}
+
+.past-orders .row .past-power-orders > div:before {
+ content: "\2192";
+ margin-right: 1em;
+}
+
+.bar > * {
+ display: inline-block;
+}
+
+.page > .title {
+ border-bottom: 1px solid silver;
+ padding: 10px;
+}
+
+.left {
+ float: left;
+}
+
+.right {
+ float: right;
+}
+
+.action {
+ cursor: pointer;
+}
+
+.action .updated {
+ font-weight: bold;
+}
+
+.action .update {
+ font-size: 0.8em;
+ color: white;
+ background-color: red;
+ display: inline-block;
+ padding: 0 0.4em 0 0.4em;
+ margin-left: 0.4em;
+ border: 1px solid lightcoral;
+}
+
+.orders, .game-messages {
+ max-height: 500px;
+ overflow: auto;
+ border: 1px solid silver;
+ padding: 10px;
+}
+
+.panel-orders > .bar {
+ border-top: 1px solid silver;
+ border-left: 1px solid silver;
+ border-right: 1px solid silver;
+}
+
+.panel-orders .summary {
+ border-left: 1px solid silver;
+ border-right: 1px solid silver;
+}
+
+.panel-orders .summary > span + span:before {
+ content: ', ';
+}
+
+.fancy-wrapper {
+ position: fixed;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ padding-top: 10%;
+ background-color: rgba(100, 100, 110, 0.5);
+}
+
+.fancy-box {
+ border: 1px solid silver;
+ position: relative;
+ margin: auto;
+}
+
+.fancy-box .fancy-bar {
+ background-color: rgb(240, 240, 240);
+ border-bottom: 1px solid silver;
+ padding-top: 10px;
+ padding-bottom: 10px;
+}
+
+.fancy-box .fancy-button {
+ text-align: right;
+}
+
+.fancy-box .fancy-content {
+ padding-top: 10px;
+ padding-bottom: 10px;
+ background-color: white;
+}
+
+.power-orders {
+ padding-bottom: 8px;
+}
+
+.power-orders .no-orders, .empty-orders {
+ text-align: center;
+ font-weight: bold;
+ font-style: italic;
+}
+
+.power-orders .no-orders {
+ color: lightgray;
+}
+
+.power-orders .empty-orders {
+ color: gray;
+}
+
+.power-orders .title {
+ background-color: rgb(230, 230, 235);
+ padding: 10px;
+ margin-bottom: 2px;
+}
+
+.power-orders .title .name {
+ font-weight: bold;
+}
+
+.dummy, .neutral {
+ font-style: italic;
+ color: gray;
+}
+
+.controller {
+ font-weight: bold;
+}
+
+.power-orders .title .wait, .wait, .no {
+ font-weight: bold;
+ color: red;
+}
+
+.power-orders .title .no-wait, .no-wait, .yes {
+ font-weight: bold;
+ color: green;
+}
+
+.empty {
+ font-weight: bold;
+ color: orange;
+}
+
+.power-orders .title button {
+ font-family: "Courier New", Courier, monospace;
+}
+
+.power-orders .order-entry {
+ padding-top: 2px;
+ padding-bottom: 2px;
+}
+
+.power-orders .order-entry.server .order-string {
+ text-decoration: underline;
+}
+
+.power-orders .order-entry.server .order-mark {
+ color: red;
+}
+
+.power-orders .entry-2 {
+ background-color: rgb(248, 248, 248);
+}
+
+.power-orders .order {
+ font-weight: bold;
+}
+
+.power-orders .remove-button {
+ text-align: right;
+}
+
+.game-message {
+ padding: 10px;
+ width: 75%;
+ border-width: 4px;
+ border-style: solid;
+ border-radius: 10px;
+}
+
+.game-message .message-header {
+ font-weight: bold;
+}
+
+.game-message.message-recipient {
+ float: left;
+ border-color: rgb(240, 200, 200);
+ background-color: rgb(255, 220, 220);
+ cursor: pointer;
+}
+
+.game-message.message-recipient.message-read {
+ border-color: rgb(200, 240, 200);
+ background-color: rgb(220, 255, 220);
+ cursor: default;
+}
+
+.game-message.message-sender {
+ float: right;
+ border-color: rgb(200, 200, 240);
+ background-color: rgb(220, 220, 255);
+}
+
+.game-message-wrapper {
+ overflow: auto;
+ clear: both;
+}
+
+.game-message-wrapper + .game-message-wrapper {
+ margin-top: 10px;
+}
+
+.button-server {
+ border: 1px solid silver;
+ border-radius: 4px;
+ padding: 5px;
+ cursor: pointer;
+ margin-bottom: 10px;
+}
+
+.button-server:hover {
+ background-color: rgb(245, 245, 245);
+}
+
+.button-server:active {
+ background-color: rgb(230, 230, 230);
+}
+
+/** Page login. **/
+/** Page games. **/
+/** Page game. **/
diff --git a/diplomacy/web/src/index.js b/diplomacy/web/src/index.js
new file mode 100644
index 0000000..d074bce
--- /dev/null
+++ b/diplomacy/web/src/index.js
@@ -0,0 +1,28 @@
+// ==============================================================================
+// Copyright (C) 2019 - Philip Paquette, Steven Bocco
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Affero General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Affero General Public License along
+// with this program. If not, see <https://www.gnu.org/licenses/>.
+// ==============================================================================
+import React from 'react';
+import ReactDOM from 'react-dom';
+import {Page} from "./gui/core/page";
+import 'popper.js';
+import 'bootstrap/dist/js/bootstrap';
+import 'bootstrap/dist/css/bootstrap.min.css';
+import './index.css';
+
+
+// ========================================
+
+ReactDOM.render(<Page/>, document.getElementById('root'));
diff --git a/diplomacy/web/src/standard.svg b/diplomacy/web/src/standard.svg
new file mode 120000
index 0000000..abb544e
--- /dev/null
+++ b/diplomacy/web/src/standard.svg
@@ -0,0 +1 @@
+../../maps/svg/standard.svg \ No newline at end of file