├── .gitignore ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── screenshots ├── rewire-screen-big.png └── rewire-screen-small.png ├── src ├── canvas.ts ├── game.ts ├── gfx-generator.ts ├── html.ts ├── index.html ├── input.ts ├── level-editor.ts ├── level.ts ├── math-util.ts ├── mouse-drag-system.ts ├── render-systems.ts ├── resources.ts ├── space.ts ├── spool-system.ts ├── start.ts ├── types.ts ├── utils.ts └── vector.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Jan Mankopf 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![thumbnail](./screenshots/rewire-screen-big.png) 2 | # js13k-rewire 3 | A puzzle game for the js13kGames 2018 Development Competition (https://js13kgames.com/). 4 | 5 | Bring the system back online by rewiring the power nodes. 6 | 7 | This game is written in typescript. 8 | 9 | You can play the game here: https://js13kgames.com/entries/re-wire 10 | 11 | 12 | ## Build 13 | ``` 14 | $ npm install 15 | $ npm run BUILD 16 | ``` 17 | 18 | 19 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js13k-rewire", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "accepts": { 8 | "version": "1.3.5", 9 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", 10 | "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", 11 | "dev": true, 12 | "requires": { 13 | "mime-types": "~2.1.18", 14 | "negotiator": "0.6.1" 15 | } 16 | }, 17 | "ansi-styles": { 18 | "version": "1.0.0", 19 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", 20 | "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=", 21 | "dev": true 22 | }, 23 | "anymatch": { 24 | "version": "1.3.2", 25 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", 26 | "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", 27 | "dev": true, 28 | "requires": { 29 | "micromatch": "^2.1.5", 30 | "normalize-path": "^2.0.0" 31 | } 32 | }, 33 | "apache-crypt": { 34 | "version": "1.2.1", 35 | "resolved": "https://registry.npmjs.org/apache-crypt/-/apache-crypt-1.2.1.tgz", 36 | "integrity": "sha1-1vxyqm0n2ZyVqU/RiNcx7v/6Zjw=", 37 | "dev": true, 38 | "requires": { 39 | "unix-crypt-td-js": "^1.0.0" 40 | } 41 | }, 42 | "apache-md5": { 43 | "version": "1.1.2", 44 | "resolved": "https://registry.npmjs.org/apache-md5/-/apache-md5-1.1.2.tgz", 45 | "integrity": "sha1-7klza2ObTxCLbp5ibG2pkwa0FpI=", 46 | "dev": true 47 | }, 48 | "arr-diff": { 49 | "version": "2.0.0", 50 | "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", 51 | "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", 52 | "dev": true, 53 | "requires": { 54 | "arr-flatten": "^1.0.1" 55 | } 56 | }, 57 | "arr-flatten": { 58 | "version": "1.1.0", 59 | "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", 60 | "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", 61 | "dev": true 62 | }, 63 | "array-filter": { 64 | "version": "0.0.1", 65 | "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", 66 | "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=", 67 | "dev": true 68 | }, 69 | "array-map": { 70 | "version": "0.0.0", 71 | "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", 72 | "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=", 73 | "dev": true 74 | }, 75 | "array-reduce": { 76 | "version": "0.0.0", 77 | "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", 78 | "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=", 79 | "dev": true 80 | }, 81 | "array-unique": { 82 | "version": "0.2.1", 83 | "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", 84 | "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", 85 | "dev": true 86 | }, 87 | "async-each": { 88 | "version": "1.0.1", 89 | "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", 90 | "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", 91 | "dev": true 92 | }, 93 | "babel-runtime": { 94 | "version": "6.26.0", 95 | "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", 96 | "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", 97 | "dev": true, 98 | "requires": { 99 | "core-js": "^2.4.0", 100 | "regenerator-runtime": "^0.11.0" 101 | } 102 | }, 103 | "balanced-match": { 104 | "version": "1.0.0", 105 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 106 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 107 | "dev": true 108 | }, 109 | "basic-auth": { 110 | "version": "2.0.0", 111 | "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.0.tgz", 112 | "integrity": "sha1-AV2z81PgLlY3d1X5YnQuiYHnu7o=", 113 | "dev": true, 114 | "requires": { 115 | "safe-buffer": "5.1.1" 116 | }, 117 | "dependencies": { 118 | "safe-buffer": { 119 | "version": "5.1.1", 120 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 121 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", 122 | "dev": true 123 | } 124 | } 125 | }, 126 | "batch": { 127 | "version": "0.6.1", 128 | "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", 129 | "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", 130 | "dev": true 131 | }, 132 | "bcryptjs": { 133 | "version": "2.4.3", 134 | "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", 135 | "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=", 136 | "dev": true 137 | }, 138 | "binary-extensions": { 139 | "version": "1.11.0", 140 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", 141 | "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=", 142 | "dev": true 143 | }, 144 | "brace-expansion": { 145 | "version": "1.1.11", 146 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 147 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 148 | "dev": true, 149 | "requires": { 150 | "balanced-match": "^1.0.0", 151 | "concat-map": "0.0.1" 152 | } 153 | }, 154 | "braces": { 155 | "version": "1.8.5", 156 | "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", 157 | "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", 158 | "dev": true, 159 | "requires": { 160 | "expand-range": "^1.8.1", 161 | "preserve": "^0.2.0", 162 | "repeat-element": "^1.1.2" 163 | } 164 | }, 165 | "builtin-modules": { 166 | "version": "1.1.1", 167 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", 168 | "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", 169 | "dev": true 170 | }, 171 | "camel-case": { 172 | "version": "3.0.0", 173 | "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", 174 | "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", 175 | "dev": true, 176 | "requires": { 177 | "no-case": "^2.2.0", 178 | "upper-case": "^1.1.1" 179 | } 180 | }, 181 | "chalk": { 182 | "version": "0.4.0", 183 | "resolved": "http://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", 184 | "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", 185 | "dev": true, 186 | "requires": { 187 | "ansi-styles": "~1.0.0", 188 | "has-color": "~0.1.0", 189 | "strip-ansi": "~0.1.0" 190 | } 191 | }, 192 | "chokidar": { 193 | "version": "1.7.0", 194 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", 195 | "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", 196 | "dev": true, 197 | "requires": { 198 | "anymatch": "^1.3.0", 199 | "async-each": "^1.0.0", 200 | "fsevents": "^1.0.0", 201 | "glob-parent": "^2.0.0", 202 | "inherits": "^2.0.1", 203 | "is-binary-path": "^1.0.0", 204 | "is-glob": "^2.0.0", 205 | "path-is-absolute": "^1.0.0", 206 | "readdirp": "^2.0.0" 207 | } 208 | }, 209 | "clean-css": { 210 | "version": "4.2.1", 211 | "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", 212 | "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==", 213 | "dev": true, 214 | "requires": { 215 | "source-map": "~0.6.0" 216 | } 217 | }, 218 | "color-convert": { 219 | "version": "1.9.3", 220 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 221 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 222 | "dev": true, 223 | "requires": { 224 | "color-name": "1.1.3" 225 | } 226 | }, 227 | "color-name": { 228 | "version": "1.1.3", 229 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 230 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 231 | "dev": true 232 | }, 233 | "colors": { 234 | "version": "1.3.1", 235 | "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.1.tgz", 236 | "integrity": "sha512-jg/vxRmv430jixZrC+La5kMbUWqIg32/JsYNZb94+JEmzceYbWKTsv1OuTp+7EaqiaWRR2tPcykibwCRgclIsw==", 237 | "dev": true 238 | }, 239 | "commander": { 240 | "version": "2.13.0", 241 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", 242 | "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==", 243 | "dev": true 244 | }, 245 | "concat-map": { 246 | "version": "0.0.1", 247 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 248 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 249 | "dev": true 250 | }, 251 | "connect": { 252 | "version": "3.5.1", 253 | "resolved": "https://registry.npmjs.org/connect/-/connect-3.5.1.tgz", 254 | "integrity": "sha1-bTDXpjx/FwhXprOqazY9lz3KWI4=", 255 | "dev": true, 256 | "requires": { 257 | "debug": "~2.2.0", 258 | "finalhandler": "0.5.1", 259 | "parseurl": "~1.3.1", 260 | "utils-merge": "1.0.0" 261 | } 262 | }, 263 | "core-js": { 264 | "version": "2.5.7", 265 | "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", 266 | "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==", 267 | "dev": true 268 | }, 269 | "core-util-is": { 270 | "version": "1.0.2", 271 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 272 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", 273 | "dev": true 274 | }, 275 | "cors": { 276 | "version": "2.8.4", 277 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.4.tgz", 278 | "integrity": "sha1-K9OB8usgECAQXNUOpZ2mMJBpRoY=", 279 | "dev": true, 280 | "requires": { 281 | "object-assign": "^4", 282 | "vary": "^1" 283 | } 284 | }, 285 | "cpx": { 286 | "version": "1.5.0", 287 | "resolved": "https://registry.npmjs.org/cpx/-/cpx-1.5.0.tgz", 288 | "integrity": "sha1-GFvgGFEdhycN7czCkxceN2VauI8=", 289 | "dev": true, 290 | "requires": { 291 | "babel-runtime": "^6.9.2", 292 | "chokidar": "^1.6.0", 293 | "duplexer": "^0.1.1", 294 | "glob": "^7.0.5", 295 | "glob2base": "^0.0.12", 296 | "minimatch": "^3.0.2", 297 | "mkdirp": "^0.5.1", 298 | "resolve": "^1.1.7", 299 | "safe-buffer": "^5.0.1", 300 | "shell-quote": "^1.6.1", 301 | "subarg": "^1.0.0" 302 | } 303 | }, 304 | "cross-spawn": { 305 | "version": "6.0.5", 306 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", 307 | "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", 308 | "dev": true, 309 | "requires": { 310 | "nice-try": "^1.0.4", 311 | "path-key": "^2.0.1", 312 | "semver": "^5.5.0", 313 | "shebang-command": "^1.2.0", 314 | "which": "^1.2.9" 315 | } 316 | }, 317 | "cssauron": { 318 | "version": "1.4.0", 319 | "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz", 320 | "integrity": "sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg=", 321 | "dev": true, 322 | "requires": { 323 | "through": "X.X.X" 324 | } 325 | }, 326 | "debug": { 327 | "version": "2.2.0", 328 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", 329 | "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", 330 | "dev": true, 331 | "requires": { 332 | "ms": "0.7.1" 333 | } 334 | }, 335 | "define-properties": { 336 | "version": "1.1.3", 337 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", 338 | "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", 339 | "dev": true, 340 | "requires": { 341 | "object-keys": "^1.0.12" 342 | }, 343 | "dependencies": { 344 | "object-keys": { 345 | "version": "1.0.12", 346 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", 347 | "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==", 348 | "dev": true 349 | } 350 | } 351 | }, 352 | "depd": { 353 | "version": "1.1.2", 354 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 355 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", 356 | "dev": true 357 | }, 358 | "destroy": { 359 | "version": "1.0.4", 360 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 361 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", 362 | "dev": true 363 | }, 364 | "duplexer": { 365 | "version": "0.1.1", 366 | "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", 367 | "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", 368 | "dev": true 369 | }, 370 | "duplexer2": { 371 | "version": "0.0.2", 372 | "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", 373 | "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", 374 | "dev": true, 375 | "requires": { 376 | "readable-stream": "~1.1.9" 377 | }, 378 | "dependencies": { 379 | "isarray": { 380 | "version": "0.0.1", 381 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 382 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", 383 | "dev": true 384 | }, 385 | "readable-stream": { 386 | "version": "1.1.14", 387 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", 388 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", 389 | "dev": true, 390 | "requires": { 391 | "core-util-is": "~1.0.0", 392 | "inherits": "~2.0.1", 393 | "isarray": "0.0.1", 394 | "string_decoder": "~0.10.x" 395 | } 396 | }, 397 | "string_decoder": { 398 | "version": "0.10.31", 399 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 400 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", 401 | "dev": true 402 | } 403 | } 404 | }, 405 | "ee-first": { 406 | "version": "1.1.1", 407 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 408 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", 409 | "dev": true 410 | }, 411 | "encodeurl": { 412 | "version": "1.0.2", 413 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 414 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", 415 | "dev": true 416 | }, 417 | "error-ex": { 418 | "version": "1.3.2", 419 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", 420 | "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", 421 | "dev": true, 422 | "requires": { 423 | "is-arrayish": "^0.2.1" 424 | } 425 | }, 426 | "es-abstract": { 427 | "version": "1.12.0", 428 | "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", 429 | "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", 430 | "dev": true, 431 | "requires": { 432 | "es-to-primitive": "^1.1.1", 433 | "function-bind": "^1.1.1", 434 | "has": "^1.0.1", 435 | "is-callable": "^1.1.3", 436 | "is-regex": "^1.0.4" 437 | } 438 | }, 439 | "es-to-primitive": { 440 | "version": "1.1.1", 441 | "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", 442 | "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", 443 | "dev": true, 444 | "requires": { 445 | "is-callable": "^1.1.1", 446 | "is-date-object": "^1.0.1", 447 | "is-symbol": "^1.0.1" 448 | } 449 | }, 450 | "escape-html": { 451 | "version": "1.0.3", 452 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 453 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", 454 | "dev": true 455 | }, 456 | "escape-string-regexp": { 457 | "version": "1.0.5", 458 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 459 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 460 | "dev": true 461 | }, 462 | "etag": { 463 | "version": "1.8.1", 464 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 465 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", 466 | "dev": true 467 | }, 468 | "event-stream": { 469 | "version": "3.3.4", 470 | "resolved": "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", 471 | "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", 472 | "dev": true, 473 | "requires": { 474 | "duplexer": "~0.1.1", 475 | "from": "~0", 476 | "map-stream": "~0.1.0", 477 | "pause-stream": "0.0.11", 478 | "split": "0.3", 479 | "stream-combiner": "~0.0.4", 480 | "through": "~2.3.1" 481 | } 482 | }, 483 | "expand-brackets": { 484 | "version": "0.1.5", 485 | "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", 486 | "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", 487 | "dev": true, 488 | "requires": { 489 | "is-posix-bracket": "^0.1.0" 490 | } 491 | }, 492 | "expand-range": { 493 | "version": "1.8.2", 494 | "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", 495 | "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", 496 | "dev": true, 497 | "requires": { 498 | "fill-range": "^2.1.0" 499 | } 500 | }, 501 | "extglob": { 502 | "version": "0.3.2", 503 | "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", 504 | "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", 505 | "dev": true, 506 | "requires": { 507 | "is-extglob": "^1.0.0" 508 | } 509 | }, 510 | "faye-websocket": { 511 | "version": "0.11.1", 512 | "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.1.tgz", 513 | "integrity": "sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg=", 514 | "dev": true, 515 | "requires": { 516 | "websocket-driver": ">=0.5.1" 517 | } 518 | }, 519 | "filename-regex": { 520 | "version": "2.0.1", 521 | "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", 522 | "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", 523 | "dev": true 524 | }, 525 | "fill-range": { 526 | "version": "2.2.4", 527 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", 528 | "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", 529 | "dev": true, 530 | "requires": { 531 | "is-number": "^2.1.0", 532 | "isobject": "^2.0.0", 533 | "randomatic": "^3.0.0", 534 | "repeat-element": "^1.1.2", 535 | "repeat-string": "^1.5.2" 536 | } 537 | }, 538 | "finalhandler": { 539 | "version": "0.5.1", 540 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.5.1.tgz", 541 | "integrity": "sha1-LEANjUUwk1vCMlScX6OF7Afeb80=", 542 | "dev": true, 543 | "requires": { 544 | "debug": "~2.2.0", 545 | "escape-html": "~1.0.3", 546 | "on-finished": "~2.3.0", 547 | "statuses": "~1.3.1", 548 | "unpipe": "~1.0.0" 549 | } 550 | }, 551 | "find-index": { 552 | "version": "0.1.1", 553 | "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz", 554 | "integrity": "sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ=", 555 | "dev": true 556 | }, 557 | "for-in": { 558 | "version": "1.0.2", 559 | "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", 560 | "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", 561 | "dev": true 562 | }, 563 | "for-own": { 564 | "version": "0.1.5", 565 | "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", 566 | "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", 567 | "dev": true, 568 | "requires": { 569 | "for-in": "^1.0.1" 570 | } 571 | }, 572 | "fresh": { 573 | "version": "0.5.2", 574 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 575 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", 576 | "dev": true 577 | }, 578 | "from": { 579 | "version": "0.1.7", 580 | "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", 581 | "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", 582 | "dev": true 583 | }, 584 | "fs.realpath": { 585 | "version": "1.0.0", 586 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 587 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 588 | "dev": true 589 | }, 590 | "fsevents": { 591 | "version": "1.2.4", 592 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", 593 | "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", 594 | "dev": true, 595 | "optional": true, 596 | "requires": { 597 | "nan": "^2.9.2", 598 | "node-pre-gyp": "^0.10.0" 599 | }, 600 | "dependencies": { 601 | "abbrev": { 602 | "version": "1.1.1", 603 | "bundled": true, 604 | "dev": true, 605 | "optional": true 606 | }, 607 | "ansi-regex": { 608 | "version": "2.1.1", 609 | "bundled": true, 610 | "dev": true 611 | }, 612 | "aproba": { 613 | "version": "1.2.0", 614 | "bundled": true, 615 | "dev": true, 616 | "optional": true 617 | }, 618 | "are-we-there-yet": { 619 | "version": "1.1.4", 620 | "bundled": true, 621 | "dev": true, 622 | "optional": true, 623 | "requires": { 624 | "delegates": "^1.0.0", 625 | "readable-stream": "^2.0.6" 626 | } 627 | }, 628 | "balanced-match": { 629 | "version": "1.0.0", 630 | "bundled": true, 631 | "dev": true, 632 | "optional": true 633 | }, 634 | "brace-expansion": { 635 | "version": "1.1.11", 636 | "bundled": true, 637 | "dev": true, 638 | "optional": true, 639 | "requires": { 640 | "balanced-match": "^1.0.0", 641 | "concat-map": "0.0.1" 642 | } 643 | }, 644 | "chownr": { 645 | "version": "1.0.1", 646 | "bundled": true, 647 | "dev": true, 648 | "optional": true 649 | }, 650 | "code-point-at": { 651 | "version": "1.1.0", 652 | "bundled": true, 653 | "dev": true, 654 | "optional": true 655 | }, 656 | "concat-map": { 657 | "version": "0.0.1", 658 | "bundled": true, 659 | "dev": true, 660 | "optional": true 661 | }, 662 | "console-control-strings": { 663 | "version": "1.1.0", 664 | "bundled": true, 665 | "dev": true, 666 | "optional": true 667 | }, 668 | "core-util-is": { 669 | "version": "1.0.2", 670 | "bundled": true, 671 | "dev": true, 672 | "optional": true 673 | }, 674 | "debug": { 675 | "version": "2.6.9", 676 | "bundled": true, 677 | "dev": true, 678 | "optional": true, 679 | "requires": { 680 | "ms": "2.0.0" 681 | } 682 | }, 683 | "deep-extend": { 684 | "version": "0.5.1", 685 | "bundled": true, 686 | "dev": true, 687 | "optional": true 688 | }, 689 | "delegates": { 690 | "version": "1.0.0", 691 | "bundled": true, 692 | "dev": true, 693 | "optional": true 694 | }, 695 | "detect-libc": { 696 | "version": "1.0.3", 697 | "bundled": true, 698 | "dev": true, 699 | "optional": true 700 | }, 701 | "fs-minipass": { 702 | "version": "1.2.5", 703 | "bundled": true, 704 | "dev": true, 705 | "optional": true, 706 | "requires": { 707 | "minipass": "^2.2.1" 708 | } 709 | }, 710 | "fs.realpath": { 711 | "version": "1.0.0", 712 | "bundled": true, 713 | "dev": true, 714 | "optional": true 715 | }, 716 | "gauge": { 717 | "version": "2.7.4", 718 | "bundled": true, 719 | "dev": true, 720 | "optional": true, 721 | "requires": { 722 | "aproba": "^1.0.3", 723 | "console-control-strings": "^1.0.0", 724 | "has-unicode": "^2.0.0", 725 | "object-assign": "^4.1.0", 726 | "signal-exit": "^3.0.0", 727 | "string-width": "^1.0.1", 728 | "strip-ansi": "^3.0.1", 729 | "wide-align": "^1.1.0" 730 | } 731 | }, 732 | "glob": { 733 | "version": "7.1.2", 734 | "bundled": true, 735 | "dev": true, 736 | "optional": true, 737 | "requires": { 738 | "fs.realpath": "^1.0.0", 739 | "inflight": "^1.0.4", 740 | "inherits": "2", 741 | "minimatch": "^3.0.4", 742 | "once": "^1.3.0", 743 | "path-is-absolute": "^1.0.0" 744 | } 745 | }, 746 | "has-unicode": { 747 | "version": "2.0.1", 748 | "bundled": true, 749 | "dev": true, 750 | "optional": true 751 | }, 752 | "iconv-lite": { 753 | "version": "0.4.21", 754 | "bundled": true, 755 | "dev": true, 756 | "optional": true, 757 | "requires": { 758 | "safer-buffer": "^2.1.0" 759 | } 760 | }, 761 | "ignore-walk": { 762 | "version": "3.0.1", 763 | "bundled": true, 764 | "dev": true, 765 | "optional": true, 766 | "requires": { 767 | "minimatch": "^3.0.4" 768 | } 769 | }, 770 | "inflight": { 771 | "version": "1.0.6", 772 | "bundled": true, 773 | "dev": true, 774 | "optional": true, 775 | "requires": { 776 | "once": "^1.3.0", 777 | "wrappy": "1" 778 | } 779 | }, 780 | "inherits": { 781 | "version": "2.0.3", 782 | "bundled": true, 783 | "dev": true, 784 | "optional": true 785 | }, 786 | "ini": { 787 | "version": "1.3.5", 788 | "bundled": true, 789 | "dev": true, 790 | "optional": true 791 | }, 792 | "is-fullwidth-code-point": { 793 | "version": "1.0.0", 794 | "bundled": true, 795 | "dev": true, 796 | "optional": true, 797 | "requires": { 798 | "number-is-nan": "^1.0.0" 799 | } 800 | }, 801 | "isarray": { 802 | "version": "1.0.0", 803 | "bundled": true, 804 | "dev": true, 805 | "optional": true 806 | }, 807 | "minimatch": { 808 | "version": "3.0.4", 809 | "bundled": true, 810 | "dev": true, 811 | "optional": true, 812 | "requires": { 813 | "brace-expansion": "^1.1.7" 814 | } 815 | }, 816 | "minimist": { 817 | "version": "0.0.8", 818 | "bundled": true, 819 | "dev": true, 820 | "optional": true 821 | }, 822 | "minipass": { 823 | "version": "2.2.4", 824 | "bundled": true, 825 | "dev": true, 826 | "optional": true, 827 | "requires": { 828 | "safe-buffer": "^5.1.1", 829 | "yallist": "^3.0.0" 830 | } 831 | }, 832 | "minizlib": { 833 | "version": "1.1.0", 834 | "bundled": true, 835 | "dev": true, 836 | "optional": true, 837 | "requires": { 838 | "minipass": "^2.2.1" 839 | } 840 | }, 841 | "mkdirp": { 842 | "version": "0.5.1", 843 | "bundled": true, 844 | "dev": true, 845 | "optional": true, 846 | "requires": { 847 | "minimist": "0.0.8" 848 | } 849 | }, 850 | "ms": { 851 | "version": "2.0.0", 852 | "bundled": true, 853 | "dev": true, 854 | "optional": true 855 | }, 856 | "needle": { 857 | "version": "2.2.0", 858 | "bundled": true, 859 | "dev": true, 860 | "optional": true, 861 | "requires": { 862 | "debug": "^2.1.2", 863 | "iconv-lite": "^0.4.4", 864 | "sax": "^1.2.4" 865 | } 866 | }, 867 | "node-pre-gyp": { 868 | "version": "0.10.0", 869 | "bundled": true, 870 | "dev": true, 871 | "optional": true, 872 | "requires": { 873 | "detect-libc": "^1.0.2", 874 | "mkdirp": "^0.5.1", 875 | "needle": "^2.2.0", 876 | "nopt": "^4.0.1", 877 | "npm-packlist": "^1.1.6", 878 | "npmlog": "^4.0.2", 879 | "rc": "^1.1.7", 880 | "rimraf": "^2.6.1", 881 | "semver": "^5.3.0", 882 | "tar": "^4" 883 | } 884 | }, 885 | "nopt": { 886 | "version": "4.0.1", 887 | "bundled": true, 888 | "dev": true, 889 | "optional": true, 890 | "requires": { 891 | "abbrev": "1", 892 | "osenv": "^0.1.4" 893 | } 894 | }, 895 | "npm-bundled": { 896 | "version": "1.0.3", 897 | "bundled": true, 898 | "dev": true, 899 | "optional": true 900 | }, 901 | "npm-packlist": { 902 | "version": "1.1.10", 903 | "bundled": true, 904 | "dev": true, 905 | "optional": true, 906 | "requires": { 907 | "ignore-walk": "^3.0.1", 908 | "npm-bundled": "^1.0.1" 909 | } 910 | }, 911 | "npmlog": { 912 | "version": "4.1.2", 913 | "bundled": true, 914 | "dev": true, 915 | "optional": true, 916 | "requires": { 917 | "are-we-there-yet": "~1.1.2", 918 | "console-control-strings": "~1.1.0", 919 | "gauge": "~2.7.3", 920 | "set-blocking": "~2.0.0" 921 | } 922 | }, 923 | "number-is-nan": { 924 | "version": "1.0.1", 925 | "bundled": true, 926 | "dev": true, 927 | "optional": true 928 | }, 929 | "object-assign": { 930 | "version": "4.1.1", 931 | "bundled": true, 932 | "dev": true, 933 | "optional": true 934 | }, 935 | "once": { 936 | "version": "1.4.0", 937 | "bundled": true, 938 | "dev": true, 939 | "optional": true, 940 | "requires": { 941 | "wrappy": "1" 942 | } 943 | }, 944 | "os-homedir": { 945 | "version": "1.0.2", 946 | "bundled": true, 947 | "dev": true, 948 | "optional": true 949 | }, 950 | "os-tmpdir": { 951 | "version": "1.0.2", 952 | "bundled": true, 953 | "dev": true, 954 | "optional": true 955 | }, 956 | "osenv": { 957 | "version": "0.1.5", 958 | "bundled": true, 959 | "dev": true, 960 | "optional": true, 961 | "requires": { 962 | "os-homedir": "^1.0.0", 963 | "os-tmpdir": "^1.0.0" 964 | } 965 | }, 966 | "path-is-absolute": { 967 | "version": "1.0.1", 968 | "bundled": true, 969 | "dev": true, 970 | "optional": true 971 | }, 972 | "process-nextick-args": { 973 | "version": "2.0.0", 974 | "bundled": true, 975 | "dev": true, 976 | "optional": true 977 | }, 978 | "rc": { 979 | "version": "1.2.7", 980 | "bundled": true, 981 | "dev": true, 982 | "optional": true, 983 | "requires": { 984 | "deep-extend": "^0.5.1", 985 | "ini": "~1.3.0", 986 | "minimist": "^1.2.0", 987 | "strip-json-comments": "~2.0.1" 988 | }, 989 | "dependencies": { 990 | "minimist": { 991 | "version": "1.2.0", 992 | "bundled": true, 993 | "dev": true, 994 | "optional": true 995 | } 996 | } 997 | }, 998 | "readable-stream": { 999 | "version": "2.3.6", 1000 | "bundled": true, 1001 | "dev": true, 1002 | "optional": true, 1003 | "requires": { 1004 | "core-util-is": "~1.0.0", 1005 | "inherits": "~2.0.3", 1006 | "isarray": "~1.0.0", 1007 | "process-nextick-args": "~2.0.0", 1008 | "safe-buffer": "~5.1.1", 1009 | "string_decoder": "~1.1.1", 1010 | "util-deprecate": "~1.0.1" 1011 | } 1012 | }, 1013 | "rimraf": { 1014 | "version": "2.6.2", 1015 | "bundled": true, 1016 | "dev": true, 1017 | "optional": true, 1018 | "requires": { 1019 | "glob": "^7.0.5" 1020 | } 1021 | }, 1022 | "safe-buffer": { 1023 | "version": "5.1.1", 1024 | "bundled": true, 1025 | "dev": true 1026 | }, 1027 | "safer-buffer": { 1028 | "version": "2.1.2", 1029 | "bundled": true, 1030 | "dev": true, 1031 | "optional": true 1032 | }, 1033 | "sax": { 1034 | "version": "1.2.4", 1035 | "bundled": true, 1036 | "dev": true, 1037 | "optional": true 1038 | }, 1039 | "semver": { 1040 | "version": "5.5.0", 1041 | "bundled": true, 1042 | "dev": true, 1043 | "optional": true 1044 | }, 1045 | "set-blocking": { 1046 | "version": "2.0.0", 1047 | "bundled": true, 1048 | "dev": true, 1049 | "optional": true 1050 | }, 1051 | "signal-exit": { 1052 | "version": "3.0.2", 1053 | "bundled": true, 1054 | "dev": true, 1055 | "optional": true 1056 | }, 1057 | "string-width": { 1058 | "version": "1.0.2", 1059 | "bundled": true, 1060 | "dev": true, 1061 | "optional": true, 1062 | "requires": { 1063 | "code-point-at": "^1.0.0", 1064 | "is-fullwidth-code-point": "^1.0.0", 1065 | "strip-ansi": "^3.0.0" 1066 | } 1067 | }, 1068 | "string_decoder": { 1069 | "version": "1.1.1", 1070 | "bundled": true, 1071 | "dev": true, 1072 | "optional": true, 1073 | "requires": { 1074 | "safe-buffer": "~5.1.0" 1075 | } 1076 | }, 1077 | "strip-ansi": { 1078 | "version": "3.0.1", 1079 | "bundled": true, 1080 | "dev": true, 1081 | "requires": { 1082 | "ansi-regex": "^2.0.0" 1083 | } 1084 | }, 1085 | "strip-json-comments": { 1086 | "version": "2.0.1", 1087 | "bundled": true, 1088 | "dev": true, 1089 | "optional": true 1090 | }, 1091 | "tar": { 1092 | "version": "4.4.1", 1093 | "bundled": true, 1094 | "dev": true, 1095 | "optional": true, 1096 | "requires": { 1097 | "chownr": "^1.0.1", 1098 | "fs-minipass": "^1.2.5", 1099 | "minipass": "^2.2.4", 1100 | "minizlib": "^1.1.0", 1101 | "mkdirp": "^0.5.0", 1102 | "safe-buffer": "^5.1.1", 1103 | "yallist": "^3.0.2" 1104 | } 1105 | }, 1106 | "util-deprecate": { 1107 | "version": "1.0.2", 1108 | "bundled": true, 1109 | "dev": true, 1110 | "optional": true 1111 | }, 1112 | "wide-align": { 1113 | "version": "1.1.2", 1114 | "bundled": true, 1115 | "dev": true, 1116 | "optional": true, 1117 | "requires": { 1118 | "string-width": "^1.0.2" 1119 | } 1120 | }, 1121 | "wrappy": { 1122 | "version": "1.0.2", 1123 | "bundled": true, 1124 | "dev": true 1125 | }, 1126 | "yallist": { 1127 | "version": "3.0.2", 1128 | "bundled": true, 1129 | "dev": true 1130 | } 1131 | } 1132 | }, 1133 | "function-bind": { 1134 | "version": "1.1.1", 1135 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 1136 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 1137 | "dev": true 1138 | }, 1139 | "glob": { 1140 | "version": "7.1.3", 1141 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", 1142 | "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", 1143 | "dev": true, 1144 | "requires": { 1145 | "fs.realpath": "^1.0.0", 1146 | "inflight": "^1.0.4", 1147 | "inherits": "2", 1148 | "minimatch": "^3.0.4", 1149 | "once": "^1.3.0", 1150 | "path-is-absolute": "^1.0.0" 1151 | } 1152 | }, 1153 | "glob-base": { 1154 | "version": "0.3.0", 1155 | "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", 1156 | "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", 1157 | "dev": true, 1158 | "requires": { 1159 | "glob-parent": "^2.0.0", 1160 | "is-glob": "^2.0.0" 1161 | } 1162 | }, 1163 | "glob-parent": { 1164 | "version": "2.0.0", 1165 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", 1166 | "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", 1167 | "dev": true, 1168 | "requires": { 1169 | "is-glob": "^2.0.0" 1170 | } 1171 | }, 1172 | "glob2base": { 1173 | "version": "0.0.12", 1174 | "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz", 1175 | "integrity": "sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=", 1176 | "dev": true, 1177 | "requires": { 1178 | "find-index": "^0.1.1" 1179 | } 1180 | }, 1181 | "graceful-fs": { 1182 | "version": "4.1.11", 1183 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", 1184 | "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", 1185 | "dev": true 1186 | }, 1187 | "has": { 1188 | "version": "1.0.3", 1189 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 1190 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 1191 | "dev": true, 1192 | "requires": { 1193 | "function-bind": "^1.1.1" 1194 | } 1195 | }, 1196 | "has-color": { 1197 | "version": "0.1.7", 1198 | "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", 1199 | "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=", 1200 | "dev": true 1201 | }, 1202 | "has-flag": { 1203 | "version": "3.0.0", 1204 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 1205 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 1206 | "dev": true 1207 | }, 1208 | "he": { 1209 | "version": "1.1.1", 1210 | "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", 1211 | "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", 1212 | "dev": true 1213 | }, 1214 | "hosted-git-info": { 1215 | "version": "2.7.1", 1216 | "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", 1217 | "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", 1218 | "dev": true 1219 | }, 1220 | "html-inline": { 1221 | "version": "1.2.0", 1222 | "resolved": "https://registry.npmjs.org/html-inline/-/html-inline-1.2.0.tgz", 1223 | "integrity": "sha1-eFSUam9cMSK5k7gdPTfWvQYAvsE=", 1224 | "dev": true, 1225 | "requires": { 1226 | "minimist": "~1.1.0", 1227 | "through2": "~0.6.3", 1228 | "trumpet": "~1.7.0" 1229 | }, 1230 | "dependencies": { 1231 | "minimist": { 1232 | "version": "1.1.3", 1233 | "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.1.3.tgz", 1234 | "integrity": "sha1-O+39kaktOQFvz6ocaB6Pqhoe/ag=", 1235 | "dev": true 1236 | } 1237 | } 1238 | }, 1239 | "html-minifier": { 1240 | "version": "3.5.20", 1241 | "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.20.tgz", 1242 | "integrity": "sha512-ZmgNLaTp54+HFKkONyLFEfs5dd/ZOtlquKaTnqIWFmx3Av5zG6ZPcV2d0o9XM2fXOTxxIf6eDcwzFFotke/5zA==", 1243 | "dev": true, 1244 | "requires": { 1245 | "camel-case": "3.0.x", 1246 | "clean-css": "4.2.x", 1247 | "commander": "2.17.x", 1248 | "he": "1.1.x", 1249 | "param-case": "2.1.x", 1250 | "relateurl": "0.2.x", 1251 | "uglify-js": "3.4.x" 1252 | }, 1253 | "dependencies": { 1254 | "commander": { 1255 | "version": "2.17.1", 1256 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", 1257 | "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", 1258 | "dev": true 1259 | }, 1260 | "uglify-js": { 1261 | "version": "3.4.9", 1262 | "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", 1263 | "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==", 1264 | "dev": true, 1265 | "requires": { 1266 | "commander": "~2.17.1", 1267 | "source-map": "~0.6.1" 1268 | } 1269 | } 1270 | } 1271 | }, 1272 | "html-select": { 1273 | "version": "2.3.24", 1274 | "resolved": "https://registry.npmjs.org/html-select/-/html-select-2.3.24.tgz", 1275 | "integrity": "sha1-Rq1tcS5zLPMcZznV0BEKX6vxdYU=", 1276 | "dev": true, 1277 | "requires": { 1278 | "cssauron": "^1.1.0", 1279 | "duplexer2": "~0.0.2", 1280 | "inherits": "^2.0.1", 1281 | "minimist": "~0.0.8", 1282 | "readable-stream": "^1.0.27-1", 1283 | "split": "~0.3.0", 1284 | "stream-splicer": "^1.2.0", 1285 | "through2": "^1.0.0" 1286 | }, 1287 | "dependencies": { 1288 | "isarray": { 1289 | "version": "0.0.1", 1290 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 1291 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", 1292 | "dev": true 1293 | }, 1294 | "readable-stream": { 1295 | "version": "1.1.14", 1296 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", 1297 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", 1298 | "dev": true, 1299 | "requires": { 1300 | "core-util-is": "~1.0.0", 1301 | "inherits": "~2.0.1", 1302 | "isarray": "0.0.1", 1303 | "string_decoder": "~0.10.x" 1304 | } 1305 | }, 1306 | "string_decoder": { 1307 | "version": "0.10.31", 1308 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 1309 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", 1310 | "dev": true 1311 | }, 1312 | "through2": { 1313 | "version": "1.1.1", 1314 | "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", 1315 | "integrity": "sha1-CEfLxESfNAVXTb3M2buEG4OsNUU=", 1316 | "dev": true, 1317 | "requires": { 1318 | "readable-stream": ">=1.1.13-1 <1.2.0-0", 1319 | "xtend": ">=4.0.0 <4.1.0-0" 1320 | } 1321 | } 1322 | } 1323 | }, 1324 | "html-tokenize": { 1325 | "version": "1.2.5", 1326 | "resolved": "https://registry.npmjs.org/html-tokenize/-/html-tokenize-1.2.5.tgz", 1327 | "integrity": "sha1-flupnstR75Buyaf83ubKMmfHiX4=", 1328 | "dev": true, 1329 | "requires": { 1330 | "inherits": "~2.0.1", 1331 | "minimist": "~0.0.8", 1332 | "readable-stream": "~1.0.27-1", 1333 | "through2": "~0.4.1" 1334 | }, 1335 | "dependencies": { 1336 | "isarray": { 1337 | "version": "0.0.1", 1338 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 1339 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", 1340 | "dev": true 1341 | }, 1342 | "readable-stream": { 1343 | "version": "1.0.34", 1344 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", 1345 | "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", 1346 | "dev": true, 1347 | "requires": { 1348 | "core-util-is": "~1.0.0", 1349 | "inherits": "~2.0.1", 1350 | "isarray": "0.0.1", 1351 | "string_decoder": "~0.10.x" 1352 | } 1353 | }, 1354 | "string_decoder": { 1355 | "version": "0.10.31", 1356 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 1357 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", 1358 | "dev": true 1359 | }, 1360 | "through2": { 1361 | "version": "0.4.2", 1362 | "resolved": "https://registry.npmjs.org/through2/-/through2-0.4.2.tgz", 1363 | "integrity": "sha1-2/WGYDEVHsg1K7bE22SiKSqEC5s=", 1364 | "dev": true, 1365 | "requires": { 1366 | "readable-stream": "~1.0.17", 1367 | "xtend": "~2.1.1" 1368 | } 1369 | }, 1370 | "xtend": { 1371 | "version": "2.1.2", 1372 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", 1373 | "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", 1374 | "dev": true, 1375 | "requires": { 1376 | "object-keys": "~0.4.0" 1377 | } 1378 | } 1379 | } 1380 | }, 1381 | "http-auth": { 1382 | "version": "3.1.3", 1383 | "resolved": "https://registry.npmjs.org/http-auth/-/http-auth-3.1.3.tgz", 1384 | "integrity": "sha1-lFz63WZSHq+PfISRPTd9exXyTjE=", 1385 | "dev": true, 1386 | "requires": { 1387 | "apache-crypt": "^1.1.2", 1388 | "apache-md5": "^1.0.6", 1389 | "bcryptjs": "^2.3.0", 1390 | "uuid": "^3.0.0" 1391 | } 1392 | }, 1393 | "http-errors": { 1394 | "version": "1.6.3", 1395 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", 1396 | "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", 1397 | "dev": true, 1398 | "requires": { 1399 | "depd": "~1.1.2", 1400 | "inherits": "2.0.3", 1401 | "setprototypeof": "1.1.0", 1402 | "statuses": ">= 1.4.0 < 2" 1403 | }, 1404 | "dependencies": { 1405 | "statuses": { 1406 | "version": "1.5.0", 1407 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", 1408 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", 1409 | "dev": true 1410 | } 1411 | } 1412 | }, 1413 | "http-parser-js": { 1414 | "version": "0.4.13", 1415 | "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.13.tgz", 1416 | "integrity": "sha1-O9bW/ebjFyyTNMOzO2wZPYD+ETc=", 1417 | "dev": true 1418 | }, 1419 | "indexof": { 1420 | "version": "0.0.1", 1421 | "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", 1422 | "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", 1423 | "dev": true 1424 | }, 1425 | "inflight": { 1426 | "version": "1.0.6", 1427 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 1428 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 1429 | "dev": true, 1430 | "requires": { 1431 | "once": "^1.3.0", 1432 | "wrappy": "1" 1433 | } 1434 | }, 1435 | "inherits": { 1436 | "version": "2.0.3", 1437 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 1438 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 1439 | "dev": true 1440 | }, 1441 | "is-arrayish": { 1442 | "version": "0.2.1", 1443 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", 1444 | "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", 1445 | "dev": true 1446 | }, 1447 | "is-binary-path": { 1448 | "version": "1.0.1", 1449 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", 1450 | "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", 1451 | "dev": true, 1452 | "requires": { 1453 | "binary-extensions": "^1.0.0" 1454 | } 1455 | }, 1456 | "is-buffer": { 1457 | "version": "1.1.6", 1458 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", 1459 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", 1460 | "dev": true 1461 | }, 1462 | "is-builtin-module": { 1463 | "version": "1.0.0", 1464 | "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", 1465 | "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", 1466 | "dev": true, 1467 | "requires": { 1468 | "builtin-modules": "^1.0.0" 1469 | } 1470 | }, 1471 | "is-callable": { 1472 | "version": "1.1.4", 1473 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", 1474 | "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", 1475 | "dev": true 1476 | }, 1477 | "is-date-object": { 1478 | "version": "1.0.1", 1479 | "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", 1480 | "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", 1481 | "dev": true 1482 | }, 1483 | "is-dotfile": { 1484 | "version": "1.0.3", 1485 | "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", 1486 | "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", 1487 | "dev": true 1488 | }, 1489 | "is-equal-shallow": { 1490 | "version": "0.1.3", 1491 | "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", 1492 | "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", 1493 | "dev": true, 1494 | "requires": { 1495 | "is-primitive": "^2.0.0" 1496 | } 1497 | }, 1498 | "is-extendable": { 1499 | "version": "0.1.1", 1500 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", 1501 | "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", 1502 | "dev": true 1503 | }, 1504 | "is-extglob": { 1505 | "version": "1.0.0", 1506 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", 1507 | "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", 1508 | "dev": true 1509 | }, 1510 | "is-glob": { 1511 | "version": "2.0.1", 1512 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", 1513 | "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", 1514 | "dev": true, 1515 | "requires": { 1516 | "is-extglob": "^1.0.0" 1517 | } 1518 | }, 1519 | "is-number": { 1520 | "version": "2.1.0", 1521 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", 1522 | "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", 1523 | "dev": true, 1524 | "requires": { 1525 | "kind-of": "^3.0.2" 1526 | } 1527 | }, 1528 | "is-posix-bracket": { 1529 | "version": "0.1.1", 1530 | "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", 1531 | "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", 1532 | "dev": true 1533 | }, 1534 | "is-primitive": { 1535 | "version": "2.0.0", 1536 | "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", 1537 | "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", 1538 | "dev": true 1539 | }, 1540 | "is-regex": { 1541 | "version": "1.0.4", 1542 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", 1543 | "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", 1544 | "dev": true, 1545 | "requires": { 1546 | "has": "^1.0.1" 1547 | } 1548 | }, 1549 | "is-symbol": { 1550 | "version": "1.0.1", 1551 | "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", 1552 | "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", 1553 | "dev": true 1554 | }, 1555 | "is-wsl": { 1556 | "version": "1.1.0", 1557 | "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", 1558 | "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", 1559 | "dev": true 1560 | }, 1561 | "isarray": { 1562 | "version": "1.0.0", 1563 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 1564 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", 1565 | "dev": true 1566 | }, 1567 | "isexe": { 1568 | "version": "2.0.0", 1569 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1570 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 1571 | "dev": true 1572 | }, 1573 | "isobject": { 1574 | "version": "2.1.0", 1575 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", 1576 | "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", 1577 | "dev": true, 1578 | "requires": { 1579 | "isarray": "1.0.0" 1580 | } 1581 | }, 1582 | "json-parse-better-errors": { 1583 | "version": "1.0.2", 1584 | "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", 1585 | "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", 1586 | "dev": true 1587 | }, 1588 | "jsonify": { 1589 | "version": "0.0.0", 1590 | "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", 1591 | "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", 1592 | "dev": true 1593 | }, 1594 | "kind-of": { 1595 | "version": "3.2.2", 1596 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 1597 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 1598 | "dev": true, 1599 | "requires": { 1600 | "is-buffer": "^1.1.5" 1601 | } 1602 | }, 1603 | "live-server": { 1604 | "version": "1.2.0", 1605 | "resolved": "https://registry.npmjs.org/live-server/-/live-server-1.2.0.tgz", 1606 | "integrity": "sha1-RJhkS7+Bpm8Y3Y3/3vYcTBw3TKM=", 1607 | "dev": true, 1608 | "requires": { 1609 | "chokidar": "^1.6.0", 1610 | "colors": "^1.3.1", 1611 | "connect": "3.5.x", 1612 | "cors": "^2.8.4", 1613 | "event-stream": "^3.3.4", 1614 | "faye-websocket": "0.11.x", 1615 | "http-auth": "3.1.x", 1616 | "morgan": "^1.6.1", 1617 | "object-assign": "^4.1.1", 1618 | "opn": "^5.3.0", 1619 | "proxy-middleware": "^0.15.0", 1620 | "send": "^0.16.2", 1621 | "serve-index": "^1.7.2" 1622 | } 1623 | }, 1624 | "load-json-file": { 1625 | "version": "4.0.0", 1626 | "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", 1627 | "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", 1628 | "dev": true, 1629 | "requires": { 1630 | "graceful-fs": "^4.1.2", 1631 | "parse-json": "^4.0.0", 1632 | "pify": "^3.0.0", 1633 | "strip-bom": "^3.0.0" 1634 | } 1635 | }, 1636 | "lower-case": { 1637 | "version": "1.1.4", 1638 | "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", 1639 | "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", 1640 | "dev": true 1641 | }, 1642 | "map-stream": { 1643 | "version": "0.1.0", 1644 | "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", 1645 | "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", 1646 | "dev": true 1647 | }, 1648 | "math-random": { 1649 | "version": "1.0.1", 1650 | "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz", 1651 | "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=", 1652 | "dev": true 1653 | }, 1654 | "memorystream": { 1655 | "version": "0.3.1", 1656 | "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", 1657 | "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", 1658 | "dev": true 1659 | }, 1660 | "micromatch": { 1661 | "version": "2.3.11", 1662 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", 1663 | "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", 1664 | "dev": true, 1665 | "requires": { 1666 | "arr-diff": "^2.0.0", 1667 | "array-unique": "^0.2.1", 1668 | "braces": "^1.8.2", 1669 | "expand-brackets": "^0.1.4", 1670 | "extglob": "^0.3.1", 1671 | "filename-regex": "^2.0.0", 1672 | "is-extglob": "^1.0.0", 1673 | "is-glob": "^2.0.1", 1674 | "kind-of": "^3.0.2", 1675 | "normalize-path": "^2.0.1", 1676 | "object.omit": "^2.0.0", 1677 | "parse-glob": "^3.0.4", 1678 | "regex-cache": "^0.4.2" 1679 | } 1680 | }, 1681 | "mime": { 1682 | "version": "1.4.1", 1683 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", 1684 | "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", 1685 | "dev": true 1686 | }, 1687 | "mime-db": { 1688 | "version": "1.35.0", 1689 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz", 1690 | "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==", 1691 | "dev": true 1692 | }, 1693 | "mime-types": { 1694 | "version": "2.1.19", 1695 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz", 1696 | "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", 1697 | "dev": true, 1698 | "requires": { 1699 | "mime-db": "~1.35.0" 1700 | } 1701 | }, 1702 | "minimatch": { 1703 | "version": "3.0.4", 1704 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 1705 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 1706 | "dev": true, 1707 | "requires": { 1708 | "brace-expansion": "^1.1.7" 1709 | } 1710 | }, 1711 | "minimist": { 1712 | "version": "0.0.8", 1713 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 1714 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 1715 | "dev": true 1716 | }, 1717 | "mkdirp": { 1718 | "version": "0.5.1", 1719 | "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 1720 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 1721 | "dev": true, 1722 | "requires": { 1723 | "minimist": "0.0.8" 1724 | } 1725 | }, 1726 | "morgan": { 1727 | "version": "1.9.0", 1728 | "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.0.tgz", 1729 | "integrity": "sha1-0B+mxlhZt2/PMbPLU6OCGjEdgFE=", 1730 | "dev": true, 1731 | "requires": { 1732 | "basic-auth": "~2.0.0", 1733 | "debug": "2.6.9", 1734 | "depd": "~1.1.1", 1735 | "on-finished": "~2.3.0", 1736 | "on-headers": "~1.0.1" 1737 | }, 1738 | "dependencies": { 1739 | "debug": { 1740 | "version": "2.6.9", 1741 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 1742 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 1743 | "dev": true, 1744 | "requires": { 1745 | "ms": "2.0.0" 1746 | } 1747 | }, 1748 | "ms": { 1749 | "version": "2.0.0", 1750 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 1751 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 1752 | "dev": true 1753 | } 1754 | } 1755 | }, 1756 | "ms": { 1757 | "version": "0.7.1", 1758 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", 1759 | "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", 1760 | "dev": true 1761 | }, 1762 | "nan": { 1763 | "version": "2.10.0", 1764 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", 1765 | "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", 1766 | "dev": true, 1767 | "optional": true 1768 | }, 1769 | "negotiator": { 1770 | "version": "0.6.1", 1771 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", 1772 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", 1773 | "dev": true 1774 | }, 1775 | "nice-try": { 1776 | "version": "1.0.5", 1777 | "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", 1778 | "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", 1779 | "dev": true 1780 | }, 1781 | "no-case": { 1782 | "version": "2.3.2", 1783 | "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", 1784 | "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", 1785 | "dev": true, 1786 | "requires": { 1787 | "lower-case": "^1.1.1" 1788 | } 1789 | }, 1790 | "nomnom": { 1791 | "version": "1.8.1", 1792 | "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", 1793 | "integrity": "sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=", 1794 | "dev": true, 1795 | "requires": { 1796 | "chalk": "~0.4.0", 1797 | "underscore": "~1.6.0" 1798 | } 1799 | }, 1800 | "normalize-package-data": { 1801 | "version": "2.4.0", 1802 | "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", 1803 | "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", 1804 | "dev": true, 1805 | "requires": { 1806 | "hosted-git-info": "^2.1.4", 1807 | "is-builtin-module": "^1.0.0", 1808 | "semver": "2 || 3 || 4 || 5", 1809 | "validate-npm-package-license": "^3.0.1" 1810 | } 1811 | }, 1812 | "normalize-path": { 1813 | "version": "2.1.1", 1814 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", 1815 | "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", 1816 | "dev": true, 1817 | "requires": { 1818 | "remove-trailing-separator": "^1.0.1" 1819 | } 1820 | }, 1821 | "npm-run-all": { 1822 | "version": "4.1.3", 1823 | "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.3.tgz", 1824 | "integrity": "sha512-aOG0N3Eo/WW+q6sUIdzcV2COS8VnTZCmdji0VQIAZF3b+a3YWb0AD0vFIyjKec18A7beLGbaQ5jFTNI2bPt9Cg==", 1825 | "dev": true, 1826 | "requires": { 1827 | "ansi-styles": "^3.2.0", 1828 | "chalk": "^2.1.0", 1829 | "cross-spawn": "^6.0.4", 1830 | "memorystream": "^0.3.1", 1831 | "minimatch": "^3.0.4", 1832 | "ps-tree": "^1.1.0", 1833 | "read-pkg": "^3.0.0", 1834 | "shell-quote": "^1.6.1", 1835 | "string.prototype.padend": "^3.0.0" 1836 | }, 1837 | "dependencies": { 1838 | "ansi-styles": { 1839 | "version": "3.2.1", 1840 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 1841 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 1842 | "dev": true, 1843 | "requires": { 1844 | "color-convert": "^1.9.0" 1845 | } 1846 | }, 1847 | "chalk": { 1848 | "version": "2.4.1", 1849 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", 1850 | "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", 1851 | "dev": true, 1852 | "requires": { 1853 | "ansi-styles": "^3.2.1", 1854 | "escape-string-regexp": "^1.0.5", 1855 | "supports-color": "^5.3.0" 1856 | } 1857 | } 1858 | } 1859 | }, 1860 | "object-assign": { 1861 | "version": "4.1.1", 1862 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 1863 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", 1864 | "dev": true 1865 | }, 1866 | "object-keys": { 1867 | "version": "0.4.0", 1868 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", 1869 | "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=", 1870 | "dev": true 1871 | }, 1872 | "object.omit": { 1873 | "version": "2.0.1", 1874 | "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", 1875 | "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", 1876 | "dev": true, 1877 | "requires": { 1878 | "for-own": "^0.1.4", 1879 | "is-extendable": "^0.1.1" 1880 | } 1881 | }, 1882 | "on-finished": { 1883 | "version": "2.3.0", 1884 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 1885 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 1886 | "dev": true, 1887 | "requires": { 1888 | "ee-first": "1.1.1" 1889 | } 1890 | }, 1891 | "on-headers": { 1892 | "version": "1.0.1", 1893 | "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", 1894 | "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=", 1895 | "dev": true 1896 | }, 1897 | "once": { 1898 | "version": "1.4.0", 1899 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1900 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1901 | "dev": true, 1902 | "requires": { 1903 | "wrappy": "1" 1904 | } 1905 | }, 1906 | "opn": { 1907 | "version": "5.3.0", 1908 | "resolved": "https://registry.npmjs.org/opn/-/opn-5.3.0.tgz", 1909 | "integrity": "sha512-bYJHo/LOmoTd+pfiYhfZDnf9zekVJrY+cnS2a5F2x+w5ppvTqObojTP7WiFG+kVZs9Inw+qQ/lw7TroWwhdd2g==", 1910 | "dev": true, 1911 | "requires": { 1912 | "is-wsl": "^1.1.0" 1913 | } 1914 | }, 1915 | "param-case": { 1916 | "version": "2.1.1", 1917 | "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", 1918 | "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", 1919 | "dev": true, 1920 | "requires": { 1921 | "no-case": "^2.2.0" 1922 | } 1923 | }, 1924 | "parse-glob": { 1925 | "version": "3.0.4", 1926 | "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", 1927 | "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", 1928 | "dev": true, 1929 | "requires": { 1930 | "glob-base": "^0.3.0", 1931 | "is-dotfile": "^1.0.0", 1932 | "is-extglob": "^1.0.0", 1933 | "is-glob": "^2.0.0" 1934 | } 1935 | }, 1936 | "parse-json": { 1937 | "version": "4.0.0", 1938 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", 1939 | "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", 1940 | "dev": true, 1941 | "requires": { 1942 | "error-ex": "^1.3.1", 1943 | "json-parse-better-errors": "^1.0.1" 1944 | } 1945 | }, 1946 | "parseurl": { 1947 | "version": "1.3.2", 1948 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", 1949 | "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", 1950 | "dev": true 1951 | }, 1952 | "path-is-absolute": { 1953 | "version": "1.0.1", 1954 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1955 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 1956 | "dev": true 1957 | }, 1958 | "path-key": { 1959 | "version": "2.0.1", 1960 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", 1961 | "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", 1962 | "dev": true 1963 | }, 1964 | "path-parse": { 1965 | "version": "1.0.6", 1966 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 1967 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", 1968 | "dev": true 1969 | }, 1970 | "path-type": { 1971 | "version": "3.0.0", 1972 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", 1973 | "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", 1974 | "dev": true, 1975 | "requires": { 1976 | "pify": "^3.0.0" 1977 | } 1978 | }, 1979 | "pause-stream": { 1980 | "version": "0.0.11", 1981 | "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", 1982 | "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", 1983 | "dev": true, 1984 | "requires": { 1985 | "through": "~2.3" 1986 | } 1987 | }, 1988 | "pify": { 1989 | "version": "3.0.0", 1990 | "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", 1991 | "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", 1992 | "dev": true 1993 | }, 1994 | "preserve": { 1995 | "version": "0.2.0", 1996 | "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", 1997 | "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", 1998 | "dev": true 1999 | }, 2000 | "process-nextick-args": { 2001 | "version": "2.0.0", 2002 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", 2003 | "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", 2004 | "dev": true 2005 | }, 2006 | "proxy-middleware": { 2007 | "version": "0.15.0", 2008 | "resolved": "https://registry.npmjs.org/proxy-middleware/-/proxy-middleware-0.15.0.tgz", 2009 | "integrity": "sha1-o/3xvvtzD5UZZYcqwvYHTGFHelY=", 2010 | "dev": true 2011 | }, 2012 | "ps-tree": { 2013 | "version": "1.1.0", 2014 | "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.1.0.tgz", 2015 | "integrity": "sha1-tCGyQUDWID8e08dplrRCewjowBQ=", 2016 | "dev": true, 2017 | "requires": { 2018 | "event-stream": "~3.3.0" 2019 | } 2020 | }, 2021 | "randomatic": { 2022 | "version": "3.1.0", 2023 | "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.0.tgz", 2024 | "integrity": "sha512-KnGPVE0lo2WoXxIZ7cPR8YBpiol4gsSuOwDSg410oHh80ZMp5EiypNqL2K4Z77vJn6lB5rap7IkAmcUlalcnBQ==", 2025 | "dev": true, 2026 | "requires": { 2027 | "is-number": "^4.0.0", 2028 | "kind-of": "^6.0.0", 2029 | "math-random": "^1.0.1" 2030 | }, 2031 | "dependencies": { 2032 | "is-number": { 2033 | "version": "4.0.0", 2034 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", 2035 | "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", 2036 | "dev": true 2037 | }, 2038 | "kind-of": { 2039 | "version": "6.0.2", 2040 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", 2041 | "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", 2042 | "dev": true 2043 | } 2044 | } 2045 | }, 2046 | "range-parser": { 2047 | "version": "1.2.0", 2048 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", 2049 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", 2050 | "dev": true 2051 | }, 2052 | "read-pkg": { 2053 | "version": "3.0.0", 2054 | "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", 2055 | "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", 2056 | "dev": true, 2057 | "requires": { 2058 | "load-json-file": "^4.0.0", 2059 | "normalize-package-data": "^2.3.2", 2060 | "path-type": "^3.0.0" 2061 | } 2062 | }, 2063 | "readable-stream": { 2064 | "version": "2.3.6", 2065 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", 2066 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", 2067 | "dev": true, 2068 | "requires": { 2069 | "core-util-is": "~1.0.0", 2070 | "inherits": "~2.0.3", 2071 | "isarray": "~1.0.0", 2072 | "process-nextick-args": "~2.0.0", 2073 | "safe-buffer": "~5.1.1", 2074 | "string_decoder": "~1.1.1", 2075 | "util-deprecate": "~1.0.1" 2076 | } 2077 | }, 2078 | "readable-wrap": { 2079 | "version": "1.0.0", 2080 | "resolved": "https://registry.npmjs.org/readable-wrap/-/readable-wrap-1.0.0.tgz", 2081 | "integrity": "sha1-O1ohHGMeEjA6VJkcgGwX564ga/8=", 2082 | "dev": true, 2083 | "requires": { 2084 | "readable-stream": "^1.1.13-1" 2085 | }, 2086 | "dependencies": { 2087 | "isarray": { 2088 | "version": "0.0.1", 2089 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 2090 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", 2091 | "dev": true 2092 | }, 2093 | "readable-stream": { 2094 | "version": "1.1.14", 2095 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", 2096 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", 2097 | "dev": true, 2098 | "requires": { 2099 | "core-util-is": "~1.0.0", 2100 | "inherits": "~2.0.1", 2101 | "isarray": "0.0.1", 2102 | "string_decoder": "~0.10.x" 2103 | } 2104 | }, 2105 | "string_decoder": { 2106 | "version": "0.10.31", 2107 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 2108 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", 2109 | "dev": true 2110 | } 2111 | } 2112 | }, 2113 | "readdirp": { 2114 | "version": "2.1.0", 2115 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", 2116 | "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", 2117 | "dev": true, 2118 | "requires": { 2119 | "graceful-fs": "^4.1.2", 2120 | "minimatch": "^3.0.2", 2121 | "readable-stream": "^2.0.2", 2122 | "set-immediate-shim": "^1.0.1" 2123 | } 2124 | }, 2125 | "regenerator-runtime": { 2126 | "version": "0.11.1", 2127 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", 2128 | "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", 2129 | "dev": true 2130 | }, 2131 | "regex-cache": { 2132 | "version": "0.4.4", 2133 | "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", 2134 | "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", 2135 | "dev": true, 2136 | "requires": { 2137 | "is-equal-shallow": "^0.1.3" 2138 | } 2139 | }, 2140 | "relateurl": { 2141 | "version": "0.2.7", 2142 | "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", 2143 | "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", 2144 | "dev": true 2145 | }, 2146 | "remove-trailing-separator": { 2147 | "version": "1.1.0", 2148 | "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", 2149 | "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", 2150 | "dev": true 2151 | }, 2152 | "repeat-element": { 2153 | "version": "1.1.2", 2154 | "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", 2155 | "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", 2156 | "dev": true 2157 | }, 2158 | "repeat-string": { 2159 | "version": "1.6.1", 2160 | "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", 2161 | "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", 2162 | "dev": true 2163 | }, 2164 | "replace": { 2165 | "version": "1.0.0", 2166 | "resolved": "https://registry.npmjs.org/replace/-/replace-1.0.0.tgz", 2167 | "integrity": "sha512-5qUu+E1YMF9AMeVEoXa9VjEEgHk7cRNs3GWAN3Z1mt0ugwUxFuuXkDuoOS3nuvN9gH4KR/8Bd2R/Q944ofGtuA==", 2168 | "dev": true, 2169 | "requires": { 2170 | "colors": "1.2.4", 2171 | "minimatch": "3.0.4", 2172 | "nomnom": "1.8.1" 2173 | }, 2174 | "dependencies": { 2175 | "colors": { 2176 | "version": "1.2.4", 2177 | "resolved": "https://registry.npmjs.org/colors/-/colors-1.2.4.tgz", 2178 | "integrity": "sha512-6Y+iBnWmXL+AWtlOp2Vr6R2w5MUlNJRwR0ShVFaAb1CqWzhPOpQg4L0jxD+xpw/Nc8QJwaq3KM79QUCriY8CWQ==", 2179 | "dev": true 2180 | } 2181 | } 2182 | }, 2183 | "resolve": { 2184 | "version": "1.8.1", 2185 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", 2186 | "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", 2187 | "dev": true, 2188 | "requires": { 2189 | "path-parse": "^1.0.5" 2190 | } 2191 | }, 2192 | "rimraf": { 2193 | "version": "2.6.2", 2194 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", 2195 | "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", 2196 | "dev": true, 2197 | "requires": { 2198 | "glob": "^7.0.5" 2199 | } 2200 | }, 2201 | "safe-buffer": { 2202 | "version": "5.1.2", 2203 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 2204 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 2205 | "dev": true 2206 | }, 2207 | "semver": { 2208 | "version": "5.5.1", 2209 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", 2210 | "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==", 2211 | "dev": true 2212 | }, 2213 | "send": { 2214 | "version": "0.16.2", 2215 | "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", 2216 | "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", 2217 | "dev": true, 2218 | "requires": { 2219 | "debug": "2.6.9", 2220 | "depd": "~1.1.2", 2221 | "destroy": "~1.0.4", 2222 | "encodeurl": "~1.0.2", 2223 | "escape-html": "~1.0.3", 2224 | "etag": "~1.8.1", 2225 | "fresh": "0.5.2", 2226 | "http-errors": "~1.6.2", 2227 | "mime": "1.4.1", 2228 | "ms": "2.0.0", 2229 | "on-finished": "~2.3.0", 2230 | "range-parser": "~1.2.0", 2231 | "statuses": "~1.4.0" 2232 | }, 2233 | "dependencies": { 2234 | "debug": { 2235 | "version": "2.6.9", 2236 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 2237 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 2238 | "dev": true, 2239 | "requires": { 2240 | "ms": "2.0.0" 2241 | } 2242 | }, 2243 | "ms": { 2244 | "version": "2.0.0", 2245 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 2246 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 2247 | "dev": true 2248 | }, 2249 | "statuses": { 2250 | "version": "1.4.0", 2251 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 2252 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", 2253 | "dev": true 2254 | } 2255 | } 2256 | }, 2257 | "serve-index": { 2258 | "version": "1.9.1", 2259 | "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", 2260 | "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", 2261 | "dev": true, 2262 | "requires": { 2263 | "accepts": "~1.3.4", 2264 | "batch": "0.6.1", 2265 | "debug": "2.6.9", 2266 | "escape-html": "~1.0.3", 2267 | "http-errors": "~1.6.2", 2268 | "mime-types": "~2.1.17", 2269 | "parseurl": "~1.3.2" 2270 | }, 2271 | "dependencies": { 2272 | "debug": { 2273 | "version": "2.6.9", 2274 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 2275 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 2276 | "dev": true, 2277 | "requires": { 2278 | "ms": "2.0.0" 2279 | } 2280 | }, 2281 | "ms": { 2282 | "version": "2.0.0", 2283 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 2284 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 2285 | "dev": true 2286 | } 2287 | } 2288 | }, 2289 | "set-immediate-shim": { 2290 | "version": "1.0.1", 2291 | "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", 2292 | "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", 2293 | "dev": true 2294 | }, 2295 | "setprototypeof": { 2296 | "version": "1.1.0", 2297 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", 2298 | "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", 2299 | "dev": true 2300 | }, 2301 | "shebang-command": { 2302 | "version": "1.2.0", 2303 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", 2304 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", 2305 | "dev": true, 2306 | "requires": { 2307 | "shebang-regex": "^1.0.0" 2308 | } 2309 | }, 2310 | "shebang-regex": { 2311 | "version": "1.0.0", 2312 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", 2313 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", 2314 | "dev": true 2315 | }, 2316 | "shell-quote": { 2317 | "version": "1.6.1", 2318 | "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", 2319 | "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", 2320 | "dev": true, 2321 | "requires": { 2322 | "array-filter": "~0.0.0", 2323 | "array-map": "~0.0.0", 2324 | "array-reduce": "~0.0.0", 2325 | "jsonify": "~0.0.0" 2326 | } 2327 | }, 2328 | "source-map": { 2329 | "version": "0.6.1", 2330 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 2331 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 2332 | "dev": true 2333 | }, 2334 | "spdx-correct": { 2335 | "version": "3.0.0", 2336 | "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", 2337 | "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", 2338 | "dev": true, 2339 | "requires": { 2340 | "spdx-expression-parse": "^3.0.0", 2341 | "spdx-license-ids": "^3.0.0" 2342 | } 2343 | }, 2344 | "spdx-exceptions": { 2345 | "version": "2.1.0", 2346 | "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", 2347 | "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", 2348 | "dev": true 2349 | }, 2350 | "spdx-expression-parse": { 2351 | "version": "3.0.0", 2352 | "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", 2353 | "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", 2354 | "dev": true, 2355 | "requires": { 2356 | "spdx-exceptions": "^2.1.0", 2357 | "spdx-license-ids": "^3.0.0" 2358 | } 2359 | }, 2360 | "spdx-license-ids": { 2361 | "version": "3.0.1", 2362 | "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.1.tgz", 2363 | "integrity": "sha512-TfOfPcYGBB5sDuPn3deByxPhmfegAhpDYKSOXZQN81Oyrrif8ZCodOLzK3AesELnCx03kikhyDwh0pfvvQvF8w==", 2364 | "dev": true 2365 | }, 2366 | "split": { 2367 | "version": "0.3.3", 2368 | "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", 2369 | "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", 2370 | "dev": true, 2371 | "requires": { 2372 | "through": "2" 2373 | } 2374 | }, 2375 | "statuses": { 2376 | "version": "1.3.1", 2377 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", 2378 | "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", 2379 | "dev": true 2380 | }, 2381 | "stream-combiner": { 2382 | "version": "0.0.4", 2383 | "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", 2384 | "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", 2385 | "dev": true, 2386 | "requires": { 2387 | "duplexer": "~0.1.1" 2388 | } 2389 | }, 2390 | "stream-splicer": { 2391 | "version": "1.3.2", 2392 | "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-1.3.2.tgz", 2393 | "integrity": "sha1-PARBvhW5v04iYnXm3IOWR0VUZmE=", 2394 | "dev": true, 2395 | "requires": { 2396 | "indexof": "0.0.1", 2397 | "inherits": "^2.0.1", 2398 | "isarray": "~0.0.1", 2399 | "readable-stream": "^1.1.13-1", 2400 | "readable-wrap": "^1.0.0", 2401 | "through2": "^1.0.0" 2402 | }, 2403 | "dependencies": { 2404 | "isarray": { 2405 | "version": "0.0.1", 2406 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 2407 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", 2408 | "dev": true 2409 | }, 2410 | "readable-stream": { 2411 | "version": "1.1.14", 2412 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", 2413 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", 2414 | "dev": true, 2415 | "requires": { 2416 | "core-util-is": "~1.0.0", 2417 | "inherits": "~2.0.1", 2418 | "isarray": "0.0.1", 2419 | "string_decoder": "~0.10.x" 2420 | } 2421 | }, 2422 | "string_decoder": { 2423 | "version": "0.10.31", 2424 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 2425 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", 2426 | "dev": true 2427 | }, 2428 | "through2": { 2429 | "version": "1.1.1", 2430 | "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", 2431 | "integrity": "sha1-CEfLxESfNAVXTb3M2buEG4OsNUU=", 2432 | "dev": true, 2433 | "requires": { 2434 | "readable-stream": ">=1.1.13-1 <1.2.0-0", 2435 | "xtend": ">=4.0.0 <4.1.0-0" 2436 | } 2437 | } 2438 | } 2439 | }, 2440 | "string.prototype.padend": { 2441 | "version": "3.0.0", 2442 | "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz", 2443 | "integrity": "sha1-86rvfBcZ8XDF6rHDK/eA2W4h8vA=", 2444 | "dev": true, 2445 | "requires": { 2446 | "define-properties": "^1.1.2", 2447 | "es-abstract": "^1.4.3", 2448 | "function-bind": "^1.0.2" 2449 | } 2450 | }, 2451 | "string_decoder": { 2452 | "version": "1.1.1", 2453 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 2454 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 2455 | "dev": true, 2456 | "requires": { 2457 | "safe-buffer": "~5.1.0" 2458 | } 2459 | }, 2460 | "strip-ansi": { 2461 | "version": "0.1.1", 2462 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", 2463 | "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=", 2464 | "dev": true 2465 | }, 2466 | "strip-bom": { 2467 | "version": "3.0.0", 2468 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", 2469 | "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", 2470 | "dev": true 2471 | }, 2472 | "subarg": { 2473 | "version": "1.0.0", 2474 | "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", 2475 | "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", 2476 | "dev": true, 2477 | "requires": { 2478 | "minimist": "^1.1.0" 2479 | }, 2480 | "dependencies": { 2481 | "minimist": { 2482 | "version": "1.2.0", 2483 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 2484 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", 2485 | "dev": true 2486 | } 2487 | } 2488 | }, 2489 | "supports-color": { 2490 | "version": "5.5.0", 2491 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 2492 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 2493 | "dev": true, 2494 | "requires": { 2495 | "has-flag": "^3.0.0" 2496 | } 2497 | }, 2498 | "through": { 2499 | "version": "2.3.8", 2500 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 2501 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", 2502 | "dev": true 2503 | }, 2504 | "through2": { 2505 | "version": "0.6.5", 2506 | "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", 2507 | "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", 2508 | "dev": true, 2509 | "requires": { 2510 | "readable-stream": ">=1.0.33-1 <1.1.0-0", 2511 | "xtend": ">=4.0.0 <4.1.0-0" 2512 | }, 2513 | "dependencies": { 2514 | "isarray": { 2515 | "version": "0.0.1", 2516 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 2517 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", 2518 | "dev": true 2519 | }, 2520 | "readable-stream": { 2521 | "version": "1.0.34", 2522 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", 2523 | "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", 2524 | "dev": true, 2525 | "requires": { 2526 | "core-util-is": "~1.0.0", 2527 | "inherits": "~2.0.1", 2528 | "isarray": "0.0.1", 2529 | "string_decoder": "~0.10.x" 2530 | } 2531 | }, 2532 | "string_decoder": { 2533 | "version": "0.10.31", 2534 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 2535 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", 2536 | "dev": true 2537 | } 2538 | } 2539 | }, 2540 | "trumpet": { 2541 | "version": "1.7.2", 2542 | "resolved": "https://registry.npmjs.org/trumpet/-/trumpet-1.7.2.tgz", 2543 | "integrity": "sha1-sCxp5GXRcfVeRJJL+bW90gl0yDA=", 2544 | "dev": true, 2545 | "requires": { 2546 | "duplexer2": "~0.0.2", 2547 | "html-select": "^2.3.5", 2548 | "html-tokenize": "^1.1.1", 2549 | "inherits": "^2.0.0", 2550 | "readable-stream": "^1.0.27-1", 2551 | "through2": "^1.0.0" 2552 | }, 2553 | "dependencies": { 2554 | "isarray": { 2555 | "version": "0.0.1", 2556 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 2557 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", 2558 | "dev": true 2559 | }, 2560 | "readable-stream": { 2561 | "version": "1.1.14", 2562 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", 2563 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", 2564 | "dev": true, 2565 | "requires": { 2566 | "core-util-is": "~1.0.0", 2567 | "inherits": "~2.0.1", 2568 | "isarray": "0.0.1", 2569 | "string_decoder": "~0.10.x" 2570 | } 2571 | }, 2572 | "string_decoder": { 2573 | "version": "0.10.31", 2574 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 2575 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", 2576 | "dev": true 2577 | }, 2578 | "through2": { 2579 | "version": "1.1.1", 2580 | "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz", 2581 | "integrity": "sha1-CEfLxESfNAVXTb3M2buEG4OsNUU=", 2582 | "dev": true, 2583 | "requires": { 2584 | "readable-stream": ">=1.1.13-1 <1.2.0-0", 2585 | "xtend": ">=4.0.0 <4.1.0-0" 2586 | } 2587 | } 2588 | } 2589 | }, 2590 | "typescript": { 2591 | "version": "3.0.3", 2592 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.0.3.tgz", 2593 | "integrity": "sha512-kk80vLW9iGtjMnIv11qyxLqZm20UklzuR2tL0QAnDIygIUIemcZMxlMWudl9OOt76H3ntVzcTiddQ1/pAAJMYg==", 2594 | "dev": true 2595 | }, 2596 | "uglify-es": { 2597 | "version": "3.3.9", 2598 | "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz", 2599 | "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==", 2600 | "dev": true, 2601 | "requires": { 2602 | "commander": "~2.13.0", 2603 | "source-map": "~0.6.1" 2604 | } 2605 | }, 2606 | "underscore": { 2607 | "version": "1.6.0", 2608 | "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", 2609 | "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", 2610 | "dev": true 2611 | }, 2612 | "unix-crypt-td-js": { 2613 | "version": "1.0.0", 2614 | "resolved": "https://registry.npmjs.org/unix-crypt-td-js/-/unix-crypt-td-js-1.0.0.tgz", 2615 | "integrity": "sha1-HAgkFQSBvHoB1J6Y8exmjYJBLzs=", 2616 | "dev": true 2617 | }, 2618 | "unpipe": { 2619 | "version": "1.0.0", 2620 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 2621 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", 2622 | "dev": true 2623 | }, 2624 | "upper-case": { 2625 | "version": "1.1.3", 2626 | "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", 2627 | "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", 2628 | "dev": true 2629 | }, 2630 | "util-deprecate": { 2631 | "version": "1.0.2", 2632 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 2633 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", 2634 | "dev": true 2635 | }, 2636 | "utils-merge": { 2637 | "version": "1.0.0", 2638 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", 2639 | "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=", 2640 | "dev": true 2641 | }, 2642 | "uuid": { 2643 | "version": "3.3.2", 2644 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", 2645 | "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", 2646 | "dev": true 2647 | }, 2648 | "validate-npm-package-license": { 2649 | "version": "3.0.4", 2650 | "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", 2651 | "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", 2652 | "dev": true, 2653 | "requires": { 2654 | "spdx-correct": "^3.0.0", 2655 | "spdx-expression-parse": "^3.0.0" 2656 | } 2657 | }, 2658 | "vary": { 2659 | "version": "1.1.2", 2660 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 2661 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", 2662 | "dev": true 2663 | }, 2664 | "websocket-driver": { 2665 | "version": "0.7.0", 2666 | "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz", 2667 | "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", 2668 | "dev": true, 2669 | "requires": { 2670 | "http-parser-js": ">=0.4.0", 2671 | "websocket-extensions": ">=0.1.1" 2672 | } 2673 | }, 2674 | "websocket-extensions": { 2675 | "version": "0.1.3", 2676 | "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", 2677 | "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", 2678 | "dev": true 2679 | }, 2680 | "which": { 2681 | "version": "1.3.1", 2682 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 2683 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 2684 | "dev": true, 2685 | "requires": { 2686 | "isexe": "^2.0.0" 2687 | } 2688 | }, 2689 | "wrappy": { 2690 | "version": "1.0.2", 2691 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 2692 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 2693 | "dev": true 2694 | }, 2695 | "xtend": { 2696 | "version": "4.0.1", 2697 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", 2698 | "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", 2699 | "dev": true 2700 | } 2701 | } 2702 | } 2703 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js13k-rewire", 3 | "version": "1.0.0", 4 | "description": "Puzzle game for the 2018 Js13kGames. Bring the System back online by rewiring the power nodes.", 5 | "main": "index.js", 6 | "author": "Jan Mankopf", 7 | "scripts": { 8 | "clean": "rimraf dist", 9 | "compile": "tsc", 10 | "minify-js": "uglifyjs \"./dist/app.js\" -o \"./dist/app.min.js\" --mangle-props --compress --mangle --toplevel && dir \"dist\" | findstr .js", 11 | "watch-compile": "tsc --watch", 12 | "watch-copy-html": "cpx \"src/index.html\" dist --watch", 13 | "dev-server": "live-server dist --no-browser", 14 | "minify-html": "html-minifier --collapse-whitespace --remove-comments --remove-optional-tags --remove-redundant-attributes --remove-script-type-attributes --use-short-doctype --minify-css true .\\dist\\rewire.html -o .\\dist\\rewire.min.html", 15 | "DEV": "npm run clean && run-p watch-compile watch-copy-html dev-server", 16 | "BUILD": "npm run clean && tsc && cpx \"src/index.html\" dist && npm run minify-js && replace 'app.js' 'app.min.js' dist/index.html && html-inline dist/index.html -o dist/rewire.html && npm run minify-html" 17 | }, 18 | "devDependencies": { 19 | "cpx": "^1.5.0", 20 | "html-inline": "^1.2.0", 21 | "html-minifier": "^3.5.20", 22 | "live-server": "^1.2.0", 23 | "npm-run-all": "^4.1.3", 24 | "replace": "^1.0.0", 25 | "rimraf": "^2.6.2", 26 | "typescript": "^3.0.3", 27 | "uglify-es": "^3.3.9" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /screenshots/rewire-screen-big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmankopf/js13k-rewire/301ddc7cf865d324b13e23e837274452e4de8a14/screenshots/rewire-screen-big.png -------------------------------------------------------------------------------- /screenshots/rewire-screen-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmankopf/js13k-rewire/301ddc7cf865d324b13e23e837274452e4de8a14/screenshots/rewire-screen-small.png -------------------------------------------------------------------------------- /src/canvas.ts: -------------------------------------------------------------------------------- 1 | const createCanvas = (width: number, height: number): [Canvas, Context] => { 2 | const canvas = document.createElement('canvas'); 3 | canvas.width = width; 4 | canvas.height = height; 5 | const context = canvas.getContext('2d') as Context; 6 | return [canvas, context]; 7 | }; 8 | -------------------------------------------------------------------------------- /src/game.ts: -------------------------------------------------------------------------------- 1 | const createGame = () => { 2 | 3 | const background = createGameBackground(); 4 | 5 | const createLevel = (levelData: LevelData, resources: Resources, onLevelFinish: () => void) => { 6 | 7 | const [canvas, context] = createCanvas(1280, 720); 8 | const space = createSpace(); 9 | 10 | let cancelFrameLoop: () => void; 11 | const inputControl = createInputControl(canvas); 12 | const spoolRenderSystem = createSpoolRenderSystem(resources); 13 | const cableRenderSystem = createCableRenderSystem(); 14 | 15 | const shutdown = function () { 16 | cancelFrameLoop(); 17 | inputControl.shutdown(); 18 | space.shutdown(); 19 | document.body.style.cursor = 'default'; 20 | }; 21 | const spoolSystem = createSpoolSystem(() => { 22 | shutdown(); 23 | onLevelFinish(); 24 | }); 25 | const mouseDragSystem = createMouseDragSystem(inputControl); 26 | 27 | 28 | // uncomment this lines and the line at the bottom to enable editor mode 29 | // const levelEditorSystem = createLevelEditorSystem(space, inputControl); 30 | // space.registerSystem(levelEditorSystem); 31 | 32 | 33 | space.registerSystem(spoolRenderSystem); 34 | space.registerSystem(spoolSystem); 35 | space.registerSystem(cableRenderSystem); 36 | space.registerSystem(mouseDragSystem); 37 | 38 | 39 | levelData.spools.forEach((spoolData) => { 40 | const spoolEntity: SpoolNodeEntity = { 41 | pos: {x: spoolData[0], y: spoolData[1]}, 42 | spool: {size: spoolData[2], type: NodeType.spool}, 43 | render: {type: NodeType.spool}, 44 | }; 45 | 46 | space.addEntity(spoolEntity); 47 | }); 48 | 49 | levelData.blocks.forEach((block) => { 50 | const blockEntity: BlockNodeEntity = { 51 | pos: {x: block[0], y: block[1]}, 52 | block: {size: block[2]}, 53 | render: {type: NodeType.block} 54 | }; 55 | space.addEntity(blockEntity); 56 | }); 57 | 58 | levelData.isolators.forEach((isolator) => { 59 | const blockEntity: SpoolNodeEntity = { 60 | pos: {x: isolator[0], y: isolator[1]}, 61 | spool: {size: isolator[2], type: NodeType.isolator}, 62 | render: {type: NodeType.isolator} 63 | }; 64 | space.addEntity(blockEntity); 65 | }); 66 | 67 | const start: StartNodeEntity = { 68 | pos: {x: levelData.start[0], y: levelData.start[1]}, 69 | spool: {size: 0, type: NodeType.start}, 70 | render: {type: NodeType.start} 71 | }; 72 | 73 | const end: EndNodeEntity = { 74 | pos: {x: levelData.end[0], y: levelData.end[1]}, 75 | spool: {size: 0, type: NodeType.end}, 76 | render: {type: NodeType.end}, 77 | mouseDrag: {size: 30} 78 | }; 79 | 80 | const cable: CableEntity = { 81 | cable: {attachments: [{entity: start as SpoolEntity, side: Side.left}, {entity: end as SpoolEntity, side: Side.left}]} 82 | }; 83 | 84 | const finish: FinishEntity = { 85 | finish: {}, 86 | render: {type: NodeType.finish}, 87 | pos: {x: levelData.finish[0], y: levelData.finish[1]} 88 | }; 89 | 90 | //TODO: render layers 91 | space.addEntity(start); 92 | space.addEntity(finish); 93 | space.addEntity(end); 94 | space.addEntity(cable); 95 | 96 | const update = (time: number) => { 97 | mouseDragSystem.update(time); 98 | spoolSystem.update(time); 99 | // levelEditorSystem.update(time); 100 | }; 101 | 102 | const render = (time: number) => { 103 | context.drawImage(background, 0,0); 104 | 105 | cableRenderSystem.render(context, time); 106 | spoolRenderSystem.render(context, time); 107 | }; 108 | 109 | cancelFrameLoop = startFrameLoop(time => { 110 | update(time); 111 | render(time); 112 | }); 113 | return { 114 | canvas, 115 | shutdown 116 | }; 117 | }; 118 | 119 | return { 120 | createLevel 121 | }; 122 | }; 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /src/gfx-generator.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | const mix = (a: number, b: number, m: number) => (1 - m) * a + m * b; 5 | const mixCol = (a: Color, b: Color, m: number): Color => ({ 6 | r: mix(a.r, b.r, m), 7 | g: mix(a.g, b.g, m), 8 | b: mix(a.b, b.b, m), 9 | a: mix(a.a, b.a, m), 10 | }); 11 | 12 | const halfV = {x: 0.5, y: 0.5}; 13 | const v10 = {x: 1, y: 0}; 14 | const v01 = {x: 0, y: 1}; 15 | const v11 = {x: 1, y: 1}; 16 | const n21 = (v: Vec2): number => ((Math.sin(v.x * 100 + v.y * 6574) + 1) * 564) % 1; 17 | 18 | const noise = (v: Vec2): number => { 19 | const lv = fractV(v); 20 | const id = floorV(v); 21 | const bl = n21(id); 22 | const br = n21(addV(id, v10)); 23 | const b = mix(bl, br, lv.x); 24 | 25 | const tl = n21(addV(id, v01)); 26 | const tr = n21(addV(id, v11)); 27 | 28 | const t = mix(tl, tr, lv.x); 29 | 30 | return mix(b, t, lv.y); 31 | }; 32 | const smoothstep = (min: number, max: number, value: number) => { 33 | const x = clamp((value - min) / (max - min), 0, 1); 34 | return x * x * (3 - 2 * x); 35 | }; 36 | const newCol = (r: number = 1, g: number = 1, b: number = 1, a: number = 1): Color => ({r, g, b, a}); 37 | const mulCol = (color: Color, v: number) => ({ 38 | r: color.r * v, 39 | g: color.g * v, 40 | b: color.b * v, 41 | a: color.a 42 | }); 43 | 44 | const addCol = (a: Color, b: Color) => { 45 | return { 46 | r: a.r + b.r * b.a, 47 | g: a.g + b.g * b.a, 48 | b: a.b + b.b * b.a, 49 | a: a.a + b.a 50 | }; 51 | }; 52 | const generateImage = (width: number, height: number, cb: (v: Vec2) => Color) => { 53 | const [canvas, context] = createCanvas(width, height); 54 | const imageData = context.getImageData(0, 0, width, height); 55 | const buf = new ArrayBuffer(imageData.data.length); 56 | const buf8 = new Uint8ClampedArray(buf); 57 | const data32 = new Uint32Array(buf); 58 | const v: Partial = {}; 59 | 60 | for (let y = 0; y < height; y++) { 61 | for (let x = 0; x < width; x++) { 62 | v.x = x / (width - 1); 63 | v.y = y / (height - 1); 64 | const c = cb(v as Vec2); 65 | data32[y * width + x] = 66 | (clamp(c.a! * 255, 0, 255) << 24) | // alpha 67 | (clamp(c.b! * 255, 0, 255) << 16) | // blue 68 | (clamp(c.g! * 255, 0, 255) << 8) | // green 69 | clamp(c.r! * 255, 0, 255); 70 | } 71 | } 72 | imageData.data.set(buf8); 73 | context.putImageData(imageData, 0, 0); 74 | 75 | return canvas; 76 | }; 77 | 78 | // https://gist.github.com/sakrist/8706749 79 | const createHexField = (v: Vec2, scale: number): number => { 80 | let {x, y} = mulVS(v, scale); 81 | x *= 0.57735 * 2.0; 82 | y += (Math.floor(x) % 2) * 0.5; 83 | x = Math.abs(x % 1 - 0.5); 84 | y = Math.abs(y % 1 - 0.5); 85 | return Math.abs(Math.max(x * 1.5 + y, y * 2.0) - 1.0); 86 | }; 87 | 88 | const createMetalPlate = (a: number, d: number): number => { 89 | const shading = smoothstep(0.91, 0.94, d) - smoothstep(0.41, 0.42, d); 90 | a += shading; 91 | return 0.9 + 0.1 * Math.sin(a * 6) * 0.9 + 0.1 * Math.sin(a * 4) 92 | - (noise({x: (a + 4 + d * 5) * 2, y: d * 80}) * 0.1) + shading * 0.2; 93 | }; 94 | 95 | const createCoilSprite = (size: number): Canvas => { 96 | const sw = 4 / size; 97 | const hexFieldScale = size / 4; 98 | const hexFieldBrightness = 0.7; 99 | const ringBrightness = 0.4; 100 | const gridShadowBlur = 0.1; 101 | const gridShadowStrength = 1; 102 | const ringWidth = 0.2; 103 | const buttonSize = 0.5; 104 | const gridColor = newCol(0.615, 0.705, 1, 1); 105 | const metalColor = newCol(1, 1, 1, 1); 106 | const shadowBlur = 0.2; 107 | const shadowDistance = 0.04; 108 | const shadowScale = 1.1; 109 | const shadowStrength = 0.5; 110 | 111 | const image = generateImage(Math.round(size * 1.1), Math.round(size * 1.1), v => { 112 | v = mulVS(v, 1.1); // scale to make room for shadow 113 | const centerV = subV(v, halfV); 114 | const a = Math.atan2(centerV.y, centerV.x); 115 | const d = lenV(centerV) * 2; 116 | let grid = hexFieldBrightness * smoothstep(0.3, 1, 1 - createHexField(v, hexFieldScale)); // TODO: FOR SPOOL 117 | const gridShadow = 1 - (smoothstep(1 - ringWidth * 0.65, 1 - ringWidth - gridShadowBlur, d) - 118 | smoothstep(buttonSize + gridShadowBlur, buttonSize * 0.85, d)); 119 | grid -= (gridShadow * gridShadowStrength); 120 | 121 | const metalPlate = createMetalPlate(a, d) * ringBrightness; 122 | const ringMask = smoothstep(1 - ringWidth, 1 - ringWidth + sw, d) + smoothstep(buttonSize, buttonSize - sw, d); 123 | const spriteCol = mixCol(mulCol(gridColor, grid), mulCol(metalColor, metalPlate), ringMask); 124 | 125 | const shadow = smoothstep(1, 1 - shadowBlur, lenV(subV(centerV, { 126 | x: shadowDistance, 127 | y: shadowDistance 128 | })) * 2 / shadowScale) * shadowStrength; 129 | const shadowCol = newCol(0, 0, 0, shadow); 130 | 131 | return mixCol(spriteCol, shadowCol, smoothstep(1 - sw, 1, d)); 132 | }); 133 | 134 | return image; 135 | 136 | }; 137 | 138 | const createIsolatorSprite = (size: number): Canvas => { 139 | const sw = 4 / size; 140 | const hexFieldScale = size / 8; 141 | const hexFieldBrightness = 0.7; 142 | const ringBrightness = 0.4; 143 | const gridShadowBlur = 0.2; 144 | const gridShadowStrength = 0.6; 145 | const ringWidth = 0.15; 146 | const buttonSize = 0.3; 147 | const gridColor = newCol(0.815, 0.2705, .2, 1); // isolate red 148 | const metalColor = newCol(1, 1, 1, 1); 149 | const shadowBlur = 0.2; 150 | const shadowDistance = 0.04; 151 | const shadowScale = 1.1; 152 | const shadowStrength = 0.5; 153 | 154 | const image = generateImage(Math.round(size * 1.1), Math.round(size * 1.1), v => { 155 | v = mulVS(v, 1.1); // scale to make room for shadow 156 | const centerV = subV(v, halfV); 157 | const a = Math.atan2(centerV.y, centerV.x); // polar x 158 | const d = lenV(centerV) * 2; // polar y 159 | let grid = hexFieldBrightness * smoothstep(0.02, 0.41, 1 - createHexField(v, hexFieldScale)); // TODO FOR ISOLATOR 160 | const gridShadow = 1 - (smoothstep(1 - ringWidth * 0.65, 1 - ringWidth - gridShadowBlur, d) - 161 | smoothstep(buttonSize + gridShadowBlur, buttonSize * 0.85, d)); 162 | grid -= (gridShadow * gridShadowStrength); 163 | 164 | const metalPlate = createMetalPlate(a, d) * ringBrightness; 165 | const ringMask = smoothstep(1 - ringWidth, 1 - ringWidth + sw, d) + smoothstep(buttonSize, buttonSize - sw, d); 166 | const spriteCol = mixCol(mulCol(gridColor, grid), mulCol(metalColor, metalPlate), ringMask); 167 | 168 | const shadow = smoothstep(1, 1 - shadowBlur, lenV(subV(centerV, { 169 | x: shadowDistance, 170 | y: shadowDistance 171 | })) * 2 / shadowScale) * shadowStrength; 172 | const shadowCol = newCol(0, 0, 0, shadow); 173 | 174 | return mixCol(spriteCol, shadowCol, smoothstep(1 - sw, 1, d)); 175 | }); 176 | 177 | return image; 178 | 179 | }; 180 | 181 | const createGear = (px:number, py:number, outerSize: number, innerSize:number, step: number): number => { 182 | const s = Math.min(fract(px), fract(1 - px)) * 2; 183 | const spikes = smoothstep(0, step*8, s - py); 184 | const center = smoothstep(innerSize, innerSize+step, 1 - py); 185 | const cut = smoothstep(outerSize+step,outerSize , 1 - py); 186 | return clamp(spikes +center - cut, 0,1); 187 | }; 188 | 189 | const createBlockSprite = (size: number): Canvas => { 190 | const image = generateImage(size, size, v => { 191 | const cv = subV(v, halfV); 192 | const d = lenV(cv) * 2; 193 | const atan = Math.atan2(cv.y, cv.x); 194 | const px = atan / (Math.PI * 2) + 0.5; // polar twistedMx 195 | const twistedPx = atan / (Math.PI * 2) + 0.5 + d * 0.3; // polar twistedMx 196 | const twistedMx = twistedPx * Math.round(8+size/50); 197 | const mx = px * Math.round(5+size/200); 198 | const m = Math.min(fract(twistedMx), fract(1 - twistedMx)); 199 | let bladeAlpha = smoothstep(0.0, 0.08, m * 0.5 - d + 0.7); 200 | let shadow = 1-smoothstep(0.9, 0.2, d); 201 | let blade = 1.4 * d - bladeAlpha * 0.5; 202 | let gear = createGear(mx, d, 0.45, 0.52, 0.02); 203 | let gearCol = 0.5+0.5*createMetalPlate(atan*1, d); 204 | blade = mix(mix(shadow, blade, bladeAlpha), gear*0.3*gearCol, gear); 205 | return newCol(blade, blade, blade, bladeAlpha+(1-shadow)); 206 | }); 207 | return image; 208 | 209 | }; 210 | 211 | const createInnerShadow = (v: Vec2): Color => { 212 | const d = lenV(v) * 2; 213 | const dm = lenV(subV(v, mulVS(v11, 0.05))) * 2; 214 | const val = smoothstep(1, 0.5, dm * 0.8) * 0.2; 215 | const a = smoothstep(1, 0.85, d); 216 | return newCol(val, val, val, a); 217 | }; 218 | const createLedGlass = (v: Vec2): Color => { 219 | const d = (lenV(v) * 2) * 1.2; 220 | const val = smoothstep(1, 0.0, d) * 0.25; 221 | const a = smoothstep(0.99, 0.9, d); 222 | return newCol(val, val, val, a); 223 | }; 224 | const createLedGlassReflection = (v: Vec2): Color => { 225 | const d = (lenV(v) * 2) * 1.5; 226 | const dm = lenV(subV(v, mulVS(v11, 0.14))) * 1.01; 227 | const val = smoothstep(1, 0.6, d) * 228 | smoothstep(0.2, 0.5, dm); 229 | return newCol(val, val, val, val); 230 | }; 231 | const createLedSprite = (): Canvas => generateImage(21, 21, v => { 232 | const cv = subV(v, halfV); 233 | const innerShadow = createInnerShadow(cv); 234 | const ledGlass = createLedGlass(cv); 235 | const ledGlassReflection = createLedGlassReflection(cv); 236 | 237 | return addCol(addCol(innerShadow, ledGlass), ledGlassReflection); 238 | }); 239 | 240 | const white = newCol(1, 1, 1, 1); 241 | const createGlow = (color:Color): Canvas => generateImage(80, 80, v => { 242 | const cv = subV(v, halfV); 243 | const d = 1 - lenV(cv) * 2; 244 | const result = mixCol(color, white, smoothstep(0.6, 0.89, d)); 245 | 246 | const a = smoothstep(0.0, 1, d); 247 | return newCol(result.r, result.g, result.b, a*a*a); 248 | }); 249 | 250 | const createMetal = (a: number, d: number): number => { 251 | return 0.9 + 0.1 * Math.sin(a * 6) * 0.9 + 0.1 * Math.sin(a * 4) 252 | - (noise({x: (a + 4 + d * 5) * 2, y: d * 80}) * 0.1); 253 | }; 254 | 255 | const createRingGlow = (color:Color): Canvas => generateImage(62, 62, v => { 256 | const cv = subV(v, halfV); 257 | const d = 1 - lenV(cv) * 2; 258 | const result = mixCol(color, white, smoothstep(0.45, 0.5, d)*smoothstep(0.55, 0.5, d)); 259 | const a = smoothstep(0.0, 0.5, d)*smoothstep(1, 0.5, d); 260 | return newCol(result.r, result.g, result.b, a*a*a); 261 | }); 262 | 263 | 264 | const createConnectorButtons = (lightColor:Color, size:number): Canvas => { 265 | const shadowBlur = 0.2; 266 | const shadowDistance = 0.04; 267 | const shadowScale = 1.1; 268 | const shadowStrength = 0.2; 269 | const image = generateImage(size, size, v => { 270 | v = mulVS(v, 1.1); // scale to make room for shadow 271 | const cv = subV(v, halfV); 272 | 273 | const atan = Math.atan2(cv.y, cv.x); 274 | const py = lenV(cv) * 2; 275 | 276 | // back 277 | const backAlpha = smoothstep(1, .96, py); 278 | let shading = smoothstep(0.9, 0.80, py)*0.3+0.3; 279 | shading -= smoothstep(0.7, 0.60, py) * smoothstep(0.2, 0.30, py) * 0.4; 280 | const backVal = createMetal(atan+(shading*3), py) * shading; 281 | const backCol = newCol(backVal, backVal, backVal, backAlpha); 282 | 283 | // light 284 | const lightAlpha = smoothstep(0.35, 0.45, py)*smoothstep(0.55, 0.45, py); 285 | 286 | const col = mixCol(backCol, lightColor, lightAlpha); 287 | const shadow = smoothstep(1, 1 - shadowBlur, lenV(subV(cv, { 288 | x: shadowDistance, 289 | y: shadowDistance 290 | })) * 2 / shadowScale) * shadowStrength; 291 | const shadowCol = newCol(0, 0, 0, shadow); 292 | return mixCol(col, shadowCol, smoothstep(0.8, 1, py)); 293 | }); 294 | return image; 295 | }; 296 | 297 | const createGameBackground = (): Canvas => { 298 | const [canvas, context] = createCanvas(1920, 1280); 299 | const image = generateImage(64, 64, v => { 300 | const m = mulVS(v, 4); 301 | const col = 1-smoothstep(0.7, 1, createHexField(m, 1))*0.7; 302 | return newCol(col * 0.117, col * 0.149, col * 0.188, 1); 303 | }); 304 | 305 | const highlight = generateImage(128*2, 72*2, v => { 306 | const w = 0.01; 307 | const c = smoothstep(0, w*0.6, v.x)*smoothstep(1, 1-w*0.6, v.x)* 308 | smoothstep(0, w, v.y)*smoothstep(1, 1-w, v.y); 309 | 310 | return newCol(1, 1, 1, (1-c)*0.04); 311 | }); 312 | 313 | for (let y = 0; y < 12; y++) { 314 | for (let x = 0; x < 24; x++) { 315 | context.drawImage(image, x * 54, y * 63); 316 | } 317 | } 318 | 319 | context.drawImage(highlight, 0, 0, 1280, 720); 320 | return canvas; 321 | }; 322 | 323 | -------------------------------------------------------------------------------- /src/html.ts: -------------------------------------------------------------------------------- 1 | 2 | const elementById = (id: any) => document.getElementById(id); 3 | 4 | const titleElement = elementById('title') as HTMLElement; 5 | const gameElement = elementById('game') as HTMLElement; 6 | const loadingElement = elementById('loading') as HTMLElement; 7 | const menuElement = elementById('menu') as HTMLElement; 8 | const levelDoneElement = elementById('levelDone') as HTMLElement; 9 | const nextMsg = elementById('nextMsg') as HTMLElement; 10 | const nextBtn = elementById('nextBtn') as HTMLElement; 11 | const startBtn = elementById('startBtn') as HTMLElement; 12 | const continueBtn = elementById('continueBtn') as HTMLElement; 13 | const contentElement = elementById('content') as HTMLElement; 14 | const resetElement = elementById('reset') as HTMLElement; 15 | const resetBtn = elementById('resetBtn') as HTMLElement; 16 | const levelInfo = elementById('levelInfo') as HTMLElement; 17 | const nodeInfo = elementById('nodeInfo') as HTMLElement; 18 | const descriptionElement = elementById('description') as HTMLElement; 19 | 20 | const skipBtn = elementById('skipBtn') as HTMLElement; 21 | const backBtn = elementById('backBtn') as HTMLElement; 22 | 23 | const saveLevel = (level: number) => { 24 | try { 25 | localStorage.setItem('level', '' + level); 26 | } catch (e) { 27 | // IE and edge don't support localstorage when opening the file from disk 28 | } 29 | }; 30 | 31 | const loadLevel = (): number => { 32 | try { 33 | return parseInt(localStorage.getItem('level')!) || 0; 34 | } catch (e) { 35 | return 0; 36 | } 37 | }; 38 | 39 | const removeElement = (element: HTMLElement) => { 40 | element.parentNode!.removeChild(element); 41 | }; 42 | 43 | const fadeTime = 0.4; 44 | 45 | const showElement = (element: HTMLElement | HTMLElement[], onComplete?: () => void) => { 46 | let elements = Array.isArray(element) ? element : [element]; 47 | elements.forEach(e => { 48 | e.style.visibility = 'visible'; 49 | e.style.opacity = '0'; 50 | }); 51 | tween(0, 1, fadeTime, 52 | (t) => { 53 | elements.forEach(e => { 54 | e.style.opacity = t.toString(); 55 | }); 56 | }, 57 | () => { 58 | onComplete && onComplete(); 59 | } 60 | ); 61 | }; 62 | 63 | const hideElement = (element: HTMLElement | HTMLElement[], onComplete?: () => void) => { 64 | let elements = Array.isArray(element) ? element : [element]; 65 | tween(1, 0, fadeTime, 66 | (t) => { 67 | elements.forEach(e => { 68 | e.style.opacity = t.toString(); 69 | }); 70 | }, 71 | () => { 72 | elements.forEach(e => { 73 | e.style.visibility = 'hidden'; 74 | }); 75 | onComplete && onComplete(); 76 | } 77 | ); 78 | }; 79 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Re-Wire 6 | 163 | 164 | 165 |
166 |
167 | 168 | 169 | 170 | 171 | 172 | 173 | 177 | 181 | 186 |
187 | 188 | 189 | 190 | 191 | 192 | -------------------------------------------------------------------------------- /src/input.ts: -------------------------------------------------------------------------------- 1 | type Mouse = { pos: Vec2, leftDown: boolean; } 2 | type InputCallback = (() => void) | undefined; 3 | type InputCallbacks = { 4 | mouseOver?: InputCallback; 5 | mouseOut?: InputCallback; 6 | mouseDown?: InputCallback; 7 | mouseUp?: InputCallback; 8 | mouseDownUpdate?: InputCallback; 9 | } 10 | 11 | interface InputControl { 12 | mousePos: Vec2; 13 | isMouseDown: ()=>boolean; 14 | 15 | targets: [MouseDragEntity, InputCallbacks][]; 16 | 17 | shutdown(): void; 18 | 19 | update(): void; 20 | 21 | dragControl(target: MouseDragEntity, callbacks: InputCallbacks): void; 22 | } 23 | 24 | const createInputControl = (canvas: Canvas): InputControl => { 25 | let mouseDown: boolean = false; 26 | const mousePos: Vec2 = {x: 0, y: 0}; 27 | 28 | const mouseOverTargets: [MouseDragEntity, InputCallbacks][] = []; 29 | const mouseOutTargets: [MouseDragEntity, InputCallbacks][] = []; 30 | const mouseDownTargets: [MouseDragEntity, InputCallbacks][] = []; 31 | 32 | const mouseMoveListener = (e: MouseEvent) => { 33 | let rect = canvas.getBoundingClientRect(); 34 | mousePos.x = e.clientX - rect.left; 35 | mousePos.y = e.clientY - rect.top; 36 | e.preventDefault(); 37 | }; 38 | const mouseDownListener = (e: MouseEvent) => { 39 | mouseDown = true; 40 | mouseOverTargets.forEach(watch => { 41 | const mouseDownCallback = watch[1].mouseDown; 42 | mouseDownCallback && mouseDownCallback(); 43 | mouseDownTargets.push(watch); 44 | }); 45 | e.preventDefault(); 46 | }; 47 | const mouseUpListener = (e: MouseEvent) => { 48 | mouseDown = false; 49 | mouseDownTargets.forEach(watch => { 50 | const mouseUpCallback = watch[1].mouseUp; 51 | mouseUpCallback && mouseUpCallback(); 52 | }); 53 | mouseDownTargets.length = 0; 54 | }; 55 | 56 | document.addEventListener('mousemove', mouseMoveListener); 57 | document.addEventListener('mousedown', mouseDownListener); 58 | document.addEventListener('mouseup', mouseUpListener); 59 | 60 | const dragControl = (target: MouseDragEntity, callbacks: InputCallbacks) => { 61 | mouseOutTargets.push([target, callbacks]); 62 | }; 63 | 64 | const update = () => { 65 | for (let i = mouseOutTargets.length - 1; i >= 0; --i) { 66 | const watch = mouseOutTargets[i]; 67 | const callbacks = watch[1]; 68 | if (distV(mousePos, watch[0].pos) <= watch[0].mouseDrag.size) { 69 | callbacks.mouseOver && callbacks.mouseOver(); 70 | mouseOutTargets.splice(i, 1); 71 | mouseOverTargets.push(watch); 72 | } 73 | } 74 | for (let i = mouseOverTargets.length - 1; i >= 0; --i) { 75 | const watch = mouseOverTargets[i]; 76 | const callbacks = watch[1]; 77 | 78 | mouseDown && callbacks.mouseDownUpdate && callbacks.mouseDownUpdate(); 79 | if (distV(mousePos, watch[0].pos) > watch[0].mouseDrag.size) { 80 | callbacks.mouseOut && callbacks.mouseOut(); 81 | mouseOverTargets.splice(i, 1); 82 | mouseOutTargets.push(watch); 83 | } 84 | } 85 | }; 86 | const shutdown = () => { 87 | document.removeEventListener('mousemove', mouseMoveListener); 88 | document.removeEventListener('mousedown', mouseDownListener); 89 | document.removeEventListener('mouseup', mouseUpListener); 90 | }; 91 | 92 | return { 93 | update, 94 | dragControl, 95 | mousePos, 96 | isMouseDown: () => (mouseDown), 97 | shutdown, 98 | targets:mouseOverTargets 99 | }; 100 | }; 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /src/level-editor.ts: -------------------------------------------------------------------------------- 1 | const createLevelEditorSystem = (space: Space, inputControl: InputControl): UpdateSystem => { 2 | const mouseWheelListener = (e: WheelEvent) => { 3 | e.preventDefault(); 4 | const spool = (inputControl.targets[0][0] as Entity).spool || (inputControl.targets[0][0] as Entity).block; 5 | 6 | if (!spool) { 7 | return; 8 | } 9 | let min = 30; 10 | let max = 160; 11 | if (spool.type == NodeType.isolator) { 12 | max = 80; 13 | } 14 | 15 | if (e.deltaY < 0) { 16 | spool.size !== max && (spool.size += 10); 17 | } else { 18 | spool.size !== min && (spool.size -= 10); 19 | } 20 | }; 21 | 22 | const keydownListener = (e: KeyboardEvent) => { 23 | if (e.key === '1') { 24 | const spoolEntity: SpoolNodeEntity = { 25 | pos: {x: inputControl.mousePos.x - 1, y: inputControl.mousePos.y}, 26 | spool: {size: 50, type: NodeType.spool}, 27 | render: {type: NodeType.spool}, 28 | }; 29 | // (spoolEntity as any).mouseDrag = {size: 20}; 30 | space.addEntity(spoolEntity); 31 | } 32 | if (e.key === '2') { 33 | const spoolEntity: BlockNodeEntity = { 34 | pos: {x: inputControl.mousePos.x, y: inputControl.mousePos.y}, 35 | block: {size: 50}, 36 | render: {type: NodeType.block}, 37 | }; 38 | // (spoolEntity as any).mouseDrag = {size: 20}; 39 | space.addEntity(spoolEntity); 40 | } 41 | if (e.key === '3') { 42 | const spoolEntity: SpoolNodeEntity = { 43 | pos: {x: inputControl.mousePos.x, y: inputControl.mousePos.y}, 44 | spool: {size: 40, type: NodeType.isolator}, 45 | render: {type: NodeType.isolator}, 46 | }; 47 | // (spoolEntity as any).mouseDrag = {size: 20}; 48 | space.addEntity(spoolEntity); 49 | } 50 | if (e.key === 'F2') { 51 | const level: Partial = {spools: [], isolators: [], blocks: []}; 52 | space.entities.forEach(entity => { 53 | if (entity.spool) { 54 | switch (entity.spool.type) { 55 | case NodeType.spool: 56 | level.spools!.push([entity.pos!.x, entity.pos!.y, entity.spool.size]); 57 | break; 58 | case NodeType.start: 59 | level.start = [entity.pos!.x, entity.pos!.y]; 60 | break; 61 | case NodeType.end: 62 | level.end = [110, 360]; 63 | break; 64 | case NodeType.isolator: 65 | level.isolators!.push([entity.pos!.x, entity.pos!.y, entity.spool!.size]); 66 | break; 67 | } 68 | } 69 | if (entity.finish) { 70 | level.finish = [entity.pos!.x, entity.pos!.y]; 71 | } 72 | if (entity.block) { 73 | level.blocks!.push([entity.pos!.x, entity.pos!.y, entity.block.size]); 74 | } 75 | }); 76 | 77 | console.log(JSON.stringify(level)); 78 | } 79 | }; 80 | 81 | window.addEventListener('keydown', keydownListener); 82 | window.addEventListener('wheel', mouseWheelListener); 83 | 84 | return { 85 | addEntity: entity => { 86 | if (entity.spool) { 87 | if (entity.spool.type != NodeType.end) { 88 | entity.mouseDrag = {size: entity.spool.size}; 89 | } 90 | 91 | } 92 | if (entity.block) { 93 | entity.mouseDrag = {size: entity.block.size}; 94 | } 95 | }, 96 | update: (time: number) => { 97 | }, 98 | shutdown: () => { 99 | window.removeEventListener('keydown', keydownListener); 100 | } 101 | }; 102 | }; 103 | -------------------------------------------------------------------------------- /src/level.ts: -------------------------------------------------------------------------------- 1 | type LevelData = { 2 | spools: [number, number, number][], 3 | blocks: [number, number, number][], 4 | isolators: [number, number, number][], 5 | start: [number, number] 6 | end: [number, number] 7 | finish: [number, number] 8 | } 9 | type GameData = { 10 | levels: LevelData[]; 11 | } 12 | 13 | const gameData: GameData = { 14 | levels: [ 15 | // { LEVEL TEMPLATE 16 | // 'spools': [[864, 336, 150], [560, 378, 50]], 17 | // 'isolators': [], 18 | // 'blocks': [], 19 | // 'start': [50, 360], 20 | // 'finish': [1230, 360], 21 | // 'end': [110, 360] 22 | // } 23 | // 1 24 | { 25 | 'spools': [[460, 207, 70], [468, 516, 70]], 26 | 'isolators': [], 27 | 'blocks': [], 28 | 'start': [50, 360], 29 | 'finish': [1230, 360], 30 | 'end': [110, 360] 31 | },// 2 32 | { 33 | 'spools': [[440, 540, 60], [846, 556, 60], [645, 173, 90]], 34 | 'isolators': [], 35 | 'blocks': [[777, 369, 110], [249, 461, 70]], 36 | 'start': [50, 360], 37 | 'finish': [1230, 360], 38 | 'end': [110, 360] 39 | },// 3 40 | { 41 | 'spools': [[871, 447, 50], [659, 590, 50], [629, 267, 40]], 42 | 'isolators': [[438, 561, 40], [497, 148, 40]], 43 | 'blocks': [[241, 435, 70], [675, 422, 90], [324, 215, 50]], 44 | 'start': [50, 360], 45 | 'finish': [1230, 360], 46 | 'end': [110, 360] 47 | },// 4 48 | { 49 | 'spools': [[872, 496, 130], [508, 234, 60], [508, 486, 60], [871, 190, 130]], 50 | 'isolators': [[234, 525, 40], [237, 182, 40]], 51 | 'blocks': [[667, 288, 60], [669, 427, 60], [593, 132, 60], [597, 588, 60]], 52 | 'start': [50, 360], 53 | 'finish': [1230, 360], 54 | 'end': [110, 360] 55 | },// 5 56 | { 57 | 'spools': [[845, 156, 70], [595, 443, 60], [668, 609, 60], [396, 416, 50]], 58 | 'isolators': [[832, 396, 40], [556, 247, 40]], 59 | 'blocks': [[696, 204, 60], [721, 392, 60], [498, 345, 50]], 60 | 'start': [50, 360], 61 | 'finish': [1230, 360], 62 | 'end': [110, 360] 63 | }, // 6 64 | { 65 | 'spools': [[664, 338, 70], [365, 171, 90], [929, 170, 90], [1011, 559, 80], [372, 558, 90]], 66 | 'isolators': [[729, 561, 40], [1149, 266, 40]], 67 | 'blocks': [[757, 203, 70], [846, 375, 70], [585, 549, 80], [1150, 429, 50]], 68 | 'start': [50, 360], 69 | 'finish': [1230, 360], 70 | 'end': [110, 360] 71 | }, // 7 72 | { 73 | 'spools': [[502, 259, 60], [508, 458, 60], [979, 356, 50], [346, 573, 60], [319, 141, 60]], 74 | 'isolators': [[724, 361, 40], [720, 142, 40]], 75 | 'blocks': [[609, 353, 60], [379, 451, 50], [848, 360, 70]], 76 | 'start': [50, 360], 77 | 'finish': [1230, 360], 78 | 'end': [110, 360] 79 | }, // 8 80 | { 81 | 'spools': [[957, 156, 70], [378, 570, 70], [507, 109, 60]], 82 | 'isolators': [[568, 536, 40], [382, 198, 40], [659, 112, 40], [940, 348, 40]], 83 | 'blocks': [[756, 445, 100], [1122, 234, 50]], 84 | 'start': [50, 360], 85 | 'finish': [1230, 360], 86 | 'end': [110, 360] 87 | }, // 9 88 | { 89 | 'spools': [[629, 130, 40], [811, 482, 50], [385, 491, 50], [386, 317, 50], [976, 569, 40], [844, 139, 60], [1161, 138, 50]], 90 | 'isolators': [[222, 230, 40], [216, 587, 30]], 91 | 'blocks': [[619, 367, 160], [1015, 255, 130]], 92 | 'start': [50, 360], 93 | 'finish': [1230, 360], 94 | 'end': [110, 360] 95 | }, // 10 96 | { 97 | 'spools': [[922, 509, 150], [257, 552, 60], [201, 200, 50], [509, 519, 50], [520, 134, 50], [937, 257, 50], [1111, 133, 50]], 98 | 'isolators': [[678, 465, 40], [679, 291, 40]], 99 | 'blocks': [[887, 113, 80], [392, 438, 70], [699, 573, 50], [1163, 468, 50]], 100 | 'start': [50, 360], 101 | 'finish': [1230, 360], 102 | 'end': [110, 360] 103 | }, // 11 104 | { 105 | 'spools': [[228, 193, 150], [326, 563, 80], [557, 209, 70], [785, 199, 50], [1043, 593, 80], [1015, 188, 130], [791, 548, 50], [543, 544, 50], [511, 373, 30], [685, 333, 30]], 106 | 'isolators': [[687, 446, 30], [1205, 455, 30]], 107 | 'blocks': [[442, 116, 50], [982, 400, 50], [1203, 265, 50], [1185, 563, 50], [776, 382, 60], [408, 428, 50]], 108 | 'start': [50, 360], 109 | 'finish': [1230, 360], 110 | 'end': [110, 360] 111 | }, // 12 112 | { 113 | 'spools': [[669, 355, 80], [668, 187, 50], [666, 70, 30], [668, 514, 50], [673, 653, 30], [473, 361, 50], [852, 353, 50], [986, 348, 30], [335, 361, 30]], 114 | 'isolators': [], 115 | 'blocks': [[804, 476, 50], [552, 244, 60], [857, 174, 90], [489, 541, 80]], 116 | 'start': [50, 360], 117 | 'finish': [1230, 360], 118 | 'end': [110, 360] 119 | }, // 13 120 | { 121 | 'spools': [[549, 114, 60], [213, 345, 30], [389, 186, 50], [834, 93, 70], [297, 272, 40], [389, 564, 50], [606, 542, 50], [815, 566, 50]], 122 | 'isolators': [], 123 | 'blocks': [[839, 300, 130], [1062, 343, 80], [483, 354, 50], [337, 419, 70], [485, 537, 30], [204, 507, 50]], 124 | 'start': [50, 360], 125 | 'finish': [1230, 360], 126 | 'end': [110, 360] 127 | }, // 14 128 | { 129 | 'spools': [[402, 380, 90], [758, 379, 90], [890, 195, 50], [324, 166, 50], [1036, 91, 40], [1038, 461, 50], [1055, 622, 40]], 130 | 'isolators': [[600, 100, 40], [595, 617, 40]], 131 | 'blocks': [[159, 251, 50], [733, 156, 70], [886, 553, 80], [988, 303, 80], [1167, 238, 50], [1082, 536, 30]], 132 | 'start': [50, 360], 133 | 'finish': [1230, 360], 134 | 'end': [110, 360] 135 | }, // 15 136 | { 137 | 'spools': [[647, 360, 160], [326, 233, 30], [462, 111, 30], [646, 71, 30], [819, 120, 30], [932, 277, 30], [930, 468, 30], [809, 602, 30], [626, 644, 30], [438, 579, 30], [334, 404, 30]], 138 | 'isolators': [[188, 119, 30], [192, 568, 30]], 139 | 'blocks': [[1069, 367, 90], [354, 134, 50], [561, 106, 40], [828, 232, 50], [855, 392, 50], [711, 577, 50], [447, 466, 50], [431, 258, 60]], 140 | 'start': [50, 360], 141 | 'finish': [1230, 360], 142 | 'end': [110, 360] 143 | }, // 16 144 | { 145 | 'spools': [[335, 304, 50], [655, 299, 60], [961, 191, 50], [318, 584, 50], [650, 580, 50], [1007, 591, 50], [346, 115, 40], [1139, 136, 50], [1198, 581, 30], [901, 497, 30]], 146 | 'isolators': [], 147 | 'blocks': [[1090, 294, 70], [985, 487, 40], [765, 482, 60], [846, 192, 50], [538, 149, 50], [1037, 134, 30], [1135, 530, 30]], 148 | 'start': [50, 360], 149 | 'finish': [1230, 360], 150 | 'end': [110, 360] 151 | }, 152 | ] 153 | }; 154 | -------------------------------------------------------------------------------- /src/math-util.ts: -------------------------------------------------------------------------------- 1 | // https://gist.github.com/blixt/f17b47c62508be59987b 2 | const clamp = (num: number, min: number, max: number): number => num < min ? min : num > max ? max : num; 3 | 4 | // https://gist.github.com/Joncom/e8e8d18ebe7fe55c3894 5 | const lineLineIntersect = (line1a: Vec2, line1b: Vec2, line2a: Vec2, line2b: Vec2): boolean => { 6 | // var s1_x, s1_y, s2_x, s2_y; 7 | const s1_x = line1b.x - line1a.x; 8 | const s1_y = line1b.y - line1a.y; 9 | const s2_x = line2b.x - line2a.x; 10 | const s2_y = line2b.y - line2a.y; 11 | 12 | // var s, t; 13 | const s = (-s1_y * (line1a.x - line2a.x) + s1_x * (line1a.y - line2a.y)) / (-s2_x * s1_y + s1_x * s2_y); 14 | const t = (s2_x * (line1a.y - line2a.y) - s2_y * (line1a.x - line2a.x)) / (-s2_x * s1_y + s1_x * s2_y); 15 | 16 | return s >= 0 && s <= 1 && t >= 0 && t <= 1; 17 | }; 18 | 19 | // borrowed from https://codereview.stackexchange.com/questions/192477/circle-line-segment-collision 20 | const lineCircleIntersect = (lineA: Vec2, lineB: Vec2, circle: Vec2, radius: number): boolean => { 21 | let dist; 22 | const v1x = lineB.x - lineA.x; 23 | const v1y = lineB.y - lineA.y; 24 | const v2x = circle.x - lineA.x; 25 | const v2y = circle.y - lineA.y; 26 | // get the unit distance along the line of the closest point to 27 | // circle center 28 | const u = (v2x * v1x + v2y * v1y) / (v1y * v1y + v1x * v1x); 29 | 30 | // if the point is on the line segment get the distance squared 31 | // from that point to the circle center 32 | if (u >= 0 && u <= 1) { 33 | dist = (lineA.x + v1x * u - circle.x) ** 2 + (lineA.y + v1y * u - circle.y) ** 2; 34 | } else { 35 | // if closest point not on the line segment 36 | // use the unit distance to determine which end is closest 37 | // and get dist square to circle 38 | dist = u < 0 ? 39 | (lineA.x - circle.x) ** 2 + (lineA.y - circle.y) ** 2 : 40 | (lineB.x - circle.x) ** 2 + (lineB.y - circle.y) ** 2; 41 | } 42 | return dist < radius * radius; 43 | }; 44 | 45 | // https://jsfiddle.net/MadLittleMods/0eh0zeyu/ 46 | const dist2 = (pt1: Vec2, pt2: Vec2) => Math.pow(pt1.x - pt2.x, 2) + Math.pow(pt1.y - pt2.y, 2); 47 | 48 | // https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Tangents_between_two_circles 49 | const getTangents = (p1: Vec2, r1: number, p2: Vec2, r2: number): Vec2[][] => { 50 | let d_sq = (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y); 51 | 52 | if (d_sq <= (r1 - r2) * (r1 - r2)) return []; 53 | 54 | let d = Math.sqrt(d_sq); 55 | let vx = (p2.x - p1.x) / d; 56 | let vy = (p2.y - p1.y) / d; 57 | 58 | // double[][] res = new double[4][4]; 59 | let result = []; 60 | let i = 0; 61 | 62 | // Let A, B be the centers, and C, D be points at which the tangent 63 | // touches first and second circle, and n be the normal vector to it. 64 | // 65 | // We have the system: 66 | // n * n = 1 (n is a unit vector) 67 | // C = A + r1 * n 68 | // D = B +/- r2 * n 69 | // n * CD = 0 (common orthogonality) 70 | // 71 | // n * CD = n * (AB +/- r2*n - r1*n) = AB*n - (r1 -/+ r2) = 0, <=> 72 | // AB * n = (r1 -/+ r2), <=> 73 | // v * n = (r1 -/+ r2) / d, where v = AB/|AB| = AB/d 74 | // This is a linear equation in unknown vector n. 75 | 76 | for (let sign1 = +1; sign1 >= -1; sign1 -= 2) { 77 | let c = (r1 - sign1 * r2) / d; 78 | 79 | // Now we're just intersecting a line with a circle: v*n=c, n*n=1 80 | 81 | if (c * c > 1.0) continue; 82 | let h = Math.sqrt(Math.max(0.0, 1.0 - c * c)); 83 | 84 | for (let sign2 = +1; sign2 >= -1; sign2 -= 2) { 85 | let nx = vx * c - sign2 * h * vy; 86 | let ny = vy * c + sign2 * h * vx; 87 | result[i] = []; 88 | const a = result[i] = new Array(2); 89 | a[0] = {x: p1.x + r1 * nx, y: p1.y + r1 * ny}; 90 | a[1] = {x: p2.x + sign1 * r2 * nx, y: p2.y + sign1 * r2 * ny}; 91 | i++; 92 | } 93 | } 94 | 95 | return result; 96 | }; 97 | 98 | 99 | const sideOfLine = (p1: Vec2, p2: Vec2, p: Vec2): Side => ((p2.x - p1.x) * (p.y - p1.y) - (p2.y - p1.y) * (p.x - p1.x)) > 0 ? Side.left : Side.right; 100 | 101 | -------------------------------------------------------------------------------- /src/mouse-drag-system.ts: -------------------------------------------------------------------------------- 1 | const createMouseDragSystem = (inputControl:InputControl): UpdateSystem => { 2 | 3 | const sp: Vec2 = {x: 0, y: 0}; 4 | const spools: Entity[] = []; 5 | let dragEntity: MouseDragEntity; 6 | let finishEntity: FinishEntity; 7 | let isDragging = false; 8 | let isOver = false; 9 | return { 10 | addEntity: entity => { 11 | // we need the spools to check if we collide 12 | if (entity.spool && (entity.spool.type === NodeType.spool || entity.spool.type === NodeType.isolator)) { 13 | spools.push(entity); 14 | } 15 | if (entity.finish) { 16 | finishEntity = entity; 17 | } 18 | 19 | if (entity.mouseDrag) { 20 | inputControl.dragControl(entity, { 21 | mouseOver: () => { 22 | isOver = true; 23 | if (inputControl.isMouseDown()) { 24 | return; 25 | } 26 | document.body.style.cursor = 'pointer'; 27 | dragEntity = entity; 28 | entity.render.hover = true; 29 | 30 | }, 31 | mouseOut: () => { 32 | document.body.style.cursor = 'default'; 33 | isOver = false; 34 | if (!isDragging) { 35 | entity.render.hover = false; 36 | } 37 | 38 | }, 39 | mouseDown: () => { 40 | isDragging = true; 41 | copyIntoV(sp, subV(inputControl.mousePos, entity.pos)); 42 | }, 43 | mouseUp:()=> { 44 | isDragging = false; 45 | if (!isOver) { 46 | entity.render.hover = false; 47 | } 48 | 49 | }, 50 | mouseDownUpdate: () => { 51 | } 52 | 53 | }); 54 | } 55 | }, 56 | update: (time: number) => { 57 | inputControl.update(); 58 | if (!dragEntity) { 59 | return; 60 | } 61 | 62 | isDragging && copyIntoV(dragEntity.pos, subV(inputControl.mousePos, sp)); 63 | 64 | const v1 = dragEntity.pos; 65 | 66 | // push away from border 67 | v1.x = clamp(v1.x, 0, 1280); 68 | v1.y = clamp(v1.y, 0, 720); 69 | 70 | // push end node away from spools 71 | spools.forEach(spool => { 72 | if (spool === dragEntity) { 73 | return; 74 | } 75 | const v2 = spool.pos; 76 | const dist = 10 + spool.spool.size; 77 | if (distV(v1, v2) < dist) { 78 | const dir = normalizeV(subV(v1, v2)); 79 | if (dir.x == 0 && dir.y == 0) { 80 | dir.x = 1; 81 | } 82 | const v = mulVS(dir, dist); 83 | dragEntity.pos = addV(v2, v); 84 | 85 | } 86 | }); 87 | 88 | // snap to finish 89 | if (distV(v1, finishEntity.pos) < 30) { 90 | finishEntity.finish.connected = true; 91 | copyIntoV(dragEntity.pos, finishEntity.pos); 92 | } else { 93 | finishEntity.finish.connected = false; 94 | } 95 | 96 | } 97 | }; 98 | }; 99 | -------------------------------------------------------------------------------- /src/render-systems.ts: -------------------------------------------------------------------------------- 1 | 2 | const createSpoolRenderSystem = (resources: Resources): RenderSystem => { 3 | const entities: Entity[] = []; 4 | const {coils, blocks, isolators, drag, finish, start} = resources; 5 | 6 | return { 7 | addEntity: (entity: Entity) => { 8 | if (entity.render) { 9 | entities.push(entity); 10 | } 11 | }, 12 | render: (context: Context, time: number) => { 13 | entities.forEach(entity => { 14 | switch (entity.render.type) { 15 | case NodeType.spool: 16 | context.drawImage(coils[entity.spool.size], entity.pos.x - entity.spool.size - 6, entity.pos.y - entity.spool.size - 6); 17 | context.drawImage(resources.led, entity.pos.x - 11, entity.pos.y - 11); 18 | if (entity.spool.overpowered) { 19 | context.drawImage(resources.redGlow, entity.pos.x - 40, entity.pos.y - 40); 20 | } else if (entity.spool.powered) { 21 | context.drawImage(resources.greenGlow, entity.pos.x - 40, entity.pos.y - 40); 22 | } 23 | break; 24 | case NodeType.isolator: 25 | context.drawImage(isolators[entity.spool.size], entity.pos.x - entity.spool.size - 6, entity.pos.y - entity.spool.size - 6); 26 | break; 27 | case NodeType.block: 28 | context.save(); 29 | context.translate(entity.pos.x, entity.pos.y); 30 | context.rotate(time); 31 | const sprite = blocks[entity.block.size]; 32 | context.drawImage(sprite, -sprite.width / 2, -sprite.height / 2); 33 | context.restore(); 34 | break; 35 | case NodeType.finish: 36 | context.drawImage(finish, entity.pos.x - 32, entity.pos.y - 32); 37 | break; 38 | case NodeType.start: 39 | context.drawImage(start, entity.pos.x - 24, entity.pos.y - 24); 40 | break; 41 | case NodeType.end: 42 | context.drawImage(drag, entity.pos.x - 32, entity.pos.y - 32); 43 | if (entity.render.hover) { 44 | context.globalAlpha = 0.8 + (0.2 * Math.sin(time * 6)); 45 | context.drawImage(resources.dragGlow, entity.pos.x - 31, entity.pos.y - 31); 46 | } else { 47 | context.globalAlpha = 0.2 + (0.2 * Math.sin(time * 3)); 48 | context.drawImage(resources.dragGlow, entity.pos.x - 31, entity.pos.y - 31); 49 | } 50 | context.globalAlpha = 1; 51 | break; 52 | 53 | } 54 | }); 55 | } 56 | }; 57 | }; 58 | 59 | const createCableRenderSystem = (): RenderSystem => { 60 | const entities: Entity[] = []; 61 | return { 62 | addEntity: (entity: Entity) => { 63 | if (entity.cable) { 64 | entities.push(entity); 65 | } 66 | }, 67 | render: (context: Context) => { 68 | 69 | entities.forEach(entity => { 70 | const attachments = entity.cable.attachments; 71 | for (let i = 0; i < attachments.length - 1; i++) { 72 | const a = attachments[i]; 73 | const b = attachments[i + 1]; 74 | 75 | context.save(); 76 | 77 | if (a.overlap) { 78 | context.setLineDash([5, 10]); 79 | } 80 | if (a.isolated) { 81 | context.strokeStyle = '#d04533'; 82 | context.lineWidth = 5; 83 | } else { 84 | context.strokeStyle = 'white'; 85 | context.lineWidth = 3; 86 | } 87 | 88 | context.lineCap = 'round'; 89 | context.beginPath(); 90 | context.moveTo(a.outPos!.x, a.outPos!.y); 91 | context.lineTo(b.inPos!.x, b.inPos!.y); 92 | context.stroke(); 93 | 94 | context.restore(); 95 | } 96 | }); 97 | } 98 | }; 99 | }; 100 | -------------------------------------------------------------------------------- /src/resources.ts: -------------------------------------------------------------------------------- 1 | /// 2 | type SpriteMap = { [size: number]: Canvas }; 3 | type ResLoadCalls = () => void; 4 | type Resources = { 5 | coils: SpriteMap; 6 | blocks: SpriteMap; 7 | isolators: SpriteMap; 8 | led: Canvas; 9 | drag: Canvas; 10 | dragGlow: Canvas; 11 | finish: Canvas; 12 | start: Canvas; 13 | greenGlow: Canvas; 14 | redGlow: Canvas; 15 | tutorial1: Canvas; 16 | tutorial2: Canvas; 17 | }; 18 | const generateResources = (onProgress: (percent: number) => void, onDone: (resources: Resources) => void) => { 19 | const resCalls: ResLoadCalls[] = []; 20 | const coilSprites: SpriteMap = {}; 21 | const blockSprites: SpriteMap = {}; 22 | const isolatorSprites: SpriteMap = {}; 23 | [30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160].forEach(size => { 24 | resCalls.push(() => { 25 | coilSprites[size] = createCoilSprite(size * 2 + 10); 26 | }); 27 | }); 28 | [30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160].forEach(size => { 29 | resCalls.push(() => { 30 | blockSprites[size] = createBlockSprite(size * 2 + 6); 31 | }); 32 | }); 33 | [30, 40, 50, 60, 70, 80].forEach(size => { 34 | resCalls.push(() => { 35 | isolatorSprites[size] = createIsolatorSprite(size * 2 + 10); 36 | }); 37 | }); 38 | 39 | const led = createLedSprite(); 40 | const greenGlow = createGlow(newCol(0, 1, 0)); 41 | const redGlow = createGlow(newCol(1, 0, 0)); 42 | const dragPoint = createConnectorButtons(newCol(0.2, 0.6, 0.2),70); 43 | const start = createConnectorButtons(newCol(0.2, 0.2, 0.2),52); 44 | const dragGlow = createRingGlow(newCol(0, 1, 0)); 45 | const finish = createConnectorButtons(newCol(1, 0.4, 0.4),70); 46 | 47 | //Tutorial Screens 48 | const [tutorial1, tutCtx1] = createCanvas(450, 264); 49 | tutorial1.className = 'tutorial'; 50 | tutCtx1.font = '20px sans-serif'; 51 | tutCtx1.fillStyle = '#ccc'; 52 | tutCtx1.fillText('1. Drag the cable ...', 20, 50); 53 | tutCtx1.drawImage(dragPoint, 358, 10); 54 | tutCtx1.fillText('2. ...around the power nodes...', 20, 140); 55 | tutCtx1.drawImage(createCoilSprite(80), 350, 90); 56 | tutCtx1.fillText('3. ...and plug it into the socket!', 20, 230); 57 | tutCtx1.drawImage(finish, 358, 190); 58 | 59 | const [tutorial2, tutCtx2] = createCanvas(450, 100); 60 | tutorial2.className = 'tutorial'; 61 | tutCtx2.font = '20px sans-serif'; 62 | tutCtx2.fillStyle = '#ccc'; 63 | tutCtx2.fillText('Isolated cables can overlap others ', 20, 55); 64 | tutCtx2.drawImage(createIsolatorSprite(80), 358, 10); 65 | 66 | 67 | const numResources = resCalls.length; 68 | let numGenerated = 0; 69 | (function nextRes() { 70 | const nextCall = resCalls.shift(); 71 | if (nextCall) { 72 | nextCall(); 73 | onProgress(100 / numResources * ++numGenerated); 74 | requestAnimationFrame(nextRes); 75 | } else { 76 | onDone({ 77 | coils: coilSprites, 78 | blocks: blockSprites, 79 | isolators: isolatorSprites, 80 | greenGlow, 81 | redGlow, 82 | led, 83 | drag: dragPoint, 84 | dragGlow, 85 | finish, 86 | tutorial1, 87 | tutorial2, 88 | start 89 | }); 90 | } 91 | })(); 92 | 93 | }; 94 | -------------------------------------------------------------------------------- /src/space.ts: -------------------------------------------------------------------------------- 1 | type System = { 2 | addEntity: (entity: Entity) => void; 3 | update?: (time: number) => void; 4 | shutdown?: () => void; 5 | }; 6 | type RenderSystem = System & { render: (context: Context, time: number) => void } 7 | type UpdateSystem = System & { update: (time: number) => void } 8 | 9 | interface Space { 10 | entities: Partial[]; 11 | 12 | registerSystem(system: System): void; 13 | 14 | addEntity(entity: Partial): void; 15 | 16 | shutdown(): void; 17 | } 18 | 19 | const createSpace = (): Space => { 20 | const systems: System[] = []; 21 | const entities: Partial[] = []; 22 | 23 | return { 24 | registerSystem: (system: System) => { 25 | systems.push(system); 26 | }, 27 | addEntity: (entity: Partial) => { 28 | entities.push(entity); 29 | systems.forEach(system => { 30 | system.addEntity(entity as Entity); 31 | }); 32 | }, 33 | shutdown:()=> { 34 | systems.forEach(system => system.shutdown && system.shutdown()); 35 | }, 36 | entities 37 | }; 38 | }; 39 | -------------------------------------------------------------------------------- /src/spool-system.ts: -------------------------------------------------------------------------------- 1 | const calculateTangents = function (attachments: Attachment[]) { 2 | for (let i = 0; i < attachments.length - 1; i++) { 3 | const a = attachments[i]; 4 | const b = attachments[i + 1]; 5 | const tangents = getTangents(a.entity.pos, a.entity.spool.size, b.entity.pos, b.entity.spool.size); 6 | const idx = a.side == Side.left ? b.side == Side.left ? 1 : 3 : b.side == Side.left ? 2 : 0; 7 | 8 | if (!tangents[idx]) { 9 | 10 | } 11 | a.outPos = tangents[idx][0]; 12 | b.inPos = tangents[idx][1]; 13 | } 14 | }; 15 | 16 | const getIntersections = (a: Vec2, b: Vec2, spoolEntities: SpoolEntity[], ignoreA: SpoolEntity, ignoreB: SpoolEntity): SpoolEntity[] => { 17 | return spoolEntities 18 | .filter(spoolEntity => 19 | (spoolEntity != ignoreA && spoolEntity != ignoreB) && 20 | lineCircleIntersect(a, b, spoolEntity.pos, spoolEntity.spool.size) 21 | ) 22 | .sort((ca, cb) => dist2(ca.pos, a) > dist2(cb.pos, a) ? 1 : -1); //TODO: need to add the radius 23 | }; 24 | 25 | const resolveConnections = function (attachments: Attachment[], spools: SpoolEntity[]) { 26 | let resolved: boolean; 27 | do { 28 | resolved = true; 29 | for (let i = 0; i < attachments.length - 1; i++) { 30 | const a = attachments[i]; 31 | const b = attachments[i + 1]; 32 | const entity = getIntersections(a.outPos!, b.inPos!, spools, a.entity, b.entity)[0]; 33 | if (entity ) { 34 | if (entity.spool.isAttached) { 35 | // node already connected 36 | a.overlap = true; 37 | } else { 38 | // we have a connection 39 | entity.spool.isAttached = true; 40 | const side = sideOfLine(a.outPos!, b.inPos!, entity.pos); 41 | const attachment: Attachment = {entity: entity, side}; 42 | attachments.splice(i + 1, 0, attachment); 43 | resolved = false; 44 | calculateTangents([a, attachment, b]); 45 | break; 46 | } 47 | } 48 | } 49 | } while (!resolved); 50 | }; 51 | 52 | const resolveDisconnections = function (attachments: Attachment[]) { 53 | let resolved: boolean; 54 | do { 55 | resolved = true; 56 | for (let i = 1; i < attachments.length - 1; i++) { 57 | const a = attachments[i - 1]; 58 | const b = attachments[i]; 59 | const c = attachments[i + 1]; 60 | 61 | const vAB = subV(a.outPos!, b.inPos!); 62 | const vBC = subV(b.outPos!, c.inPos!); 63 | let angle = Math.atan2(vBC.y, vBC.x) - Math.atan2(vAB.y, vAB.x); 64 | if (angle < 0) angle += 2 * Math.PI; 65 | if ((b.side == Side.left && angle > Math.PI * 1.8) || 66 | (b.side == Side.right && angle < Math.PI * 0.2)) { 67 | attachments.splice(i, 1); 68 | b.entity.spool.isAttached = false; 69 | resolved = false; 70 | calculateTangents([a, c]); 71 | break; 72 | } 73 | } 74 | } while (!resolved); 75 | }; 76 | 77 | const createSpoolSystem = (onLevelCompleted: () => void): UpdateSystem => { 78 | const spoolEntities: SpoolEntity[] = []; 79 | const blockEntities: BlockEntity[] = []; 80 | const cables: CableEntity[] = []; 81 | let finishEntity: FinishEntity; 82 | let lastPoweredSpools =0; 83 | let numSpools = 0; 84 | 85 | return { 86 | addEntity: (entity: Entity) => { 87 | if (entity.spool) { 88 | spoolEntities.push(entity); 89 | if (entity.spool.type == NodeType.spool) { 90 | numSpools++; 91 | nodeInfo.innerHTML = 0 + ' / ' + numSpools; 92 | } 93 | } 94 | if (entity.cable) { 95 | cables.push(entity); 96 | } 97 | if (entity.block) { 98 | blockEntities.push(entity); 99 | } 100 | if (entity.finish) { 101 | finishEntity = entity; 102 | } 103 | }, 104 | update: (time: number) => { 105 | cables.forEach(cable => { 106 | const attachments = cable.cable.attachments; 107 | 108 | // reset states 109 | cable.cable.overpowered = false; 110 | attachments.forEach(attachment => { 111 | attachment.overlap = false; 112 | }); 113 | spoolEntities.forEach(spool => { 114 | spool.spool.powered = spool.spool.overpowered = false; 115 | }); 116 | let numPoweredSpools = 0; 117 | 118 | 119 | calculateTangents(attachments); 120 | resolveConnections(attachments, spoolEntities); 121 | resolveDisconnections(attachments); 122 | 123 | // set isolated status 124 | let isIsolated = false; 125 | cable.cable.attachments.forEach(attachment => { 126 | const spool = attachment.entity.spool; 127 | if (spool.type == NodeType.isolator) { 128 | isIsolated = !isIsolated; 129 | } 130 | attachment.isolated = isIsolated; 131 | }); 132 | 133 | // check line overlap 134 | for (let i = 0; i < attachments.length - 1; i++) { 135 | const a1 = attachments[i]; 136 | const b1 = attachments[i + 1]; 137 | if (a1.isolated) { 138 | continue; 139 | } 140 | for (let j = 0; j < attachments.length - 1; j++) { 141 | const a2 = attachments[j]; 142 | const b2 = attachments[j + 1]; 143 | if (a2.isolated) { 144 | continue; 145 | } 146 | if (lineLineIntersect(a1.outPos!, b1.inPos!, a2.outPos!, b2.inPos!)) { 147 | a1.overlap = a2.overlap = true; 148 | } 149 | } 150 | } 151 | 152 | // check block collision 153 | for (let i = 0; i < attachments.length - 1; i++) { 154 | const a1 = attachments[i]; 155 | const b1 = attachments[i + 1]; 156 | for (let j = 0; j < blockEntities.length; j++) { 157 | if (lineCircleIntersect(a1.outPos!, b1.inPos!, blockEntities[j].pos, blockEntities[j].block.size)) { 158 | a1.overlap = true; 159 | cable.cable.overpowered = true; 160 | } 161 | } 162 | } 163 | // check power / overpower 164 | let hasPower = true; 165 | cable.cable.attachments.every(attachment => { 166 | if (!hasPower) { 167 | return false; 168 | } 169 | if (attachment.isolated && !attachment.overlap) { 170 | return true; 171 | } 172 | if (attachment.entity.spool.powered) { 173 | attachment.entity.spool.overpowered = true; 174 | cable.cable.overpowered = true; 175 | return false; 176 | } 177 | 178 | attachment.entity.spool.powered = true; 179 | 180 | if (attachment.overlap) { 181 | 182 | hasPower = false; 183 | } else if (attachment.entity.spool.type == NodeType.spool){ 184 | 185 | numPoweredSpools++; 186 | } 187 | return true; 188 | }); 189 | 190 | // check if level is completed 191 | if (hasPower && finishEntity.finish.connected && !cable.cable.overpowered && numPoweredSpools === numSpools) { 192 | onLevelCompleted(); 193 | } 194 | 195 | if (numPoweredSpools != lastPoweredSpools) { 196 | nodeInfo.innerHTML = numPoweredSpools + ' / ' + numSpools; 197 | } 198 | 199 | 200 | lastPoweredSpools = numPoweredSpools; 201 | 202 | }); 203 | } 204 | }; 205 | }; 206 | -------------------------------------------------------------------------------- /src/start.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | /// 5 | /// 6 | /// 7 | 8 | const showEndScreen = () => { 9 | nextMsg.innerHTML = 'Thanks for playing!'; 10 | nextBtn.innerHTML = 'AGAIN'; 11 | showElement(levelDoneElement, () => { 12 | nextBtn.addEventListener('click', e => { 13 | location.reload(); 14 | }); 15 | }); 16 | saveLevel(0); 17 | }; 18 | 19 | const startGame = (parent: HTMLElement, resources: Resources, startLevel: number) => { 20 | const game = createGame(); 21 | let currentLevel = startLevel; 22 | 23 | const startNextLevel = () => { 24 | console.log('start level ' + currentLevel); 25 | 26 | let tutorial: HTMLElement; 27 | if (currentLevel == 0) { 28 | tutorial = resources.tutorial1; 29 | gameElement.appendChild(tutorial); 30 | showElement(tutorial); 31 | } 32 | if (currentLevel == 2) { 33 | tutorial = resources.tutorial2; 34 | gameElement.appendChild(tutorial); 35 | showElement(tutorial); 36 | } 37 | 38 | const level = game.createLevel(gameData.levels[currentLevel], resources, () => { 39 | if (tutorial) { 40 | hideElement(tutorial, () => { 41 | removeElement(tutorial); 42 | }); 43 | } 44 | if (currentLevel < gameData.levels.length - 1) { 45 | currentLevel++; 46 | saveLevel(currentLevel); 47 | hideElement(resetElement); 48 | showElement([levelDoneElement], () => { 49 | nextBtn.onclick = () => { 50 | nextBtn.onclick = null; 51 | hideElement([levelDoneElement, level.canvas, levelInfo, nodeInfo], () => { 52 | removeElement(level.canvas); 53 | startNextLevel(); 54 | }); 55 | 56 | }; 57 | }); 58 | } else { 59 | showEndScreen(); 60 | } 61 | }); 62 | 63 | parent.appendChild(level.canvas); 64 | levelInfo.innerHTML = 'Level ' + (currentLevel + 1); 65 | showElement([level.canvas, resetElement, levelInfo, nodeInfo]); 66 | 67 | const resetLevel = () => { 68 | if (tutorial) { 69 | hideElement(tutorial, () => { 70 | removeElement(tutorial); 71 | }); 72 | } 73 | backBtn.onclick = skipBtn.onclick = resetBtn.onclick = null; 74 | hideElement([level.canvas, resetElement, levelInfo, nodeInfo], () => { 75 | level.shutdown(); 76 | removeElement(level.canvas); 77 | startNextLevel(); 78 | }); 79 | 80 | }; 81 | 82 | resetBtn.onclick = resetLevel; 83 | skipBtn.onclick = () => { 84 | if (currentLevel > gameData.levels.length - 2) { 85 | return; 86 | } 87 | currentLevel++; 88 | resetLevel(); 89 | }; 90 | backBtn.onclick = () => { 91 | if (currentLevel < 1) { 92 | return; 93 | } 94 | currentLevel--; 95 | resetLevel(); 96 | }; 97 | }; 98 | 99 | startNextLevel(); 100 | }; 101 | 102 | const prepareGame = () => { 103 | const [loadingBar, context] = createCanvas(200, 7); 104 | loadingBar.id = 'loadingbar'; 105 | loadingElement.appendChild(loadingBar); 106 | showElement(loadingBar); 107 | context.strokeStyle = 'grey'; 108 | context.fillStyle = 'grey'; 109 | context.lineWidth = 1; 110 | 111 | context.strokeRect(0.5, 0.5, 199, 4); 112 | generateResources(p => { 113 | context.fillRect(0.5, 0.5, 199 / 100 * p, 4); 114 | }, (resources) => { 115 | 116 | hideElement(loadingBar, () => { 117 | showElement([menuElement, descriptionElement]); 118 | 119 | const savedLevel = loadLevel(); 120 | continueBtn.style.visibility = savedLevel ? 'visible' : 'hidden'; 121 | 122 | const hideUIandStartGame = (startLevel: number) => { 123 | startBtn.onclick = continueBtn.onclick = null; 124 | hideElement([titleElement, menuElement, descriptionElement], () => { 125 | startGame(contentElement, resources, startLevel); 126 | }); 127 | }; 128 | startBtn.onclick = () => { 129 | saveLevel(0); 130 | hideUIandStartGame(0); 131 | }; 132 | 133 | continueBtn.onclick = () => { 134 | hideUIandStartGame(savedLevel); 135 | }; 136 | 137 | // hideUIandStartGame(10); // skip main menu and start with level 138 | }); 139 | 140 | }); 141 | }; 142 | 143 | showElement(titleElement, prepareGame); 144 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | type Canvas = HTMLCanvasElement; 2 | type Context = CanvasRenderingContext2D; 3 | type FillStyle = string | CanvasGradient | CanvasPattern; 4 | type StrokeStyle = string | CanvasGradient | CanvasPattern 5 | 6 | enum Side {left = -1, right = 1} 7 | 8 | enum NodeType { 9 | spool, start, end, block, finish, isolator 10 | } 11 | 12 | interface GameObject { 13 | 14 | } 15 | 16 | type Color = { r: number, g: number, b: number, a: number } 17 | 18 | interface Connector { 19 | pos: Vec2; 20 | size: number; 21 | } 22 | 23 | type Activatable = Connector & { 24 | active?: boolean; 25 | } 26 | 27 | type HasPosition = { pos: Vec2; } 28 | 29 | type Spool = HasPosition & { size: number; } 30 | // interface Spool extends Connector { 31 | // hover?: boolean; 32 | // } 33 | 34 | type Vec2 = { 35 | x: number; 36 | y: number; 37 | }; 38 | 39 | type PositionComponent = { 40 | pos: Vec2; 41 | } 42 | 43 | type SpoolComponent = { 44 | type: NodeType; 45 | size: number; 46 | isAttached?:boolean; 47 | powered?: boolean; 48 | overpowered?: boolean; 49 | } 50 | 51 | type BlockComponent = { 52 | size: number; 53 | } 54 | type IsolatorComponent = { 55 | size: number; 56 | } 57 | 58 | type RenderComponent = { 59 | type: NodeType 60 | hover?: boolean 61 | } 62 | type InputComponent = { 63 | inputSize: number 64 | } 65 | type Attachment = { entity: SpoolEntity, side: Side; inPos?: Vec2, outPos?: Vec2, isolated?:boolean, overlap?:boolean } 66 | type MouseDragComponent = { size: number }; 67 | type CableComponent = { 68 | attachments: Attachment[]; 69 | overpowered?: boolean; 70 | } 71 | 72 | type FinishComponent = { connected?: boolean }; 73 | type Entity = { 74 | pos: Vec2; 75 | spool: SpoolComponent; 76 | block: BlockComponent; 77 | input: InputComponent; 78 | render: RenderComponent; 79 | isolator: IsolatorComponent; 80 | cable: CableComponent; 81 | mouseDrag: MouseDragComponent; 82 | finish: FinishComponent; 83 | // startNode?: EndNode; 84 | // EndNodeNode?: EndNode; 85 | } 86 | 87 | type SpoolEntity = Pick; 88 | type SpoolNodeEntity = Pick & SpoolEntity; 89 | type StartNodeEntity = Pick; 90 | type EndNodeEntity = Pick; 91 | type CableEntity = Pick; 92 | type RenderEntity = Pick; 93 | type MouseDragEntity = Pick; 94 | type FinishEntity = Pick; 95 | type BlockEntity = Pick; 96 | type BlockNodeEntity = Pick & BlockEntity; 97 | type IsolatorEntity = Pick; 98 | 99 | // TODO: do i need to differentiate between NodeEntity and Entity?! don't think so, remove NodeEntity 100 | 101 | /* 102 | Start 103 | HasPosition 104 | StartNode 105 | Spool 106 | End 107 | HasPosition 108 | Spool 109 | MouseEvents 110 | DragConnector 111 | Finish 112 | HasPosition 113 | FinishNode 114 | Spool 115 | HasPosition 116 | Spool 117 | 118 | 119 | 120 | */ 121 | 122 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | const nextFrame = requestAnimationFrame; 2 | const startFrameLoop = (callback: (time: number) => void ) => { 3 | 4 | let requestId: number; 5 | let stopLoop:boolean = false; 6 | let lastTime = 0; 7 | const update = (time: number) => { 8 | callback(time * 0.001); 9 | if (!stopLoop) { 10 | requestId = nextFrame(update); 11 | } 12 | lastTime = time; 13 | }; 14 | requestId= nextFrame(update); 15 | 16 | return () => { 17 | stopLoop = true; 18 | }; 19 | }; 20 | 21 | const tween = (from: number, to: number, duration:number, onUpdate: (t: number) => void, onComplete: () => void) => { 22 | const startTime = performance.now(); 23 | const update = (time: number) => { 24 | let t = 1/duration * (time-startTime)*0.001; 25 | if (t < 1) { 26 | onUpdate(from+(to-from)*t); 27 | nextFrame(update); 28 | } else { 29 | onUpdate(to); 30 | nextFrame(onComplete); 31 | } 32 | }; 33 | update(startTime); 34 | }; 35 | -------------------------------------------------------------------------------- /src/vector.ts: -------------------------------------------------------------------------------- 1 | /// 2 | const fract = (n:number) => ((n % 1) + 1) % 1; 3 | 4 | const subV = (v1: Vec2, v2: Vec2): Vec2 => ({x: v1.x - v2.x, y: v1.y - v2.y}); 5 | const addV = (v1: Vec2, v2: Vec2): Vec2 => ({x: v1.x + v2.x, y: v1.y + v2.y}); 6 | const mulVS = (v: Vec2, s: number): Vec2 => ({x: v.x * s, y: v.y * s}); 7 | const divVS = (v: Vec2, s: number): Vec2 => mulVS(v, 1 / s); 8 | const lenV = (v: Vec2): number => Math.sqrt(v.x * v.x + v.y * v.y); 9 | const distV = (v1: Vec2, v2: Vec2): number => lenV(subV(v1, v2)); 10 | const normalizeV = (v: Vec2): Vec2 => divVS(v, lenV(v) || 1); 11 | const perpLeftV = (v: Vec2) => ({x: -v.y, y: v.x}); 12 | const perpRightV = (v: Vec2) => ({x: v.y, y: -v.x}); 13 | const angleV = (v: Vec2): number => { 14 | let angle = Math.atan2(v.y, v.x); 15 | if (angle < 0) angle += 2 * Math.PI; 16 | return angle; 17 | }; 18 | const copyIntoV = (target: Vec2, source: Vec2): void => { 19 | target.x = source.x; 20 | target.y = source.y; 21 | }; 22 | const copyV = (source: Vec2): Vec2 => ({x:source.x, y: source.y}); 23 | const fractV = (v: Vec2) => ({x: fract(v.x), y: fract(v.y)}); 24 | const floorV = (v: Vec2) => ({x: ~~v.x, y: ~~v.y}); 25 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "none", 5 | "outFile": "./dist/app.js", 6 | "strict": true, 7 | "esModuleInterop": true, 8 | "inlineSourceMap": true, 9 | "inlineSources": true 10 | } 11 | } 12 | --------------------------------------------------------------------------------