diff --git a/.gitignore b/.gitignore index ebe50d5e0..6aefb3414 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.log +*.swp .DS_Store .env .sass-cache diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..c061c9209 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2917 @@ +{ + "name": "crafting-guide", + "version": "3.2.6", + "lockfileVersion": 1, + "dependencies": { + "abbrev": { + "version": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz", + "integrity": "sha1-0FVMIlZjbi9W58LlrRg/hZQo2B8=", + "dev": true + }, + "accepts": { + "version": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", + "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=" + }, + "acorn": { + "version": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz", + "integrity": "sha1-q259nYhqrKiwhbwzEreaGYQz8Oc=" + }, + "acorn-globals": { + "version": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz", + "integrity": "sha1-VbtemGkVB7dFedBRNBMhfDgMVM8=" + }, + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "dev": true, + "optional": true + }, + "align-text": { + "version": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=" + }, + "amdefine": { + "version": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" + }, + "ansi-regex": { + "version": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "aproba": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.1.2.tgz", + "integrity": "sha512-ZpYajIfO0j2cOFTO955KUMIKNmj6zhX8kVztMAxFsDaMwz+9Z9SV0uou2pC9HJqcfpffOsjnbrDMvkNy+9RXPw==", + "dev": true, + "optional": true + }, + "archiver": { + "version": "https://registry.npmjs.org/archiver/-/archiver-1.3.0.tgz", + "integrity": "sha1-TyGU1tj5nfP1MeaIHxTxXVX6ryI=", + "dev": true, + "dependencies": { + "async": { + "version": "https://registry.npmjs.org/async/-/async-2.4.0.tgz", + "integrity": "sha1-SZAgDxjqW4N8LMT4wDGmmFw4VhE=", + "dev": true + }, + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + } + } + }, + "archiver-utils": { + "version": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-1.3.0.tgz", + "integrity": "sha1-5QtMCccL89aA4y/xt5lOn52JUXQ=", + "dev": true, + "dependencies": { + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + } + } + }, + "are-we-there-yet": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", + "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", + "dev": true, + "optional": true + }, + "argparse": { + "version": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "dev": true + }, + "array-find-index": { + "version": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true + }, + "array-flatten": { + "version": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "asap": { + "version": "https://registry.npmjs.org/asap/-/asap-1.0.0.tgz", + "integrity": "sha1-sqRdpf36ILBJb8N2jMJ8EvqRan0=" + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "dev": true, + "optional": true + }, + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", + "dev": true, + "optional": true + }, + "assertion-error": { + "version": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz", + "integrity": "sha1-E8pRXYYgbaC6xm6DTdOX2HWBCUw=", + "dev": true + }, + "async": { + "version": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true, + "optional": true + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", + "dev": true, + "optional": true + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", + "dev": true, + "optional": true + }, + "backbone": { + "version": "https://registry.npmjs.org/backbone/-/backbone-1.3.3.tgz", + "integrity": "sha1-TMgOp8sWMaxHSInOQPL4vGg7KZk=" + }, + "balanced-match": { + "version": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "dev": true, + "optional": true + }, + "bl": { + "version": "https://registry.npmjs.org/bl/-/bl-1.2.1.tgz", + "integrity": "sha1-ysMo977kVzDUBLaSID/LWQ4XLV4=", + "dev": true + }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "dev": true + }, + "body-parser": { + "version": "https://registry.npmjs.org/body-parser/-/body-parser-1.17.1.tgz", + "integrity": "sha1-dbO8mN3W5+DY/+dQ36ylxmmT+kc=" + }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "dev": true + }, + "brace-expansion": { + "version": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz", + "integrity": "sha1-Pv/DxQ4ABTH7cg6v+A8K6O8jz1k=", + "dev": true + }, + "browser-stdout": { + "version": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", + "dev": true + }, + "browserify-zlib": { + "version": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", + "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=", + "dev": true + }, + "buffer-crc32": { + "version": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "dev": true + }, + "buffer-shims": { + "version": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", + "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=", + "dev": true + }, + "builtin-modules": { + "version": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "bytes": { + "version": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", + "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk=" + }, + "camelcase": { + "version": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "dev": true + }, + "camelcase-keys": { + "version": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true, + "optional": true + }, + "center-align": { + "version": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=" + }, + "chai": { + "version": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", + "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", + "dev": true + }, + "chalk": { + "version": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true + }, + "character-parser": { + "version": "https://registry.npmjs.org/character-parser/-/character-parser-1.2.1.tgz", + "integrity": "sha1-wN3kqxgnE7kZuXCVmhI+zBow/NY=" + }, + "clean-css": { + "version": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.25.tgz", + "integrity": "sha1-nppS1cHmvFEj4bJ4P6Zf6ViUbt4=", + "dependencies": { + "commander": { + "version": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=" + } + } + }, + "client-sessions": { + "version": "https://registry.npmjs.org/client-sessions/-/client-sessions-0.8.0.tgz", + "integrity": "sha1-p9jFVYrV1W8qGZ81M+tlS134k/0=" + }, + "cliui": { + "version": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dependencies": { + "wordwrap": { + "version": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" + } + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "coffee-script": { + "version": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.5.tgz", + "integrity": "sha1-gJ9FhUGRErv+RqBzrXVDrxjCc0Y=", + "dev": true + }, + "coffeeify": { + "version": "https://registry.npmjs.org/coffeeify/-/coffeeify-2.1.0.tgz", + "integrity": "sha1-Bt6Aqoe2GUk3c0Nh3vSt4lS3Gh4=", + "dev": true + }, + "colors": { + "version": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "dev": true + }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "dev": true + }, + "commander": { + "version": "https://registry.npmjs.org/commander/-/commander-2.6.0.tgz", + "integrity": "sha1-nfflL7Kgyw+4kFjugMMQQiXzfh0=" + }, + "compress-commons": { + "version": "https://registry.npmjs.org/compress-commons/-/compress-commons-1.2.0.tgz", + "integrity": "sha1-WFhwku8g03y1i68AARLJJ4/3O58=", + "dev": true + }, + "concat-map": { + "version": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", + "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, + "constantinople": { + "version": "https://registry.npmjs.org/constantinople/-/constantinople-3.0.2.tgz", + "integrity": "sha1-S5RdmTeQe82Y7ldRIsOBdRZUQUE=" + }, + "content-disposition": { + "version": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "content-type": { + "version": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz", + "integrity": "sha1-t9ETrueo3Se9IRM8TcJSnfFyHu0=" + }, + "convert-source-map": { + "version": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz", + "integrity": "sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU=", + "dev": true + }, + "cookie": { + "version": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookie-parser": { + "version": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.3.tgz", + "integrity": "sha1-D+MfoZ0AC5X0qt8fU/3CuKIDuqU=" + }, + "cookie-signature": { + "version": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "cookies": { + "version": "https://registry.npmjs.org/cookies/-/cookies-0.7.0.tgz", + "integrity": "sha1-C8lh2RDDUlSYD8fJ7/XaEgEbvwA=" + }, + "core-util-is": { + "version": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "crafting-guide-common": { + "version": "5.6.0", + "dependencies": { + "abbrev": { + "version": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz", + "integrity": "sha1-0FVMIlZjbi9W58LlrRg/hZQo2B8=" + }, + "ansi-regex": { + "version": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "argparse": { + "version": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=" + }, + "array-find-index": { + "version": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=" + }, + "assertion-error": { + "version": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz", + "integrity": "sha1-E8pRXYYgbaC6xm6DTdOX2HWBCUw=" + }, + "async": { + "version": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" + }, + "backbone": { + "version": "https://registry.npmjs.org/backbone/-/backbone-1.3.3.tgz", + "integrity": "sha1-TMgOp8sWMaxHSInOQPL4vGg7KZk=" + }, + "balanced-match": { + "version": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=" + }, + "body-parser": { + "version": "https://registry.npmjs.org/body-parser/-/body-parser-1.14.2.tgz", + "integrity": "sha1-EBXLH+LEQ4WCWVgdtTMy+NDPUPk=", + "dependencies": { + "iconv-lite": { + "version": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", + "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=" + }, + "qs": { + "version": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz", + "integrity": "sha1-qfMRQq9GjLcrJbMBNrokVoNJFr4=" + } + } + }, + "brace-expansion": { + "version": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz", + "integrity": "sha1-Pv/DxQ4ABTH7cg6v+A8K6O8jz1k=" + }, + "browser-stdout": { + "version": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=" + }, + "builtin-modules": { + "version": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" + }, + "bytes": { + "version": "https://registry.npmjs.org/bytes/-/bytes-2.2.0.tgz", + "integrity": "sha1-/TVGSkA/b5EXwt42Cez/nK4ABYg=" + }, + "camelcase": { + "version": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" + }, + "camelcase-keys": { + "version": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=" + }, + "chai": { + "version": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", + "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=" + }, + "chalk": { + "version": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=" + }, + "coffee-script": { + "version": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.5.tgz", + "integrity": "sha1-gJ9FhUGRErv+RqBzrXVDrxjCc0Y=" + }, + "colors": { + "version": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=" + }, + "commander": { + "version": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=" + }, + "concat-map": { + "version": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "content-type": { + "version": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz", + "integrity": "sha1-t9ETrueo3Se9IRM8TcJSnfFyHu0=" + }, + "currently-unhandled": { + "version": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=" + }, + "dateformat": { + "version": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", + "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=" + }, + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=" + }, + "decamelize": { + "version": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "deep-eql": { + "version": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", + "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", + "dependencies": { + "type-detect": { + "version": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", + "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=" + } + } + }, + "depd": { + "version": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz", + "integrity": "sha1-4b2Cxqq2ztlluXuIsX7T5SjKGMM=" + }, + "diff": { + "version": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", + "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=" + }, + "ee-first": { + "version": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "error-ex": { + "version": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", + "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=" + }, + "escape-string-regexp": { + "version": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "esprima": { + "version": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=" + }, + "eventemitter2": { + "version": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", + "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=" + }, + "exit": { + "version": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=" + }, + "faye-websocket": { + "version": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=" + }, + "file-sync-cmp": { + "version": "https://registry.npmjs.org/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz", + "integrity": "sha1-peeo/7+kk7Q7kju9TKiaU7Y7YSs=" + }, + "find-up": { + "version": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=" + }, + "findup-sync": { + "version": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz", + "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=", + "dependencies": { + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=" + } + } + }, + "formatio": { + "version": "https://registry.npmjs.org/formatio/-/formatio-1.2.0.tgz", + "integrity": "sha1-87IWfZBoxGmKjVH092CjmlTYGOs=" + }, + "fs.realpath": { + "version": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "gaze": { + "version": "https://registry.npmjs.org/gaze/-/gaze-1.1.2.tgz", + "integrity": "sha1-hHIkZ3rbiHDWeSV+0ziP22HkAQU=" + }, + "get-stdin": { + "version": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=" + }, + "getobject": { + "version": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz", + "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=" + }, + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", + "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=" + }, + "globule": { + "version": "https://registry.npmjs.org/globule/-/globule-1.1.0.tgz", + "integrity": "sha1-xJNS5NwYPYWJPuglOF65lLtt9F8=", + "dependencies": { + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=" + }, + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.16.6.tgz", + "integrity": "sha1-0iyaxmAojzhD4Wun0rXQbMon13c=" + } + } + }, + "graceful-fs": { + "version": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + }, + "graceful-readlink": { + "version": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" + }, + "growl": { + "version": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=" + }, + "grunt": { + "version": "https://registry.npmjs.org/grunt/-/grunt-1.0.1.tgz", + "integrity": "sha1-6HeHZOlEsY8yuw8QuQeEdcnftWs=", + "dependencies": { + "coffee-script": { + "version": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.10.0.tgz", + "integrity": "sha1-EpOLz5vhlI+gBvkuDEyegXBRCMA=" + }, + "grunt-cli": { + "version": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.2.0.tgz", + "integrity": "sha1-VisRnrsGndtGSs4oRVAb6Xs1tqg=" + } + } + }, + "grunt-contrib-clean": { + "version": "https://registry.npmjs.org/grunt-contrib-clean/-/grunt-contrib-clean-1.1.0.tgz", + "integrity": "sha1-Vkq/LQN4qYOhW54/MO51tzjEBjg=", + "dependencies": { + "rimraf": { + "version": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", + "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=" + } + } + }, + "grunt-contrib-coffee": { + "version": "https://registry.npmjs.org/grunt-contrib-coffee/-/grunt-contrib-coffee-1.0.0.tgz", + "integrity": "sha1-2u6wSVTxTihovMm6bq+RBf3C2kw=", + "dependencies": { + "ansi-regex": { + "version": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz", + "integrity": "sha1-QchHGUZGN15qGl0Qw8oFTvn8mA0=" + }, + "chalk": { + "version": "https://registry.npmjs.org/chalk/-/chalk-1.0.0.tgz", + "integrity": "sha1-s89O0P9Tl8mcdbj2edsvUoMfltw=" + }, + "coffee-script": { + "version": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.10.0.tgz", + "integrity": "sha1-EpOLz5vhlI+gBvkuDEyegXBRCMA=" + }, + "has-ansi": { + "version": "https://registry.npmjs.org/has-ansi/-/has-ansi-1.0.3.tgz", + "integrity": "sha1-wLWxYV2eOCsP9nFp2We0JeSMpTg=" + }, + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.3.0.tgz", + "integrity": "sha1-79nEpuxT87BUEkKZFcPkgk5NJaQ=" + }, + "strip-ansi": { + "version": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz", + "integrity": "sha1-32LBqpTtLxFOHQ8h/R1QSCt5pg4=" + }, + "supports-color": { + "version": "https://registry.npmjs.org/supports-color/-/supports-color-1.3.1.tgz", + "integrity": "sha1-FXWN8J2P87SswwdTn6vicJXhBC0=" + } + } + }, + "grunt-contrib-copy": { + "version": "https://registry.npmjs.org/grunt-contrib-copy/-/grunt-contrib-copy-1.0.0.tgz", + "integrity": "sha1-cGDGWB6QS4qw0A8HbgqPbj58NXM=" + }, + "grunt-contrib-watch": { + "version": "https://registry.npmjs.org/grunt-contrib-watch/-/grunt-contrib-watch-1.0.0.tgz", + "integrity": "sha1-hKGnodar0m7VaEE0lscxM+mQAY8=" + }, + "grunt-known-options": { + "version": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.0.tgz", + "integrity": "sha1-pCdO6zL6dl2lp6OxcSYXzjsUQUk=" + }, + "grunt-legacy-log": { + "version": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-1.0.0.tgz", + "integrity": "sha1-+4bxgJhHvAfcR4Q/ns1srLYt8tU=", + "dependencies": { + "underscore.string": { + "version": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.2.3.tgz", + "integrity": "sha1-gGmSYzZl1eX8tNsfs6hi62jp5to=" + } + } + }, + "grunt-legacy-log-utils": { + "version": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-1.0.0.tgz", + "integrity": "sha1-p7ji0Ps1taUPSvmG/BEnSevJbz0=", + "dependencies": { + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.3.0.tgz", + "integrity": "sha1-79nEpuxT87BUEkKZFcPkgk5NJaQ=" + } + } + }, + "grunt-legacy-util": { + "version": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-1.0.0.tgz", + "integrity": "sha1-OGqnjcbtUJhsKxiVcmWxtIq7m4Y=", + "dependencies": { + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.3.0.tgz", + "integrity": "sha1-79nEpuxT87BUEkKZFcPkgk5NJaQ=" + }, + "underscore.string": { + "version": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.2.3.tgz", + "integrity": "sha1-gGmSYzZl1eX8tNsfs6hi62jp5to=" + } + } + }, + "grunt-mocha-test": { + "version": "https://registry.npmjs.org/grunt-mocha-test/-/grunt-mocha-test-0.13.2.tgz", + "integrity": "sha1-Dzq8xqtUNkex7/xatE69NwLwq4w=" + }, + "has-ansi": { + "version": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=" + }, + "has-flag": { + "version": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=" + }, + "hooker": { + "version": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", + "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=" + }, + "hosted-git-info": { + "version": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.4.2.tgz", + "integrity": "sha1-AHa59GonBQbduq6lZJaJdGBhKmc=" + }, + "http-errors": { + "version": "https://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz", + "integrity": "sha1-GX4izevUGYWF6GlO9nhhl7ke2UI=" + }, + "iconv-lite": { + "version": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.16.tgz", + "integrity": "sha1-Zd477rOeKWDWfwSfFjT/y83pAUs=" + }, + "indent-string": { + "version": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=" + }, + "inflight": { + "version": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=" + }, + "inherits": { + "version": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "is-arrayish": { + "version": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "is-builtin-module": { + "version": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=" + }, + "is-finite": { + "version": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=" + }, + "is-utf8": { + "version": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" + }, + "isarray": { + "version": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "isexe": { + "version": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "js-yaml": { + "version": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.5.5.tgz", + "integrity": "sha1-A3fDgBfKvHMisNH7zSWkkWQfL74=" + }, + "json3": { + "version": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=" + }, + "livereload-js": { + "version": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.2.2.tgz", + "integrity": "sha1-bIclfmSKtHW8JOoldFftzB+NC8I=" + }, + "load-json-file": { + "version": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=" + }, + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=" + }, + "lodash._baseassign": { + "version": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=" + }, + "lodash._basecopy": { + "version": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=" + }, + "lodash._basecreate": { + "version": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", + "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=" + }, + "lodash._getnative": { + "version": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=" + }, + "lodash._isiterateecall": { + "version": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=" + }, + "lodash.create": { + "version": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", + "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=" + }, + "lodash.isarguments": { + "version": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=" + }, + "lodash.isarray": { + "version": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=" + }, + "lodash.keys": { + "version": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=" + }, + "lolex": { + "version": "https://registry.npmjs.org/lolex/-/lolex-1.6.0.tgz", + "integrity": "sha1-OpoCg0UqR9dDnnJzG54H1zhuSfY=" + }, + "loud-rejection": { + "version": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=" + }, + "map-obj": { + "version": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=" + }, + "media-typer": { + "version": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "meow": { + "version": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=" + }, + "mime-db": { + "version": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz", + "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=" + }, + "mime-types": { + "version": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", + "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=" + }, + "minimatch": { + "version": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha1-Kk5AkLlrLbBqnX3wEFWmKnfJt3Q=" + }, + "minimist": { + "version": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "mkdirp": { + "version": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dependencies": { + "minimist": { + "version": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + } + } + }, + "mocha": { + "version": "https://registry.npmjs.org/mocha/-/mocha-3.3.0.tgz", + "integrity": "sha1-0pt0KNP1LILi5l3x7LcGThqrv7U=", + "dependencies": { + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-2.6.0.tgz", + "integrity": "sha1-vFlryr52F/Edn6FTYe3tVgi4SZs=" + }, + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=" + }, + "ms": { + "version": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" + }, + "supports-color": { + "version": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", + "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=" + } + } + }, + "ms": { + "version": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" + }, + "native-promise-only": { + "version": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", + "integrity": "sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=" + }, + "nopt": { + "version": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=" + }, + "normalize-package-data": { + "version": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.8.tgz", + "integrity": "sha1-2Bntoqne29H/pWPqQHHZNngilbs=" + }, + "number-is-nan": { + "version": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "object-assign": { + "version": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "on-finished": { + "version": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=" + }, + "once": { + "version": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=" + }, + "parse-json": { + "version": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=" + }, + "parseurl": { + "version": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz", + "integrity": "sha1-yKuMkiO6NIiKpkopeyiFO+wY2lY=" + }, + "path-exists": { + "version": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=" + }, + "path-is-absolute": { + "version": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-to-regexp": { + "version": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", + "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=" + }, + "path-type": { + "version": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=" + }, + "pify": { + "version": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, + "pinkie": { + "version": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=" + }, + "qs": { + "version": "https://registry.npmjs.org/qs/-/qs-5.1.0.tgz", + "integrity": "sha1-TZMuXH6kEcynajEtOaYGIA/VDNk=" + }, + "raw-body": { + "version": "https://registry.npmjs.org/raw-body/-/raw-body-2.1.7.tgz", + "integrity": "sha1-rf6s4uT7MJgFgBTQjActzFl1h3Q=", + "dependencies": { + "bytes": { + "version": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", + "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk=" + }, + "iconv-lite": { + "version": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", + "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=" + } + } + }, + "read-pkg": { + "version": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=" + }, + "read-pkg-up": { + "version": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=" + }, + "redent": { + "version": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=" + }, + "repeating": { + "version": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=" + }, + "resolve": { + "version": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=" + }, + "rimraf": { + "version": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", + "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=" + }, + "samsam": { + "version": "https://registry.npmjs.org/samsam/-/samsam-1.2.1.tgz", + "integrity": "sha1-7dOQk6MYQ3DLhZJDsr3yVefY6mc=" + }, + "semver": { + "version": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" + }, + "signal-exit": { + "version": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + }, + "sinon": { + "version": "https://registry.npmjs.org/sinon/-/sinon-2.1.0.tgz", + "integrity": "sha1-4Fep0r8bMvXW3WJijKnuOWGwyvs=", + "dependencies": { + "type-detect": { + "version": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.3.tgz", + "integrity": "sha1-Dj8mcLRAmbC0bChNE2p+9Jx0wuo=" + } + } + }, + "sinon-chai": { + "version": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-2.9.0.tgz", + "integrity": "sha1-NNggBCvJZhoUUnEw1AHrRixJu4Q=" + }, + "spdx-correct": { + "version": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", + "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=" + }, + "spdx-expression-parse": { + "version": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", + "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=" + }, + "spdx-license-ids": { + "version": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", + "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=" + }, + "sprintf-js": { + "version": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "statuses": { + "version": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" + }, + "strip-ansi": { + "version": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=" + }, + "strip-bom": { + "version": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=" + }, + "strip-indent": { + "version": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=" + }, + "supports-color": { + "version": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "text-encoding": { + "version": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", + "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=" + }, + "tiny-lr": { + "version": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-0.2.1.tgz", + "integrity": "sha1-s/26gC5dVqM8L28QeUsy5Hescp0=" + }, + "trim-newlines": { + "version": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=" + }, + "type-detect": { + "version": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", + "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=" + }, + "type-is": { + "version": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", + "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=" + }, + "underscore": { + "version": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", + "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" + }, + "underscore.inflections": { + "version": "https://registry.npmjs.org/underscore.inflections/-/underscore.inflections-0.2.1.tgz", + "integrity": "sha1-EBvTWeAq8pOqWhBidI6WPiCHZ/E=" + }, + "underscore.string": { + "version": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.4.tgz", + "integrity": "sha1-LCo/n4PmR2L9xF5s6sZRQoZCE9s=" + }, + "unpipe": { + "version": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "uri-path": { + "version": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz", + "integrity": "sha1-l0fwGDWJM8Md4PzP2C0TjmcmLjI=" + }, + "util-deprecate": { + "version": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz", + "integrity": "sha1-ZUS7ot/ajBzxfmKaOjBeK7H+5sE=" + }, + "validate-npm-package-license": { + "version": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", + "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=" + }, + "websocket-driver": { + "version": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz", + "integrity": "sha1-XLJVbOuF9Dc8bYI4qmkchFThOjY=" + }, + "websocket-extensions": { + "version": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz", + "integrity": "sha1-domUmcGEtu91Q3fC27DNbLVdKec=" + }, + "when": { + "version": "https://registry.npmjs.org/when/-/when-3.7.8.tgz", + "integrity": "sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I=" + }, + "which": { + "version": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", + "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=" + }, + "wrappy": { + "version": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } + }, + "crc": { + "version": "https://registry.npmjs.org/crc/-/crc-3.4.4.tgz", + "integrity": "sha1-naHpgOO9RPxck79as9ozeNheRms=" + }, + "crc32-stream": { + "version": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-2.0.0.tgz", + "integrity": "sha1-483TtN8xaN10494/u8t7KX/pCPQ=", + "dev": true + }, + "cross-spawn": { + "version": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-0.2.9.tgz", + "integrity": "sha1-vWf5bAfvtjA7f+lMHpefiEeOCjk=", + "dev": true + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "dev": true, + "optional": true + }, + "css": { + "version": "https://registry.npmjs.org/css/-/css-1.0.8.tgz", + "integrity": "sha1-k4aBHKgrzMnuf7WnMrHioxfIo+c=" + }, + "css-parse": { + "version": "https://registry.npmjs.org/css-parse/-/css-parse-1.0.4.tgz", + "integrity": "sha1-OLBQP7+dqfVOnB29pg4UXHcRe90=" + }, + "css-stringify": { + "version": "https://registry.npmjs.org/css-stringify/-/css-stringify-1.0.5.tgz", + "integrity": "sha1-sNBClG2ylTu50pKQCmy19tASIDE=" + }, + "currently-unhandled": { + "version": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true + }, + "dargs": { + "version": "https://registry.npmjs.org/dargs/-/dargs-4.1.0.tgz", + "integrity": "sha1-A6nbtLXC8Tm/FK5T8LiipqhvThc=", + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "optional": true, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true, + "optional": true + } + } + }, + "dateformat": { + "version": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", + "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", + "dev": true + }, + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-2.6.1.tgz", + "integrity": "sha1-eYVQkLosTjEVzH2HaUkdWPBJE1E=" + }, + "decamelize": { + "version": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "deep-eql": { + "version": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", + "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", + "dev": true, + "dependencies": { + "type-detect": { + "version": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", + "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=", + "dev": true + } + } + }, + "deep-extend": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", + "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=", + "dev": true, + "optional": true + }, + "define-properties": { + "version": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", + "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", + "dev": true + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true, + "optional": true + }, + "depd": { + "version": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz", + "integrity": "sha1-4b2Cxqq2ztlluXuIsX7T5SjKGMM=" + }, + "destroy": { + "version": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "diff": { + "version": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", + "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", + "dev": true + }, + "dotenv": { + "version": "https://registry.npmjs.org/dotenv/-/dotenv-4.0.0.tgz", + "integrity": "sha1-hk7xN5rO1Vzm+V3r7NzhefegzR0=" + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "dev": true, + "optional": true + }, + "ee-first": { + "version": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz", + "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA=" + }, + "end-of-stream": { + "version": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.0.tgz", + "integrity": "sha1-epDYM+/abPpurA9JSduw+tOmMgY=", + "dev": true + }, + "error-ex": { + "version": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", + "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", + "dev": true + }, + "escape-html": { + "version": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "escape-string-regexp": { + "version": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esprima": { + "version": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + }, + "etag": { + "version": "https://registry.npmjs.org/etag/-/etag-1.8.0.tgz", + "integrity": "sha1-b2Ma7zNtbEY2K1F2QETOIWvjwFE=" + }, + "eventemitter2": { + "version": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", + "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=", + "dev": true + }, + "exit": { + "version": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "express": { + "version": "https://registry.npmjs.org/express/-/express-4.15.2.tgz", + "integrity": "sha1-rxB/wUhQRFfy3Kmm8lcdcSm5ezU=" + }, + "express-session": { + "version": "https://registry.npmjs.org/express-session/-/express-session-1.15.2.tgz", + "integrity": "sha1-2YUWRDpMy4aI4XJa5YTALapAk9Q=", + "dependencies": { + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-2.6.3.tgz", + "integrity": "sha1-D364wwll7AjHKsz6ATDIt5mEFB0=" + } + } + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", + "dev": true, + "optional": true + }, + "extsprintf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", + "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=", + "dev": true + }, + "faye-websocket": { + "version": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "dev": true + }, + "figures": { + "version": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true + }, + "file-sync-cmp": { + "version": "https://registry.npmjs.org/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz", + "integrity": "sha1-peeo/7+kk7Q7kju9TKiaU7Y7YSs=", + "dev": true + }, + "finalhandler": { + "version": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.2.tgz", + "integrity": "sha1-0ONvnbxVfy3hRCPfYmGInp1gyTo=", + "dependencies": { + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-2.6.4.tgz", + "integrity": "sha1-dYaps8OXQcAoKuM0RcTorHRzT+A=" + }, + "ms": { + "version": "https://registry.npmjs.org/ms/-/ms-0.7.3.tgz", + "integrity": "sha1-cIFVpeROM/X9D8U+gdDUCpG+H/8=" + } + } + }, + "find-up": { + "version": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true + }, + "findup-sync": { + "version": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz", + "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=", + "dev": true, + "dependencies": { + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "dev": true + } + } + }, + "foreach": { + "version": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true, + "optional": true + }, + "form-data": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "dev": true, + "optional": true + }, + "formatio": { + "version": "https://registry.npmjs.org/formatio/-/formatio-1.2.0.tgz", + "integrity": "sha1-87IWfZBoxGmKjVH092CjmlTYGOs=", + "dev": true + }, + "forwarded": { + "version": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz", + "integrity": "sha1-Ge+YdMSuHCl7zweP3mOgm2aoQ2M=" + }, + "fresh": { + "version": "https://registry.npmjs.org/fresh/-/fresh-0.5.0.tgz", + "integrity": "sha1-9HTKXmqSRtb9jglTz6m5yAWvp44=" + }, + "fs.realpath": { + "version": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fstream": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", + "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", + "dev": true + }, + "fstream-ignore": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz", + "integrity": "sha1-nDHa40dnAY/h0kmyTa2mfQktoQU=", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.0.tgz", + "integrity": "sha1-FhdnFMgBeY5Ojyz391KUZ7tKV3E=", + "dev": true + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "optional": true + }, + "gaze": { + "version": "https://registry.npmjs.org/gaze/-/gaze-1.1.2.tgz", + "integrity": "sha1-hHIkZ3rbiHDWeSV+0ziP22HkAQU=", + "dev": true + }, + "get-stdin": { + "version": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true + }, + "getobject": { + "version": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz", + "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "optional": true, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true, + "optional": true + } + } + }, + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", + "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=", + "dev": true + }, + "globule": { + "version": "https://registry.npmjs.org/globule/-/globule-1.1.0.tgz", + "integrity": "sha1-xJNS5NwYPYWJPuglOF65lLtt9F8=", + "dev": true, + "dependencies": { + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "dev": true + }, + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.16.6.tgz", + "integrity": "sha1-0iyaxmAojzhD4Wun0rXQbMon13c=", + "dev": true + } + } + }, + "graceful-fs": { + "version": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + }, + "graceful-readlink": { + "version": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" + }, + "growl": { + "version": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", + "dev": true + }, + "grunt": { + "version": "https://registry.npmjs.org/grunt/-/grunt-1.0.1.tgz", + "integrity": "sha1-6HeHZOlEsY8yuw8QuQeEdcnftWs=", + "dev": true, + "dependencies": { + "coffee-script": { + "version": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.10.0.tgz", + "integrity": "sha1-EpOLz5vhlI+gBvkuDEyegXBRCMA=", + "dev": true + }, + "grunt-cli": { + "version": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.2.0.tgz", + "integrity": "sha1-VisRnrsGndtGSs4oRVAb6Xs1tqg=", + "dev": true + } + } + }, + "grunt-contrib-clean": { + "version": "https://registry.npmjs.org/grunt-contrib-clean/-/grunt-contrib-clean-1.1.0.tgz", + "integrity": "sha1-Vkq/LQN4qYOhW54/MO51tzjEBjg=", + "dev": true, + "dependencies": { + "rimraf": { + "version": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", + "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", + "dev": true + } + } + }, + "grunt-contrib-coffee": { + "version": "https://registry.npmjs.org/grunt-contrib-coffee/-/grunt-contrib-coffee-1.0.0.tgz", + "integrity": "sha1-2u6wSVTxTihovMm6bq+RBf3C2kw=", + "dev": true, + "dependencies": { + "ansi-regex": { + "version": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz", + "integrity": "sha1-QchHGUZGN15qGl0Qw8oFTvn8mA0=", + "dev": true + }, + "chalk": { + "version": "https://registry.npmjs.org/chalk/-/chalk-1.0.0.tgz", + "integrity": "sha1-s89O0P9Tl8mcdbj2edsvUoMfltw=", + "dev": true + }, + "coffee-script": { + "version": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.10.0.tgz", + "integrity": "sha1-EpOLz5vhlI+gBvkuDEyegXBRCMA=", + "dev": true + }, + "has-ansi": { + "version": "https://registry.npmjs.org/has-ansi/-/has-ansi-1.0.3.tgz", + "integrity": "sha1-wLWxYV2eOCsP9nFp2We0JeSMpTg=", + "dev": true + }, + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.3.0.tgz", + "integrity": "sha1-79nEpuxT87BUEkKZFcPkgk5NJaQ=", + "dev": true + }, + "strip-ansi": { + "version": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz", + "integrity": "sha1-32LBqpTtLxFOHQ8h/R1QSCt5pg4=", + "dev": true + }, + "supports-color": { + "version": "https://registry.npmjs.org/supports-color/-/supports-color-1.3.1.tgz", + "integrity": "sha1-FXWN8J2P87SswwdTn6vicJXhBC0=", + "dev": true + } + } + }, + "grunt-contrib-compress": { + "version": "https://registry.npmjs.org/grunt-contrib-compress/-/grunt-contrib-compress-1.4.1.tgz", + "integrity": "sha1-NiEum7tB6bQf9vvi/HcoHGmrAqA=", + "dev": true, + "dependencies": { + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + } + } + }, + "grunt-contrib-copy": { + "version": "https://registry.npmjs.org/grunt-contrib-copy/-/grunt-contrib-copy-1.0.0.tgz", + "integrity": "sha1-cGDGWB6QS4qw0A8HbgqPbj58NXM=", + "dev": true + }, + "grunt-contrib-jade": { + "version": "https://registry.npmjs.org/grunt-contrib-jade/-/grunt-contrib-jade-1.0.0.tgz", + "integrity": "sha1-tVe8uc0uczrU4gkOEpvrIBsLhFw=", + "dev": true + }, + "grunt-contrib-sass": { + "version": "https://registry.npmjs.org/grunt-contrib-sass/-/grunt-contrib-sass-1.0.0.tgz", + "integrity": "sha1-gGg4JRy8DhqU1k1RXN00z2dNcBs=", + "dev": true, + "dependencies": { + "async": { + "version": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=", + "dev": true + } + } + }, + "grunt-contrib-uglify": { + "version": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-2.3.0.tgz", + "integrity": "sha1-s9AmDr3WzvoS/y+Onh4ln33kIW8=", + "dev": true + }, + "grunt-contrib-watch": { + "version": "https://registry.npmjs.org/grunt-contrib-watch/-/grunt-contrib-watch-1.0.0.tgz", + "integrity": "sha1-hKGnodar0m7VaEE0lscxM+mQAY8=", + "dev": true + }, + "grunt-known-options": { + "version": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.0.tgz", + "integrity": "sha1-pCdO6zL6dl2lp6OxcSYXzjsUQUk=", + "dev": true + }, + "grunt-legacy-log": { + "version": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-1.0.0.tgz", + "integrity": "sha1-+4bxgJhHvAfcR4Q/ns1srLYt8tU=", + "dev": true, + "dependencies": { + "underscore.string": { + "version": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.2.3.tgz", + "integrity": "sha1-gGmSYzZl1eX8tNsfs6hi62jp5to=", + "dev": true + } + } + }, + "grunt-legacy-log-utils": { + "version": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-1.0.0.tgz", + "integrity": "sha1-p7ji0Ps1taUPSvmG/BEnSevJbz0=", + "dev": true, + "dependencies": { + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.3.0.tgz", + "integrity": "sha1-79nEpuxT87BUEkKZFcPkgk5NJaQ=", + "dev": true + } + } + }, + "grunt-legacy-util": { + "version": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-1.0.0.tgz", + "integrity": "sha1-OGqnjcbtUJhsKxiVcmWxtIq7m4Y=", + "dev": true, + "dependencies": { + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.3.0.tgz", + "integrity": "sha1-79nEpuxT87BUEkKZFcPkgk5NJaQ=", + "dev": true + }, + "underscore.string": { + "version": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.2.3.tgz", + "integrity": "sha1-gGmSYzZl1eX8tNsfs6hi62jp5to=", + "dev": true + } + } + }, + "grunt-mocha-test": { + "version": "https://registry.npmjs.org/grunt-mocha-test/-/grunt-mocha-test-0.13.2.tgz", + "integrity": "sha1-Dzq8xqtUNkex7/xatE69NwLwq4w=", + "dev": true + }, + "grunt-sass-globbing": { + "version": "https://registry.npmjs.org/grunt-sass-globbing/-/grunt-sass-globbing-1.5.1.tgz", + "integrity": "sha1-nmCVXNjLP0lt3QfPcc+UQFsjgtE=", + "dev": true + }, + "gzip-size": { + "version": "https://registry.npmjs.org/gzip-size/-/gzip-size-1.0.0.tgz", + "integrity": "sha1-Zs+LEBBHInuVus5uodoMF37Vwi8=", + "dev": true + }, + "har-schema": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", + "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", + "dev": true, + "optional": true + }, + "har-validator": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", + "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", + "dev": true, + "optional": true + }, + "has-ansi": { + "version": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true + }, + "has-flag": { + "version": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true, + "optional": true + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "dev": true, + "optional": true + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "dev": true + }, + "hooker": { + "version": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", + "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=", + "dev": true + }, + "hosted-git-info": { + "version": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.4.2.tgz", + "integrity": "sha1-AHa59GonBQbduq6lZJaJdGBhKmc=", + "dev": true + }, + "http-errors": { + "version": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.1.tgz", + "integrity": "sha1-X4uO2YrKVFZWv1cplzh/kEpyIlc=" + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz", + "integrity": "sha1-/iZaIYrGpXz+hUkn6dBMGYJe3es=" + }, + "iltorb": { + "version": "https://registry.npmjs.org/iltorb/-/iltorb-1.2.1.tgz", + "integrity": "sha1-hqfJJF8GxRqL94L0YZTY+yYMLnE=", + "dev": true, + "optional": true + }, + "indent-string": { + "version": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true + }, + "inflight": { + "version": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true + }, + "inherits": { + "version": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ini": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", + "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=", + "dev": true, + "optional": true + }, + "ipaddr.js": { + "version": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.3.0.tgz", + "integrity": "sha1-HgOlL9rYOou7KyXL9JmLTP/NPew=" + }, + "is-arrayish": { + "version": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-buffer": { + "version": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz", + "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=" + }, + "is-builtin-module": { + "version": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true + }, + "is-finite": { + "version": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true + }, + "is-promise": { + "version": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true, + "optional": true + }, + "is-utf8": { + "version": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "isarray": { + "version": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true, + "optional": true + }, + "jade": { + "version": "https://registry.npmjs.org/jade/-/jade-1.11.0.tgz", + "integrity": "sha1-nIDlOMEtP7lcjZu5VZ+gzAQEBf0=" + }, + "jquery": { + "version": "https://registry.npmjs.org/jquery/-/jquery-3.2.1.tgz", + "integrity": "sha1-XE2d5lKvbNCncBVKYxu6ErAVx4c=" + }, + "js-yaml": { + "version": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.5.5.tgz", + "integrity": "sha1-A3fDgBfKvHMisNH7zSWkkWQfL74=", + "dev": true + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true, + "optional": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "optional": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true, + "optional": true + }, + "json3": { + "version": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "dev": true + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true, + "optional": true + }, + "jsprim": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz", + "integrity": "sha1-o7h+QCmNjDgFUtjMdiigu5WiKRg=", + "dev": true, + "optional": true, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true, + "optional": true + } + } + }, + "jstransformer": { + "version": "https://registry.npmjs.org/jstransformer/-/jstransformer-0.0.2.tgz", + "integrity": "sha1-eq4pqQPRls+glz2IXT5HlH7Ndqs=" + }, + "keygrip": { + "version": "https://registry.npmjs.org/keygrip/-/keygrip-1.0.1.tgz", + "integrity": "sha1-sC+kgW7vIajEs1yp5Skh/8iaMOk=" + }, + "kind-of": { + "version": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.0.tgz", + "integrity": "sha1-tYq+TVwEStM3JqjBUltIz4kb/wc=" + }, + "lazy-cache": { + "version": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" + }, + "lazystream": { + "version": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", + "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", + "dev": true + }, + "livereload-js": { + "version": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.2.2.tgz", + "integrity": "sha1-bIclfmSKtHW8JOoldFftzB+NC8I=", + "dev": true + }, + "load-json-file": { + "version": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true + }, + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", + "dev": true + }, + "lodash._baseassign": { + "version": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", + "dev": true + }, + "lodash._basecopy": { + "version": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "dev": true + }, + "lodash._basecreate": { + "version": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", + "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", + "dev": true + }, + "lodash._getnative": { + "version": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "dev": true + }, + "lodash._isiterateecall": { + "version": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "dev": true + }, + "lodash.create": { + "version": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", + "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", + "dev": true + }, + "lodash.isarguments": { + "version": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "dev": true + }, + "lodash.isarray": { + "version": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "dev": true + }, + "lodash.keys": { + "version": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true + }, + "lolex": { + "version": "https://registry.npmjs.org/lolex/-/lolex-1.6.0.tgz", + "integrity": "sha1-OpoCg0UqR9dDnnJzG54H1zhuSfY=", + "dev": true + }, + "longest": { + "version": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" + }, + "loud-rejection": { + "version": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true + }, + "lru-cache": { + "version": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", + "dev": true + }, + "map-obj": { + "version": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + }, + "marked": { + "version": "https://registry.npmjs.org/marked/-/marked-0.3.6.tgz", + "integrity": "sha1-ssbGGPzOzk74bE/Gy4p8v1rtqNc=" + }, + "maxmin": { + "version": "https://registry.npmjs.org/maxmin/-/maxmin-1.1.0.tgz", + "integrity": "sha1-cTZehKmd2Piz99X94vANHn9zvmE=", + "dev": true, + "dependencies": { + "pretty-bytes": { + "version": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz", + "integrity": "sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ=", + "dev": true + } + } + }, + "media-typer": { + "version": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "meow": { + "version": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "dev": true + }, + "merge-descriptors": { + "version": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", + "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=" + }, + "mime-db": { + "version": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz", + "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=" + }, + "mime-types": { + "version": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", + "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=" + }, + "minimatch": { + "version": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha1-Kk5AkLlrLbBqnX3wEFWmKnfJt3Q=", + "dev": true + }, + "minimist": { + "version": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "mkdirp": { + "version": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dependencies": { + "minimist": { + "version": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + } + } + }, + "mocha": { + "version": "https://registry.npmjs.org/mocha/-/mocha-3.3.0.tgz", + "integrity": "sha1-0pt0KNP1LILi5l3x7LcGThqrv7U=", + "dev": true, + "dependencies": { + "commander": { + "version": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true + }, + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-2.6.0.tgz", + "integrity": "sha1-vFlryr52F/Edn6FTYe3tVgi4SZs=", + "dev": true + }, + "glob": { + "version": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "dev": true + }, + "supports-color": { + "version": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", + "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", + "dev": true + } + } + }, + "ms": { + "version": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" + }, + "nan": { + "version": "https://registry.npmjs.org/nan/-/nan-2.6.2.tgz", + "integrity": "sha1-5P805slf37WuzAjeZZb0NgWn20U=", + "dev": true, + "optional": true + }, + "native-promise-only": { + "version": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", + "integrity": "sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=", + "dev": true + }, + "negotiator": { + "version": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "node-pre-gyp": { + "version": "0.6.36", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz", + "integrity": "sha1-22BBEst04NR3VU6bUFsXq936t4Y=", + "dev": true, + "optional": true, + "dependencies": { + "nopt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "dev": true, + "optional": true + }, + "rimraf": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", + "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", + "dev": true, + "optional": true + } + } + }, + "nopt": { + "version": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true + }, + "normalize-package-data": { + "version": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.8.tgz", + "integrity": "sha1-2Bntoqne29H/pWPqQHHZNngilbs=", + "dev": true + }, + "normalize-path": { + "version": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "optional": true + }, + "number-is-nan": { + "version": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "dev": true, + "optional": true + }, + "object-assign": { + "version": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-keys": { + "version": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", + "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", + "dev": true + }, + "object.assign": { + "version": "https://registry.npmjs.org/object.assign/-/object.assign-4.0.4.tgz", + "integrity": "sha1-scnMBE7xuf5jYG/BQau7MuFHMMw=", + "dev": true + }, + "on-finished": { + "version": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=" + }, + "on-headers": { + "version": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", + "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=" + }, + "once": { + "version": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true + }, + "optimist": { + "version": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", + "integrity": "sha1-yQlBrVnkJzMokjB00s8ufLxuwNk=" + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz", + "integrity": "sha1-Qv5tWVPfBsgGS+bxdsPQWqqjRkQ=", + "dev": true, + "optional": true + }, + "pako": { + "version": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=", + "dev": true + }, + "parse-json": { + "version": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true + }, + "parseurl": { + "version": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz", + "integrity": "sha1-yKuMkiO6NIiKpkopeyiFO+wY2lY=" + }, + "path-exists": { + "version": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true + }, + "path-is-absolute": { + "version": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-to-regexp": { + "version": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "path-type": { + "version": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true + }, + "performance-now": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", + "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", + "dev": true, + "optional": true + }, + "pify": { + "version": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true + }, + "pretty-bytes": { + "version": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-3.0.1.tgz", + "integrity": "sha1-J9AAjXeAY6C0gRuzXHnxvV1fvM8=", + "dev": true + }, + "process-nextick-args": { + "version": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, + "promise": { + "version": "https://registry.npmjs.org/promise/-/promise-6.1.0.tgz", + "integrity": "sha1-LOcp9rlLRcJoka0GAsXJDgTG7vY=" + }, + "proxy-addr": { + "version": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.4.tgz", + "integrity": "sha1-J+VF9pYKRKYn2bREZ+NcG2tM4vM=" + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true, + "optional": true + }, + "qs": { + "version": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", + "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=" + }, + "random-bytes": { + "version": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=" + }, + "range-parser": { + "version": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, + "raw-body": { + "version": "https://registry.npmjs.org/raw-body/-/raw-body-2.2.0.tgz", + "integrity": "sha1-mUl2z2pQlqQRYoQEkvC9xdbn+5Y=" + }, + "rc": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.1.tgz", + "integrity": "sha1-LgPo5C7kULjLPc5lvhv4l04d/ZU=", + "dev": true, + "optional": true + }, + "read-pkg": { + "version": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true + }, + "read-pkg-up": { + "version": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true + }, + "readable-stream": { + "version": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.9.tgz", + "integrity": "sha1-z3jsb0ptHrQ9JkiMrJfwQudLf8g=", + "dev": true + }, + "redent": { + "version": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "dev": true + }, + "remove-trailing-separator": { + "version": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.1.tgz", + "integrity": "sha1-YV67lq9VlVLUv0BXyENtSGq2PMQ=", + "dev": true + }, + "repeat-string": { + "version": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "repeating": { + "version": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true + }, + "request": { + "version": "2.81.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", + "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", + "dev": true, + "optional": true + }, + "resolve": { + "version": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + }, + "right-align": { + "version": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=" + }, + "rimraf": { + "version": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", + "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", + "dev": true + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "samsam": { + "version": "https://registry.npmjs.org/samsam/-/samsam-1.2.1.tgz", + "integrity": "sha1-7dOQk6MYQ3DLhZJDsr3yVefY6mc=", + "dev": true + }, + "sass": { + "version": "https://registry.npmjs.org/sass/-/sass-0.5.0.tgz", + "integrity": "sha1-ne4Rg6D0ADYfLF00U78uVHBeA/k=", + "dev": true + }, + "semver": { + "version": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true + }, + "send": { + "version": "https://registry.npmjs.org/send/-/send-0.15.1.tgz", + "integrity": "sha1-igI1TCbm9cynAAZfXwzeupDse18=" + }, + "serve-static": { + "version": "https://registry.npmjs.org/serve-static/-/serve-static-1.12.1.tgz", + "integrity": "sha1-dEOpZePO1kes61Y5+ga/TRu+ADk=" + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true, + "optional": true + }, + "setprototypeof": { + "version": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" + }, + "signal-exit": { + "version": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "sinon": { + "version": "https://registry.npmjs.org/sinon/-/sinon-2.2.0.tgz", + "integrity": "sha1-OxtC/13vy/UaUqYqym1hFxuf0mI=", + "dev": true, + "dependencies": { + "isarray": { + "version": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "path-to-regexp": { + "version": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", + "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", + "dev": true + }, + "type-detect": { + "version": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.3.tgz", + "integrity": "sha1-Dj8mcLRAmbC0bChNE2p+9Jx0wuo=", + "dev": true + } + } + }, + "sinon-chai": { + "version": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-2.10.0.tgz", + "integrity": "sha1-arMAi7jK6ZKedE12ZXS0zzXzS1s=", + "dev": true + }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "dev": true, + "optional": true + }, + "source-map": { + "version": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=" + }, + "spdx-correct": { + "version": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", + "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", + "dev": true + }, + "spdx-expression-parse": { + "version": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", + "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", + "dev": true + }, + "spdx-license-ids": { + "version": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", + "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", + "dev": true + }, + "sprintf-js": { + "version": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "dev": true, + "optional": true, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true, + "optional": true + } + } + }, + "statuses": { + "version": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" + }, + "stream-buffers": { + "version": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz", + "integrity": "sha1-kdX1Ew0c75bc+n9yaUUYh0HQnuQ=", + "dev": true + }, + "string_decoder": { + "version": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.0.tgz", + "integrity": "sha1-8G9BFXtmTYYGn4S9vcmw2KsoFmc=", + "dev": true + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", + "dev": true, + "optional": true + }, + "strip-ansi": { + "version": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true + }, + "strip-bom": { + "version": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true + }, + "strip-indent": { + "version": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true, + "optional": true + }, + "supports-color": { + "version": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "tar": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", + "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", + "dev": true + }, + "tar-pack": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/tar-pack/-/tar-pack-3.4.0.tgz", + "integrity": "sha1-I74tf2cagzk3bL2wuP4/3r8xeYQ=", + "dev": true, + "optional": true, + "dependencies": { + "rimraf": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", + "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", + "dev": true, + "optional": true + } + } + }, + "tar-stream": { + "version": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.2.tgz", + "integrity": "sha1-+8bG6DwaGdTLSMfZYXH8JI7/x78=", + "dev": true + }, + "text-encoding": { + "version": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", + "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=", + "dev": true + }, + "through2": { + "version": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "dev": true + }, + "tiny-lr": { + "version": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-0.2.1.tgz", + "integrity": "sha1-s/26gC5dVqM8L28QeUsy5Hescp0=", + "dev": true, + "dependencies": { + "body-parser": { + "version": "https://registry.npmjs.org/body-parser/-/body-parser-1.14.2.tgz", + "integrity": "sha1-EBXLH+LEQ4WCWVgdtTMy+NDPUPk=", + "dev": true, + "dependencies": { + "qs": { + "version": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz", + "integrity": "sha1-qfMRQq9GjLcrJbMBNrokVoNJFr4=", + "dev": true + } + } + }, + "bytes": { + "version": "https://registry.npmjs.org/bytes/-/bytes-2.2.0.tgz", + "integrity": "sha1-/TVGSkA/b5EXwt42Cez/nK4ABYg=", + "dev": true + }, + "debug": { + "version": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true + }, + "http-errors": { + "version": "https://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz", + "integrity": "sha1-GX4izevUGYWF6GlO9nhhl7ke2UI=", + "dev": true + }, + "iconv-lite": { + "version": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", + "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=", + "dev": true + }, + "ms": { + "version": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + }, + "qs": { + "version": "https://registry.npmjs.org/qs/-/qs-5.1.0.tgz", + "integrity": "sha1-TZMuXH6kEcynajEtOaYGIA/VDNk=", + "dev": true + }, + "raw-body": { + "version": "https://registry.npmjs.org/raw-body/-/raw-body-2.1.7.tgz", + "integrity": "sha1-rf6s4uT7MJgFgBTQjActzFl1h3Q=", + "dev": true, + "dependencies": { + "bytes": { + "version": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", + "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk=", + "dev": true + } + } + } + } + }, + "tough-cookie": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", + "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", + "dev": true, + "optional": true + }, + "transformers": { + "version": "https://registry.npmjs.org/transformers/-/transformers-2.1.0.tgz", + "integrity": "sha1-XSPLNVYd2F3Gf7hIIwm0fVPM6ac=", + "dependencies": { + "is-promise": { + "version": "https://registry.npmjs.org/is-promise/-/is-promise-1.0.1.tgz", + "integrity": "sha1-MVc3YcBX4zwukaq56W2gjO++duU=" + }, + "promise": { + "version": "https://registry.npmjs.org/promise/-/promise-2.0.0.tgz", + "integrity": "sha1-RmSKqdYFr10ucMMCS/WUNtoCuA4=" + }, + "source-map": { + "version": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=" + }, + "uglify-js": { + "version": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.2.5.tgz", + "integrity": "sha1-puAqcNg5eSuXgEiLe4sYTAlcmcc=" + } + } + }, + "trim-newlines": { + "version": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "optional": true + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, + "optional": true + }, + "type-detect": { + "version": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", + "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=", + "dev": true + }, + "type-is": { + "version": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", + "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=" + }, + "typedarray": { + "version": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "uglify-js": { + "version": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.22.tgz", + "integrity": "sha1-1Uk0d4qNoUkD+imjJvskwKtRoaA=", + "dependencies": { + "source-map": { + "version": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=" + } + } + }, + "uglify-to-browserify": { + "version": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "optional": true + }, + "uid-number": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz", + "integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=", + "dev": true, + "optional": true + }, + "uid-safe": { + "version": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.4.tgz", + "integrity": "sha1-Otbzg2jG1MjHXsF2I/t5qh0HHYE=" + }, + "underscore": { + "version": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", + "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" + }, + "underscore.inflections": { + "version": "https://registry.npmjs.org/underscore.inflections/-/underscore.inflections-0.2.1.tgz", + "integrity": "sha1-EBvTWeAq8pOqWhBidI6WPiCHZ/E=" + }, + "underscore.string": { + "version": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.4.tgz", + "integrity": "sha1-LCo/n4PmR2L9xF5s6sZRQoZCE9s=" + }, + "unpipe": { + "version": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "uri-path": { + "version": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz", + "integrity": "sha1-l0fwGDWJM8Md4PzP2C0TjmcmLjI=", + "dev": true + }, + "util-deprecate": { + "version": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", + "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=" + }, + "uuid": { + "version": "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz", + "integrity": "sha1-ZUS7ot/ajBzxfmKaOjBeK7H+5sE=", + "dev": true, + "optional": true + }, + "validate-npm-package-license": { + "version": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", + "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", + "dev": true + }, + "vary": { + "version": "https://registry.npmjs.org/vary/-/vary-1.1.1.tgz", + "integrity": "sha1-Z1Neu2lMHVIldFeYRmUyP1h+jTc=" + }, + "verror": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", + "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=", + "dev": true, + "optional": true + }, + "void-elements": { + "version": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=" + }, + "walkdir": { + "version": "https://registry.npmjs.org/walkdir/-/walkdir-0.0.11.tgz", + "integrity": "sha1-oW0CXrkxvQO1LzCMrtD0D86+lTI=", + "dev": true + }, + "websocket-driver": { + "version": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz", + "integrity": "sha1-XLJVbOuF9Dc8bYI4qmkchFThOjY=", + "dev": true + }, + "websocket-extensions": { + "version": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz", + "integrity": "sha1-domUmcGEtu91Q3fC27DNbLVdKec=", + "dev": true + }, + "when": { + "version": "https://registry.npmjs.org/when/-/when-3.7.8.tgz", + "integrity": "sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I=" + }, + "which": { + "version": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", + "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", + "dev": true + }, + "wide-align": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", + "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", + "dev": true, + "optional": true + }, + "window-size": { + "version": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=" + }, + "with": { + "version": "https://registry.npmjs.org/with/-/with-4.0.3.tgz", + "integrity": "sha1-7v0VTp550sjTQXtkeo8U2f7M4U4=", + "dependencies": { + "acorn": { + "version": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz", + "integrity": "sha1-yM4n3grMdtiW0rH6099YjZ6C8BQ=" + } + } + }, + "wordwrap": { + "version": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + }, + "wrappy": { + "version": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "xtend": { + "version": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + }, + "yargs": { + "version": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dependencies": { + "camelcase": { + "version": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=" + } + } + }, + "zip-stream": { + "version": "https://registry.npmjs.org/zip-stream/-/zip-stream-1.1.1.tgz", + "integrity": "sha1-Uha0i7tNJlH2TVxubwnrSnOZ1Vc=", + "dev": true, + "dependencies": { + "lodash": { + "version": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + } + } + } + } +} diff --git a/package.json b/package.json index 5f8a79fb1..b62a407e2 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "body-parser": "1.17.1", "client-sessions": "0.8.0", "cookie-parser": "1.4.3", - "crafting-guide-common": ">=3.0.0 <4.0.0", + "crafting-guide-common": ">=5.0.0", "dotenv": "4.0.0", "express": "4.15.2", "express-session": "1.15.2", diff --git a/src/client/client.coffee b/src/client/client.coffee index 9c7bbc064..ebf5d2286 100644 --- a/src/client/client.coffee +++ b/src/client/client.coffee @@ -8,77 +8,86 @@ ############################################################################################################ # Allow Node.js-style `global` in addition to `window` -if typeof(global) is 'undefined' +if typeof(global) is "undefined" window.global = window -global._ = require '../common/underscore' -global.$ = require 'jquery' -global.c = require '../common/constants' +global._ = require "../common/underscore" +global.$ = require "jquery" +global.c = require "../common/constants" global.π = Math.PI global.ε = 0.0001 -global.w = require 'when' +global.w = require "when" -{Logger} = require('crafting-guide-common').util +{Logger} = require("crafting-guide-common").util global.logger = new Logger -Tracker = require './tracker' +Tracker = require "./tracker" global.tracker = new Tracker -marked = require 'marked' +marked = require "marked" marked.setOptions sanitize:true -global.Backbone = Backbone = require 'backbone' +global.Backbone = Backbone = require "backbone" Backbone.$ = $ ######################################################################################################################## global.hostName = window.location.hostname switch global.hostName - when 'prerender.crafting-guide.com' - global.env = 'prerender' + when "prerender.crafting-guide.com" + global.env = "prerender" logger.level = Logger.FATAL - apiBaseUrl = 'http://prerender.crafting-guide.com:4347' - when 'local.crafting-guide.com', 'localhost' - global.env = 'local' + apiBaseUrl = "http://prerender.crafting-guide.com:4347" + when "local.crafting-guide.com", "localhost" + global.env = "local" logger.level = Logger.DEBUG apiBaseUrl = "http://#{global.hostName}:4347" - when 'staging.crafting-guide.com' - global.env = 'staging' + when "staging.crafting-guide.com" + global.env = "staging" logger.level = Logger.VERBOSE - apiBaseUrl = 'http://api-staging.crafting-guide.com' - when 'crafting-guide.com' - global.env = 'production' + apiBaseUrl = "http://api-staging.crafting-guide.com" + when "crafting-guide.com" + global.env = "production" logger.level = Logger.INFO tracker.enabled = true - apiBaseUrl = 'http://api.crafting-guide.com' + apiBaseUrl = "http://api.crafting-guide.com" else throw new Error "cannot determine the environment of: #{window.location.hostname}" ######################################################################################################################## -Storage = require './storage' +Storage = require "./storage" storage = new Storage storage:global.localStorage ######################################################################################################################## tracker.trackPageView() -{CraftingGuideClient} = require('crafting-guide-common').api +{CraftingGuideClient} = require("crafting-guide-common").api client = _(new CraftingGuideClient(baseUrl:apiBaseUrl)).extend Backbone.Events client.onStatusChanged = (client, oldStatus, newStatus)-> logger.info "Crafting Guide server status changed from #{oldStatus} to #{newStatus}" - client.trigger 'change:status', client, oldStatus, newStatus - client.trigger 'change', client + client.trigger "change:status", client, oldStatus, newStatus + client.trigger "change", client client.startMonitoringStatus() ######################################################################################################################## -SiteController = require './site/site_controller' -global.site = site = new SiteController client:client, storage:storage -site.render() -site.loadDefaultModPack() -site.loadCurrentUser() +{http, ModPackStore, ItemDetailStore} = require("crafting-guide-common").api +storeOptions = http:http, baseUrl:"#{location.protocol}//#{location.hostname}:#{location.port}" +global.stores = + modPack: new ModPackStore storeOptions + itemDetail: new ItemDetailStore storeOptions -Backbone.history.start pushState:true -logger.info -> "CraftingGuide is ready" +######################################################################################################################## + +global.stores.modPack.load c.modPacks.default + .then (modPack)-> + SiteController = require "./site/site_controller" + global.site = site = new SiteController client:client, storage:storage, modPack:modPack + site.render() + site.loadCurrentUser() + + Backbone.history.start pushState:true + logger.info -> "CraftingGuide is ready" diff --git a/src/client/models/site/craft_page.coffee b/src/client/models/site/craft_page.coffee index 4f2325d41..30c2b0c1d 100644 --- a/src/client/models/site/craft_page.coffee +++ b/src/client/models/site/craft_page.coffee @@ -5,45 +5,90 @@ # All rights reserved. # -CraftingGuideCommon = require "crafting-guide-common" - -{BaseModel} = CraftingGuideCommon.deprecated -{Craftsman} = CraftingGuideCommon.deprecated.crafting -{Inventory} = CraftingGuideCommon.deprecated.game -{ModPack} = CraftingGuideCommon.deprecated.game +{Inventory} = require("crafting-guide-common").models +{Observable} = require("crafting-guide-common").util +{PlanBuilder} = require("crafting-guide-common").crafting +{ResourcesEvaluator} = require("crafting-guide-common").crafting +{StepsEvaluator} = require("crafting-guide-common").crafting ######################################################################################################################## -module.exports = class CraftPage extends BaseModel +module.exports = class CraftPage extends Observable - constructor: (attributes={}, options={})-> - if not attributes.modPack then throw new Error 'attributes.modPack is required' - attributes.params ?= null - attributes.craftsman ?= new Craftsman attributes.modPack - super attributes, options + constructor: (attributes={})-> + super - @modPack.on c.event.change, => @_consumeParams() - @on c.event.change + ':params', => @_consumeParams() - @craftsman.on c.event.change + ':stage', => @trigger c.event.change, this - @craftsman.on c.event.change + ':complete', => @trigger c.event.change, this + @muted -> @modPack = attributes.modPack + + @_currentPlan = null + @_have = new Inventory + @_planBuilder = new PlanBuilder new StepsEvaluator + @_want = new Inventory + + @_consumeParams attributes.params + + @_have.on Observable::ANY, this, "_onHaveChanged" + @_want.on Observable::ANY, this, "_onWantChanged" + + # Properties ################################################################################### + + Object.defineProperties @prototype, + + currentPlan: + get: -> return @_currentPlan + set: -> throw new Error "currentPlan cannot be assigned" + + have: + get: -> return @_have + set: -> throw new "have cannot be assigned" + + isDirty: + get: -> return @_isDirty + set: -> throw new Error "isDirty cannot be assigned" + + isOutdated: + get: -> return @currentPlan? and @isDirty + set: -> throw new Error "isOutdated cannot be assigned" + + modPack: + get: -> return @_modPack + set: (modPack)-> + if @_modPack? then throw new Error "modPack cannot be reassigned" + if not modPack? then throw new Error "modPack is required" + @_modPack = modPack + + planBuilder: + get: -> return @_planBuilder + set: -> throw new Error "planBuilder cannot be assigned" + + want: + get: -> return @_want + set: -> throw new Error "want cannot be assigned" + + # Public Methods ############################################################################### + + createPlan: -> + newPlan = @_planBuilder.createPlan @_want, @_have + @triggerPropertyChange "currentPlan", @_currentPlan, newPlan, -> + @_currentPlan = newPlan + @triggerPropertyChange "isDirty", @_isDirty, false # Private Methods ############################################################################## - _consumeParams: -> - return unless @params? + _consumeParams: (params)-> + return unless params?.inventoryText? - @craftsman.want.clear() - if not @params.inventoryText? - @params = null - else - inventory = new Inventory - inventory.parse @params.inventoryText + newWant = Inventory.fromUrlString params.inventoryText, @modPack + @_want.clear() - inventory.each (stack)=> - item = @modPack.findItem stack.itemSlug, enableAsNeeded:true - return unless item? and item.isCraftable + for itemId, stack of newWant.stacks + continue unless stack.item.isCraftable + @_want.add stack.item, stack.quantity - @craftsman.want.add stack.itemSlug, stack.quantity - inventory.remove stack.itemSlug + _onHaveChanged: -> + @triggerPropertyChange "isDirty", @_isDirty, true - if inventory.isEmpty then @params = null + _onWantChanged: -> + @triggerPropertyChange "isDirty", @_isDirty, true, -> + @_isDirty = true + if @want.isEmpty then @triggerPropertyChange "currentPlan", @_currentPlan, null diff --git a/src/client/models/site/item_display.coffee b/src/client/models/site/item_display.coffee new file mode 100644 index 000000000..a35582e0f --- /dev/null +++ b/src/client/models/site/item_display.coffee @@ -0,0 +1,62 @@ +# +# Crafting Guide - item_display.coffee +# +# Copyright © 2014-2017 by Redwood Labs +# All rights reserved. +# + +_ = require "../../../common/underscore" +c = require "../../../common/constants" +{Inventory} = require("crafting-guide-common").models + +######################################################################################################################## + +module.exports = class ItemDisplay + + constructor: (item)-> + @item = item + + # Properties ################################################################################### + + Object.defineProperties @prototype, + + craftingUrl: + get: -> + inventory = new Inventory + inventory.add @item + c.url.crafting inventoryText:inventory.toUrlString() + + iconUrl: + get: -> return c.url.itemIcon this + set: -> throw new Error "iconUrl cannot be assigned" + + item: + get: -> return @_item + set: (item)-> + if @_item? then throw new Error "item cannot be re-assigned" + if not item? then throw new Error "item is required" + @_item = item + + itemSlug: + get: -> return _.slugify @name + set: -> throw new Error "slug cannot be assigned" + + mod: + get: -> return @_item.mod + set: -> throw new Error "mod cannot be assigned" + + modId: + get: -> return @_item.mod.id + set: -> throw new Error "modId cannot be assigned" + + modUrl: + get: -> return c.url.mod modId:@item.mod.id + set: -> throw new Error "modUrl cannot be assigned" + + name: + get: -> return @item.displayName + set: -> throw new Error "name cannot be assigned" + + url: + get: -> return c.url.item this + set: -> throw new Error "url cannot be assigned" diff --git a/src/client/models/site/item_page.coffee b/src/client/models/site/item_page.coffee index c0a812bd8..88fcba6ba 100644 --- a/src/client/models/site/item_page.coffee +++ b/src/client/models/site/item_page.coffee @@ -5,53 +5,91 @@ # All rights reserved. # -{BaseModel} = require("crafting-guide-common").deprecated +{Item} = require("crafting-guide-common").models +ItemDisplay = require "./item_display" +{Observable} = require("crafting-guide-common").util ######################################################################################################################## -module.exports = class ItemPage extends BaseModel +module.exports = class ItemPage extends Observable - constructor: (attributes={}, options={})-> - if not attributes.modPack? then throw new Error 'attributes.modPack is required' - attributes.item ?= null - super attributes, options + constructor: (item)-> + if item.constructor isnt Item then throw new Error "item must be an Item instance" + @item = item + super + + # Properties ################################################################################### + + Object.defineProperties @prototype, + + item: + get: -> return @_item + set: (item)-> + if @_item? then throw new Error "item cannot be reassigned" + if not item? then throw new Error "item is required" + if @_item? then @_item.off Observable::ANY, this + @_item = item + @_item.on Observable::ANY, this, "_onItemChanged" + + itemDisplay: + get: -> return @_itemDisplay ?= new ItemDisplay @item + + mod: + get: -> return @_item.mod + set: -> throw new Error "mod cannot be assigned" + + modPack: + get: -> return @mod.modPack + set: -> throw new Error "modPack cannot be assigned" # Property Methods ############################################################################# findComponentInItems: -> - return @_findRecipesMatching (recipe)=> recipe.requires @item.slug - - findSimilarItems: -> - return null unless @item?.modVersion? - - result = [] - @item.modVersion.eachItemInGroup @item.group, (item)=> - result.push item - - return null unless result.length > 0 - return result + return @_findItemsWithMatchingRecipes (recipe)=> + recipe.computeQuantityRequired @item findRecipes: -> - return @modPack.findRecipes @item?.slug, [], alwaysFromOwningMod:true + return (recipe for recipeId, recipe of @item.recipes) - findToolForRecipes: -> - return @_findRecipesMatching (recipe)=> recipe.requiresTool @item.slug + findSimilarItems: -> + group = @mod.itemGroups[@item.groupName] + return unless group? + + return null unless group.length > 0 + return group + + findToolForItems: -> + return @_findItemsWithMatchingRecipes (recipe)=> + return recipe.tools[@item.id]? + + loadDetails: -> + stores.itemDetail.loadDetailFor @item + .catch (error)=> + if error.message.indexOf("404") is -1 + logger.error "Could not load details for item #{@item.id}: #{error.message}" + else + logger.info "Item #{@item.id} has no details file." # Private Methods ############################################################################## - _findRecipesMatching: (isAcceptable)-> - return null unless @item? - + _findItemsWithMatchingRecipes: (isMatching)-> result = {} - @modPack.eachMod (mod)=> - mod.eachRecipe (recipe)=> - if isAcceptable recipe - for outputStack in recipe.output - continue if recipe.isPassThroughFor outputStack.itemSlug - outputItem = @modPack.findItem outputStack.itemSlug, includeDisabled:true - result[outputItem.slug] = outputItem - result = _.values result - return null unless result.length > 0 + for modId, mod of @modPack.mods + for itemId, item of mod.items + for recipeId, recipe of item.recipes + if isMatching(recipe) + result[item.id] = item + + result = (item for itemId, item of result) + result.sort (a, b)-> + if not a?.displayName? and not b?.displayName? then return 0 + if not b?.displayName? then return +1 + if not a?.displayName? then return +1 + return a.displayName.localeCompare b.displayName + + return result + + _onItemChanged: -> + @trigger Observable::CHANGE - return result.sort (a, b)-> a.compareTo b diff --git a/src/client/models/site/item_selector.coffee b/src/client/models/site/item_selector.coffee index 2c4f8beb9..7e77ee3c0 100644 --- a/src/client/models/site/item_selector.coffee +++ b/src/client/models/site/item_selector.coffee @@ -5,52 +5,49 @@ # All rights reserved. # -{BaseModel} = require('crafting-guide-common').deprecated -{ItemSlug} = require('crafting-guide-common').deprecated.game +{Observable} = require("crafting-guide-common").util ######################################################################################################################## -module.exports = class ItemSelector extends BaseModel +module.exports = class ItemSelector extends Observable - constructor: (attributes={}, options={})-> - if not options.modPack? then throw new Error 'options.modPack is required' - options.isAcceptable ?= (item)-> return true # accept everything by default - super attributes, options + constructor: (modPack, options={})-> + super - @_isAcceptable = options.isAcceptable + @_isAcceptable = options.isAcceptable or (item)-> return true # accept everything by default @_maxResults = 100 @_minHintLength = 3 - @_modPack = options.modPack @_results = [] + @modPack = modPack + # Property Methods ############################################################################# Object.defineProperties @prototype, hint: - get: -> - return @_hint + get: -> return @_hint + set: (hint)-> + @triggerPropertyChange "hint", @_hint, hint, -> + @_hint = hint?.toLowerCase() + @_refreshResults() - set: (newHint)-> - oldHint = @_hint - return if newHint is oldHint - - @_hint = newHint.toLowerCase() - - @trigger c.event.change + ':hint', this, oldHint, newHint - @_refreshResults() - @trigger c.event.change, this + modPack: + get: -> return @_modPack + set: (modPack)-> + if not modPack? then throw new Error "modPack is required" + if @_modPack? then throw new Error "modPack cannot be reassigned" + @_modPack = modPack results: - get: -> - return @_results + get: -> return @_results # Private Methods ############################################################################## - _computeScore: (name, itemSlug)-> + _computeScore: (item)-> hintIndex = 0 hintLetter = @_hint[hintIndex] - name = name.toLowerCase() + name = item.displayName.toLowerCase() nextScore = 1 totalScore = 0 @@ -60,8 +57,6 @@ module.exports = class ItemSelector extends BaseModel nextScore += 1 hintIndex += 1 if hintIndex is @_hint.length - item = @_modPack.findItem itemSlug - return 0 unless item? return 0 unless @_isAcceptable item break @@ -70,34 +65,40 @@ module.exports = class ItemSelector extends BaseModel nextScore = 1 return 0 if hintIndex < @_hint.length - - totalScore *= @_hint.length / name.length return totalScore _refreshResults: -> - oldResults = @_results scoredItems = [] count = 0 - logger.verbose => "Looking for items which match: #{@_hint}" if @_hint.length >= @_minHintLength - @_modPack.eachMod (mod)=> + for modId, mod of @_modPack.mods return if count >= @_maxResults - return unless mod.enabled + return unless mod.isEnabled - mod.eachName (name, itemSlug)=> - return if scoredItems.length >= @_maxResults - return unless itemSlug.isQualified - - score = @_computeScore name, itemSlug - if score >= @_hint.length - scoredItems.push score:score, itemSlug:itemSlug + for itemId, item of mod.items + score = @_computeScore item + if score > 0 + scoredItems.push score:score, item:item scoredItems.sort (a, b)-> if a.score isnt b.score return if a.score > b.score then -1 else +1 - return ItemSlug.compare a.itemSlug, b.itemSlug - newResults = (e.itemSlug for e in scoredItems) - @_results = newResults - @trigger c.event.change + ':results', this, oldResults, newResults + nameA = a.item.displayName + nameB = b.item.displayName + if nameA.length isnt nameB.length + return if nameA.length < nameB.length then -1 else +1 + + if nameA isnt nameB + return if nameA < nameB then -1 else +1 + + return 0 + + @_results = [] + for element in scoredItems + @_results.push element.item + break if @_results.length >= @_maxResults + + @trigger c.event.change + ':results', this + diff --git a/src/client/models/site/markdown_image_list.coffee b/src/client/models/site/markdown_image_list.coffee index 42821fad3..a11755541 100644 --- a/src/client/models/site/markdown_image_list.coffee +++ b/src/client/models/site/markdown_image_list.coffee @@ -5,26 +5,22 @@ # All rights reserved. # -{BaseModel} = require('crafting-guide-common').deprecated +{Observable} = require("crafting-guide-common").util MarkdownImage = require './markdown_image' ######################################################################################################################## -module.exports = class MarkdownImageList extends BaseModel +module.exports = class MarkdownImageList extends Observable - constructor: (attributes={}, options={})-> - attributes.imageBase ?= '' - attributes.markdownText ?= null - super attributes, options + constructor: (options={})-> + super - @client = options.client - @_images = {} + @_images = [] + @muted => + @client = options.client + @imageBase = options.imageBase + @markdownText = options.markdownText - @on c.event.change + ':imageBase', => - for fileName, image of @_images - image.path = @imageBase - - @on c.event.change + ':markdownText', => @_analyzeMarkdownText() @_analyzeMarkdownText() # Public Methods ############################################################################### @@ -46,22 +42,43 @@ module.exports = class MarkdownImageList extends BaseModel # Property Methods ############################################################################# - getAll: -> - fileNames = (fileName for fileName, image of @_images).sort() - result = [] - for fileName in fileNames - result.push @_images[fileName] - - return result - - isValid: -> - for fileName, image of @_images - return false unless image.valid - return true - Object.defineProperties @prototype, - all: {get:@prototype.getAll} - valid: {get:@prototype.isValid} + + all: + get: -> + fileNames = (fileName for fileName, image of @_images).sort() + result = [] + for fileName in fileNames + result.push @_images[fileName] + + return result + + client: + get: -> return @_client + set: (client)-> + if not client? then throw new Error "client is required" + @_client = client + + imageBase: -> + get: -> return @_imageBase + set: (imageBase)-> + @triggerPropertyChange "imageBase", @_imageBase, imageBase, -> + @_imageBase = imageBase + for fileName, image of @_images + image.path = @imageBase + + markdownText: + get: -> return @_markdownText + set: (markdownText)-> + @triggerPropertyChange "markdownText", @_markdownText, markdownText, -> + @_markdownText = markdownText + @_analyzeMarkdownText() + + valid: + get: -> + for fileName, image of @_images + return false unless image.valid + return true # Private Methods ############################################################################## @@ -79,8 +96,8 @@ module.exports = class MarkdownImageList extends BaseModel image = @_images[fileName] if not image? image = new MarkdownImage {fileName:fileName, path:@imageBase}, {client:@client} - @listenTo image, c.event.change, => @trigger c.event.change, this - @trigger c.event.add, this, image + image.on Observable::CHANGE, this, "_onImageChanged" + @trigger Observable::ADD, image changed = true newImages[fileName] = image @@ -92,4 +109,7 @@ module.exports = class MarkdownImageList extends BaseModel if changed @_images = newImages - @trigger c.event.change, this + @trigger Observable::CHANGE + + _onImageChanged: -> + @trigger Observable::CHANGE diff --git a/src/client/models/site/markdown_image_list.test.coffee b/src/client/models/site/markdown_image_list.test.coffee index 58e458766..2bc701570 100644 --- a/src/client/models/site/markdown_image_list.test.coffee +++ b/src/client/models/site/markdown_image_list.test.coffee @@ -16,7 +16,7 @@ list = null describe 'markdown_image_list.coffee', -> beforeEach -> - list = new MarkdownImageList {}, client:{fetchFile:sinon.stub().returns(w.promise(->))} + list = new MarkdownImageList client:{fetchFile:sinon.stub().returns(w.promise(->))} describe '_analyzeMarkdownText', -> diff --git a/src/client/models/site/multiblock_display.coffee b/src/client/models/site/multiblock_display.coffee new file mode 100644 index 000000000..64df5b37d --- /dev/null +++ b/src/client/models/site/multiblock_display.coffee @@ -0,0 +1,53 @@ +# +# Crafting Guide - multiblock_display.coffee +# +# Copyright © 2014-2017 by Redwood Labs +# All rights reserved. +# + +{Inventory} = require("crafting-guide-common").models +{Observable} = require("crafting-guide-common").util + +######################################################################################################################## + +module.exports = class MultiblockDisplay extends Observable + + constructor: (recipe)-> + @_layerInventories = [] + @recipe = recipe + + # Properties ################################################################################### + + Object.defineProperties @prototype, + + recipe: + get: -> return @_recipe + set: (recipe)-> + if not recipe? then throw new Error "recipe is required" + if @_recipe? then throw new Error "recipe cannot be reassigned" + @_recipe = recipe + + # Public Methods ############################################################################### + + getInventory: (z)-> + if not z? + return @_fullInventory ?= @_createFullInventory() + else + return @_layerInventories[z] ?= @_addLayerInventory z + + # Private Methods ############################################################################## + + _addLayerInventory: (z, inventory=null)-> + inventory ?= new Inventory + for x in [0..@recipe.width] + for y in [0..@recipe.height] + stack = @recipe.getInputAt x, y, z + continue unless stack? + inventory.add stack.item, stack.quantity + return inventory + + _createFullInventory: (inventory=null)-> + inventory ?= new Inventory() + for z in [0..@recipe.depth] + @_addLayerInventory z, inventory + return inventory diff --git a/src/client/models/site/recipe_display.coffee b/src/client/models/site/recipe_display.coffee new file mode 100644 index 000000000..b7a0a56f0 --- /dev/null +++ b/src/client/models/site/recipe_display.coffee @@ -0,0 +1,134 @@ +# +# Crafting Guide - recipe_display.coffee +# +# Copyright © 2014-2017 by Redwood Labs +# All rights reserved. +# + +_ = require "../../../common/underscore" +c = require "../../../common/constants" +{Inventory} = require("crafting-guide-common").models +{Observable} = require("crafting-guide-common").util + +######################################################################################################################## + +module.exports = class RecipeDisplay extends Observable + + constructor: (options={})-> + if not options.recipe? then throw new Error "options.recipe is required" + super + + @_layerInventories = [] + + @multiplier = options.multiplier or 1 + @recipe = options.recipe + @showInputInventory = if options.showInputInventory then options.showInputInventory or false + @showOutputInventory = if options.showOutputInventory then options.showOutputInventory or false + @showOutputSlot = if options.showOutputSlot then options.showOutputSlot or false + + # Class Methods ################################################################################ + + @::RECIPE_TYPE = + CRAFTING_TABLE: "crafting_table" + MULTIBLOCK: "multiblock" + + @::ALL_RECIPE_TYPES = (value for key, value of @::RECIPE_TYPE) + + # Properties ################################################################################### + + Object.defineProperties @prototype, + + depth: + get: -> return @recipe.depth + set: -> throw new Error "depth cannot be assigned" + + height: + get: -> return @recipe.height + set: -> throw new Error "height cannot be assigned" + + multiplier: + get: -> return @_multiplier + set: (multiplier)-> + if not _.isNumber(multiplier) then multiplier = 1 + @triggerPropertyChange "multiplier", @_multiplier, multiplier + + recipe: + get: -> return @_recipe + set: (recipe)-> + return if recipe is @_recipe + if not recipe? then throw new Error "recipe is required" + if @_recipe? then throw new Error "recipe cannot be reassigned" + @_recipe = recipe + @_computeType() + + showInputInventory: + get: -> return @_showInputInventory + set: (showInputInventory)-> + @triggerPropertyChange "showInputInventory", @_showInputInventory, !!showInputInventory + + showOutputInventory: + get: -> return @_showOutputInventory + set: (showOutputInventory)-> + @triggerPropertyChange "showOutputInventory", @_showOutputInventory, !!showOutputInventory + + showOutputSlot: + get: -> return @_showOutputSlot + set: (showOutputSlot)-> + @triggerPropertyChange "showOutputSlot", @_showOutputSlot, !!showOutputSlot + + tools: + get: -> return @recipe.tools + set: -> throw new Error "tools cannot be assigned" + + type: + get: -> return @_type + set: -> throw new Error "type cannot be assigned" + + width: + get: -> return @recipe.width + set: -> throw new Error "width cannot be assigned" + + # Public Methods ############################################################################### + + getInputAt: (x, y, z)-> + return @recipe.getInputAt x, y, z + + getInventory: (z)-> + if not z? + return @_fullInventory ?= @_createFullInventory() + else + return @_layerInventories[z] ?= @_addLayerInventory z + + getOutputInventory: -> + if not @_outputInventory? + @_outputInventory = new Inventory + for stack in @recipe.allProducts + @_outputInventory.add stack.item, stack.quantity + + return @_outputInventory + + # Private Methods ############################################################################## + + _addLayerInventory: (z, inventory=null)-> + inventory ?= new Inventory + for x in [0..@recipe.width] + for y in [0..@recipe.height] + stack = @recipe.getInputAt x, y, z + continue unless stack? + inventory.add stack.item, stack.quantity * @multiplier + return inventory + + _computeType: -> + if not @recipe? + type = null + else if @recipe.depth > 1 + type = @RECIPE_TYPE.MULTIBLOCK + else + type = @RECIPE_TYPE.CRAFTING_TABLE + @triggerPropertyChange "type", @_type, type + + _createFullInventory: (inventory=null)-> + inventory ?= new Inventory() + for z in [0..@recipe.depth] + @_addLayerInventory z, inventory + return inventory diff --git a/src/client/models/stores/mod_pack_store.coffee b/src/client/models/stores/mod_pack_store.coffee deleted file mode 100644 index 8184c3e3d..000000000 --- a/src/client/models/stores/mod_pack_store.coffee +++ /dev/null @@ -1,56 +0,0 @@ -# -# Crafting Guide - mod_pack_store.coffee -# -# Copyright © 2014-2017 by Redwood Labs -# All rights reserved. -# - -ModPackJsonParser = require "../parsing/mod_pack_json_parser" -w = require "when" - -######################################################################################################################## - -module.exports = class ModPackStore - - constructor: -> - @_data = {} - @_loading = {} - @_parser = new ModPackJsonParser - - # Class Methods ################################################################################ - - Object.defineProperties ModPackStore, - instance: - get: -> - @_instance ?= new ModPackStore - return @_instance - set: -> - throw new Error "cannot assign instance" - - # Public Methods ############################################################################### - - get: (modPackId)-> - return @_data[modPackId] - - load: (modPackId)-> - if not @_loading[modPackId]? - @_loading[modPackId] = w.promise (resolve, reject)-> - url = c.url.modPackArchive modPackId:modPackId - - onError = (xhr, status, message)=> - logger.error "failed to load mod pack #{modPackId}: #{status} — #{message}" - reject new Error message - - onSuccess = (data, status, xhr)=> - logger.info "laoded mod pack: #{modPackId}" - try - @_parser.reset() - modPack = @_parser.parse data, url - @_data[modPack.id] = modPack - resolve modPack - catch error - reject error - - $.ajax dataType: "text", error: onError, success: onSuccess, url: url - - return @_loading[modPackId] diff --git a/src/client/site/base_controller.coffee b/src/client/site/base_controller.coffee index 21564d860..d1f7733f8 100644 --- a/src/client/site/base_controller.coffee +++ b/src/client/site/base_controller.coffee @@ -5,7 +5,8 @@ # All rights reserved. # -templates = require './templates' +{Observable} = require("crafting-guide-common").util +templates = require './templates' ######################################################################################################################## @@ -84,9 +85,6 @@ module.exports = class BaseController extends Backbone.View onDidModelChange: -> @tryRefresh() - onDidModelSync: -> - @tryRefresh() - onWillRender: -> # do nothing onDidRender: -> # do nothing @@ -96,11 +94,12 @@ module.exports = class BaseController extends Backbone.View onDidShow: -> # do nothing onWillChangeModel: (oldModel, newModel)-> - if oldModel?.on? - @stopListening oldModel - if newModel?.on? - @listenTo newModel, 'sync', (e)=> @onDidModelSync e - @listenTo newModel, 'change', (e)=> @onDidModelChange e + if oldModel?.isObservable + oldModel.off target:this + + if newModel?.isObservable + newModel.on Observable::ANY, this, "onDidModelChange" + return newModel # Property Methods ############################################################################# @@ -113,7 +112,7 @@ module.exports = class BaseController extends Backbone.View newModel = @onWillChangeModel @_model, newModel @_model = newModel - @tryRefresh() + @onDidModelChange() rendered: get: -> @_rendered @@ -147,9 +146,13 @@ module.exports = class BaseController extends Backbone.View @$el.append $renderedEl.children() @$el.addClass $renderedEl.attr 'class' - @$el.data $renderedEl.data() - @delegateEvents() + elementData = $renderedEl.data() + elementData.controller = this + elementData.model = data + @$el.data elementData + + @delegateEvents() @_rendered = true @onDidRender() diff --git a/src/client/site/browse_page/browse_page_controller.coffee b/src/client/site/browse_page/browse_page_controller.coffee index 7baa67088..28c8a648a 100644 --- a/src/client/site/browse_page/browse_page_controller.coffee +++ b/src/client/site/browse_page/browse_page_controller.coffee @@ -28,7 +28,6 @@ module.exports = class BrowsePageController extends PageController @_tileControllers = [] @_client.on c.event.change, => @tryRefresh() - @_modPack.on c.event.change, => @tryRefresh() # Property Methods ############################################################################# @@ -81,7 +80,7 @@ module.exports = class BrowsePageController extends PageController _refreshModTiles: -> index = 0 - mods = @_modPack.getAllMods() + mods = (mod for modId, mod of @_modPack.mods) for mod in mods controller = @_tileControllers[index] if not controller diff --git a/src/client/site/browse_page/mod_tile/mod_tile_controller.coffee b/src/client/site/browse_page/mod_tile/mod_tile_controller.coffee index ecb42f375..9c3fe8640 100644 --- a/src/client/site/browse_page/mod_tile/mod_tile_controller.coffee +++ b/src/client/site/browse_page/mod_tile/mod_tile_controller.coffee @@ -29,12 +29,12 @@ module.exports = class ModTileController extends BaseController super refresh: -> - @$link.attr 'href', c.url.mod modSlug:@model.slug - @$logoImage.attr 'src', c.url.modIcon modSlug:@model.slug - @$title.text @model.name + @$link.attr 'href', c.url.mod modId:@model.id + @$logoImage.attr 'src', c.url.modIcon modId:@model.id + @$title.text @model.displayName @$description.text @model.description - if @model.enabled + if @model.isEnabled @$el.removeClass 'disabled' else @$el.addClass 'disabled' diff --git a/src/client/site/common/crafting_grid/crafting_grid_controller.coffee b/src/client/site/common/crafting_grid/crafting_grid_controller.coffee index ab87389b9..53a22709c 100644 --- a/src/client/site/common/crafting_grid/crafting_grid_controller.coffee +++ b/src/client/site/common/crafting_grid/crafting_grid_controller.coffee @@ -5,39 +5,47 @@ # All rights reserved. # -BaseController = require '../../base_controller' -SlotController = require '../slot/slot_controller' +BaseController = require "../../base_controller" +{Recipe} = require("crafting-guide-common").models +SlotController = require "../slot/slot_controller" ######################################################################################################################## module.exports = class CraftingGridController extends BaseController constructor: (options={})-> - if not options.imageLoader? then throw new Error 'options.imageLoader is required' - if not options.modPack? then throw new Error 'options.modPack is required' - if not options.router? then throw new Error 'options.router is required' - # options.model should be a recipe - options.templateName = 'common/crafting_grid' + if not options.imageLoader? then throw new Error "options.imageLoader is required" + if not options.modPack? then throw new Error "options.modPack is required" + if not options.router? then throw new Error "options.router is required" + options.templateName = "common/crafting_grid" super options @_imageLoader = options.imageLoader @_modPack = options.modPack @_router = options.router - @_modPack.on c.event.change, => @tryRefresh() - # BaseController Methods ####################################################################### + onWillChangeModel: (oldModel, newModel)-> + if newModel? and (newModel.constructor isnt Recipe) then throw new Error "options.model must be a Recipe" + super + onDidRender: -> @_slotControllers = [] - for el in @$('.view__slot') + for el in @$(".view__slot") controller = new SlotController el:el, imageLoader:@_imageLoader, modPack:@_modPack, router:@_router controller.render() @_slotControllers.push controller super refresh: -> - for controller, index in @_slotControllers - controller.model = @model?.getStackAtSlot(index) + index = 0 + for y in [0..2] + for x in [0..2] + controller = @_slotControllers[index++] + if @model? + controller.model = @model.getInputAt x, y + else + controller.model = null super diff --git a/src/client/site/common/inventory/inventory_controller.coffee b/src/client/site/common/inventory/inventory_controller.coffee index 9e2e4fe11..1110080b1 100644 --- a/src/client/site/common/inventory/inventory_controller.coffee +++ b/src/client/site/common/inventory/inventory_controller.coffee @@ -47,8 +47,6 @@ module.exports = class InventoryController extends BaseController @_stackControllers = [] - @listenTo @_modPack, c.event.change, => @tryRefresh() - # Event Methods ################################################################################ onClearButtonClicked: -> @@ -61,31 +59,33 @@ module.exports = class InventoryController extends BaseController @trigger c.event.change, this onFirstButtonClicked: (stackController)-> - tracker.trackEvent @_trackingContext, 'remove-from', "#{stackController?.model?.itemSlug}" - @trigger c.event.button.first, this, stackController?.model?.itemSlug + item = stackController.model?.item + tracker.trackEvent @_trackingContext, 'remove-from', item.id + @trigger c.event.button.first, this, item onItemSelectorButtonClicked: -> return unless @model? tracker.trackEvent @_trackingContext, 'launch-add-to' @_selector.launch() - .then (itemSlug)=> - if not itemSlug? + .then (item)=> + if not item? tracker.trackEvent @_trackingContext, 'cancel-add-to' return - tracker.trackEvent @_trackingContext, 'complete-add-to', "#{itemSlug}" - @model.add itemSlug, 1 - @trigger c.event.add, this, itemSlug + tracker.trackEvent @_trackingContext, 'complete-add-to', "#{item.id}" + @model.add item, 1 + @trigger c.event.add, this, item.id @trigger c.event.change, this onSecondButtonClicked: (stackController)-> + itemId = stackController.model?.item.id @trigger c.event.button.second, this, stackController?.model?.itemSlug # BaseController Overrides ##################################################################### onDidRender: -> - @_selector = @addChild ItemSelectorController, null, isAcceptable: @_isAcceptable, modPack: @_modPack + @_selector = @addChild ItemSelectorController, null, isAcceptable:@_isAcceptable, modPack:@_modPack @$clearButton = @$('.button.clear') @$emptyPlaceholder = @$('.empty_placeholder') @@ -131,7 +131,7 @@ module.exports = class InventoryController extends BaseController index = 0 if @model? - @model.each (stack)=> + for itemId, stack of @model.stacks controller = @_stackControllers[index] if not controller? controller = new StackController @@ -153,7 +153,9 @@ module.exports = class InventoryController extends BaseController @$itemContainer.append controller.$el else controller.model = stack + index += 1 while @_stackControllers.length > index @_stackControllers.pop().remove() + diff --git a/src/client/site/common/item_group/item_tile/item_tile_controller.coffee b/src/client/site/common/item_group/item_tile/item_tile_controller.coffee index ad867f32e..147ed405e 100644 --- a/src/client/site/common/item_group/item_tile/item_tile_controller.coffee +++ b/src/client/site/common/item_group/item_tile/item_tile_controller.coffee @@ -5,39 +5,37 @@ # All rights reserved. # -BaseController = require '../../../base_controller' +BaseController = require "../../../base_controller" +ItemDisplay = require "../../../../models/site/item_display" ######################################################################################################################## module.exports = class ItemTileController extends BaseController constructor: (options={})-> - if not options.imageLoader? then throw new Error 'options.imageLoader is required' - if not options.model? then throw new Error 'options.model is required' - if not options.modPack? then throw new Error 'options.modPack is required' - options.templateName = 'common/item_group/item_tile' + if not options.imageLoader? then throw new Error "options.imageLoader is required" + if not options.model? then throw new Error "options.model is required" + options.templateName = "common/item_group/item_tile" super options @_imageLoader = options.imageLoader - @_modPack = options.modPack + @_display = new ItemDisplay @model # BaseController Overrides ##################################################################### onDidRender: -> - @$icon = @$('img') - @$name = @$('.itemName') - @$nameLink = @$('a') + @$icon = @$("img") + @$name = @$(".itemName") + @$nameLink = @$("a") super refresh: -> - display = @_modPack.findItemDisplay @model.slug - - @_imageLoader.load display.iconUrl, @$icon - @$name.html display.itemName - @$nameLink.attr 'href', display.itemUrl + @_imageLoader.load @_display.iconUrl, @$icon + @$name.html @_display.name + @$nameLink.attr "href", @_display.url # Backbone.View Overrides ###################################################################### events: -> return _.extend super, - 'click a': 'routeLinkClick' + "click a": "routeLinkClick" diff --git a/src/client/site/common/item_selector/element/element_controller.coffee b/src/client/site/common/item_selector/element/element_controller.coffee index c1ccbe108..38dd56d6c 100644 --- a/src/client/site/common/item_selector/element/element_controller.coffee +++ b/src/client/site/common/item_selector/element/element_controller.coffee @@ -5,58 +5,63 @@ # All rights reserved. # -BaseController = require '../../../base_controller' +BaseController = require "../../../base_controller" +ItemDisplay = require "../../../../models/site/item_display" ######################################################################################################################## module.exports = class ElementController extends BaseController constructor: (options={})-> - if not options.model? then throw new Error 'options.model is required' - options.onClicked ?= (controller)-> # do nothing - options.onSelected ?= (controller)-> # do nothing - options.templateName = 'common/item_selector/element' + if not options.model? then throw new Error "options.model is required" + options.templateName = "common/item_selector/element" options.useAnimations = false super options - @onClicked = options.onClicked - @onSelected = options.onSelected + @onClicked = options.onClicked or (controller)-> # do nothing + @onSelected = options.onSelected or (controller)-> # do nothing # Property Methods ############################################################################# - isSelected: -> - return @_selected - - setSelected: (newSelected)-> - oldSelected = @_selected - return if newSelected is oldSelected - - @_selected = newSelected - @tryRefresh() - - @trigger c.event.change + ':selected', this, oldSelected, newSelected - @trigger c.event.change, this - Object.defineProperties @prototype, - selected: {get:@prototype.isSelected, set:@prototype.setSelected} + + display: + get: -> return @_display ?= new ItemDisplay @model + set: -> throw new Error "display cannot be assigned" + + isSelected: + get: -> return @_selected + set: (newSelected)-> + oldSelected = @_selected + return if newSelected is oldSelected + + @_selected = newSelected + @tryRefresh() + + @trigger c.event.change + ":selected", this, oldSelected, newSelected + @trigger c.event.change, this # BaseController Overrides ##################################################################### + onDidModelChange: -> + @_display = null + super + onDidRender: -> - @$icon = @$('img') - @$name = @$('.name') - @$modName = @$('.modName') + @$icon = @$("img") + @$name = @$(".name") + @$modName = @$(".modName") super refresh: -> - @$icon.attr 'src', @model.iconUrl - @$name.html @model.itemName - @$modName.html @model.modName + @$icon.attr "src", @display.iconUrl + @$name.html @model.displayName + @$modName.html @model.mod.displayName if @_selected - @$el.addClass 'selected' + @$el.addClass "selected" else - @$el.removeClass 'selected' + @$el.removeClass "selected" super @@ -64,15 +69,15 @@ module.exports = class ElementController extends BaseController events: -> return _.extend super, - 'click': '_onClick' - 'mouseenter': '_onMouseEnter' + "click": "_onClick" + "mouseenter": "_onMouseEnter" # Private Methods ############################################################################## _onClick: (event)-> - event.preventDefault() @onClicked this + return false _onMouseEnter: (event)-> - event.preventDefault() @onSelected this + return false diff --git a/src/client/site/common/item_selector/item_selector_controller.coffee b/src/client/site/common/item_selector/item_selector_controller.coffee index 33c634a7a..25f70433d 100644 --- a/src/client/site/common/item_selector/item_selector_controller.coffee +++ b/src/client/site/common/item_selector/item_selector_controller.coffee @@ -5,21 +5,22 @@ # All rights reserved. # -BaseController = require '../../base_controller' -ItemSelector = require '../../../models/site/item_selector' -ElementController = require './element/element_controller' +BaseController = require "../../base_controller" +ItemDisplay = require "../../../models/site/item_display" +ItemSelector = require "../../../models/site/item_selector" +ElementController = require "./element/element_controller" w = require "when" ######################################################################################################################## module.exports = class ItemSelectorController extends BaseController - constructor: (options)-> - if not options.modPack? then throw new Error 'options.modPack is required' + constructor: (options={})-> + if not options.modPack? then throw new Error "options.modPack is required" options.isAcceptable ?= null - options.model ?= new ItemSelector {}, modPack:options.modPack, isAcceptable:options.isAcceptable + options.model ?= new ItemSelector options.modPack, isAcceptable:options.isAcceptable options.onChoseItem ?= (item)-> # do nothing - options.templateName = 'common/item_selector' + options.templateName = "common/item_selector" super options @_modPack = options.modPack @@ -29,25 +30,25 @@ module.exports = class ItemSelectorController extends BaseController # Public Methods ############################################################################### - launch: (hint='')-> + launch: (hint="")-> @model.hint = hint if @rendered then @refresh() @_disableWindowScrolling() - @$page.addClass 'blur' + @$page.addClass "blur" @$screen.append @$popup - @$screen.css 'display', '' + @$screen.css "display", "" @$popup.off c.event.click @$popup.on c.event.click, (event)=> @onPopupClicked(event) - @$hintField.off 'keyup input' - @$hintField.on 'keyup', (event)=> @onHintKeyPress(event) - @$hintField.on 'input', (event)=> @onHintChanged(event) + @$hintField.off "keyup input" + @$hintField.on "keyup", (event)=> @onHintKeyPress(event) + @$hintField.on "input", (event)=> @onHintChanged(event) @$hintField.focus() - @$closeButton.one 'click', (event)=> @_close() + @$closeButton.one "click", (event)=> @_close() @$screen.one c.event.click, (event)=> @onScreenClicked(event) @@ -85,17 +86,17 @@ module.exports = class ItemSelectorController extends BaseController return false onResultClicked: (controller)-> - @_session.resolve controller.model.slug + @_session.resolve controller.model @_session = null @_close() return false onResultSelected: (controller)-> for c in @_elementControllers - c.selected = false + c.isSelected = false if controller? - controller.selected = true + controller.isSelected = true return false @@ -106,14 +107,14 @@ module.exports = class ItemSelectorController extends BaseController # BaseController Overrides ##################################################################### onDidRender: -> - @$page = $('.page') # find the shared, global page - @$screen = $('.view__screen') # find the shared, global screen + @$page = $(".page") # find the shared, global page + @$screen = $(".view__screen") # find the shared, global screen - @$closeButton = @$('img.close') - @$popup = @$('.view__item_selector_popup') - @$hintField = @$('.view__item_selector_popup input') - @$searchInput = @$('.search input') - @$resultsContainer = @$('.results') + @$closeButton = @$("img.close") + @$popup = @$(".view__item_selector_popup") + @$hintField = @$(".view__item_selector_popup input") + @$searchInput = @$(".search input") + @$resultsContainer = @$(".results") @$popup.detach() super @@ -127,16 +128,16 @@ module.exports = class ItemSelectorController extends BaseController _chooseSelected: -> for controller in @_elementControllers - if controller.selected + if controller.isSelected @onResultClicked controller return _close: -> @_enableWindowScrolling() - @$page.removeClass 'blur' - @$screen.css 'display', 'none' + @$page.removeClass "blur" + @$screen.css "display", "none" @$popup.detach() - @model.hint = '' + @model.hint = "" if @_session @_session.resolve null @@ -144,28 +145,27 @@ module.exports = class ItemSelectorController extends BaseController _disableWindowScrolling: -> @_windowScrollPosition = $(window).scrollTop() - $('body').addClass('scrollDisabled').css('margin-top', -@_windowScrollPosition) + $("body").addClass("scrollDisabled").css("margin-top", -@_windowScrollPosition) _enableWindowScrolling: -> - $('body').removeClass('scrollDisabled').css('margin-top', 0) + $("body").removeClass("scrollDisabled").css("margin-top", 0) $(window).scrollTop @_windowScrollPosition _refreshResults: -> index = 0 - for itemSlug in @model.results - displayModel = @_modPack.findItemDisplay itemSlug + for item in @model.results controller = @_elementControllers[index] if not controller? controller = new ElementController - model: displayModel + model: item onClicked: (c)=> @onResultClicked(c) onSelected: (c)=> @onResultSelected(c) controller.render show:false @_elementControllers[index] = controller @$resultsContainer.append controller.$el else - controller.model = displayModel + controller.model = item controller.show() index += 1 @@ -180,14 +180,17 @@ module.exports = class ItemSelectorController extends BaseController controller = @_elementControllers[i] nextController = @_elementControllers[i + 1] - if controller.selected - controller.selected = false - nextController.selected = true + if controller.isSelected + controller.isSelected = false + nextController.isSelected = true @_showElement nextController.$el return + [..., controller] = @_elementControllers + controller.isSelected = false + controller = @_elementControllers[0] - controller.selected = true + controller.isSelected = true @_showElement controller.$el _selectPrevious: -> @@ -197,14 +200,17 @@ module.exports = class ItemSelectorController extends BaseController previousController = @_elementControllers[i - 1] controller = @_elementControllers[i] - if controller.selected - previousController.selected = true - controller.selected = false + if controller.isSelected + previousController.isSelected = true + controller.isSelected = false @_showElement previousController.$el return - controller = @_elementControllers[@_elementControllers.length - 1] - controller.selected = true + controller = @_elementControllers[0] + controller.isSelected = false + + [..., controller] = @_elementControllers + controller.isSelected = true @_showElement controller.$el _showElement: ($el)-> diff --git a/src/client/site/common/markdown_section/markdown_image_list/markdown_image_list_controller.coffee b/src/client/site/common/markdown_section/markdown_image_list/markdown_image_list_controller.coffee index 81db1a92d..d2468583d 100644 --- a/src/client/site/common/markdown_section/markdown_image_list/markdown_image_list_controller.coffee +++ b/src/client/site/common/markdown_section/markdown_image_list/markdown_image_list_controller.coffee @@ -5,20 +5,24 @@ # All rights reserved. # -BaseController = require '../../../base_controller' -MarkdownImageController = require './markdown_image/markdown_image_controller' -MarkdownImageList = require '../../../../models/site/markdown_image_list' +_ = require "../../../../../underscore" +c = require "../../../../../common/constants" +BaseController = require "../../../base_controller" +MarkdownImageController = require "./markdown_image/markdown_image_controller" +MarkdownImageList = require "../../../../models/site/markdown_image_list" +{Observable} = require("crafting-guide-common").util ######################################################################################################################## module.exports = class MarkdownImageListController extends BaseController + _.extend this, Observable constructor: (options={})-> - options.model ?= new MarkdownImageList {}, {client:options.client} - options.templateName = 'common/markdown_section/markdown_image_list' + options.model ?= new MarkdownImageList client:options.client + options.templateName = "common/markdown_section/markdown_image_list" super options - @imageBase = '' + @imageBase = "" @_valid = null # Public Methods ############################################################################### @@ -33,31 +37,24 @@ module.exports = class MarkdownImageListController extends BaseController @model.reset() # Property Methods ############################################################################# - - getImageBase: -> - return @_imageBase - - setImageBase: (newImageBase)-> - oldImageBase = @_imageBase - return unless oldImageBase isnt newImageBase - - @_imageBase = newImageBase - @trigger c.event.change + ':imageBase', this, oldImageBase, newImageBase - @trigger c.event.change, this - - getMarkdownText: -> - return @model.markdownText - - setMarkdownText: (markdownText)-> - @model.markdownText = markdownText - - getValid: -> - return @_valid - + Object.defineProperties @prototype, - imageBase: {get:@prototype.getImageBase, set:@prototype.setImageBase} - markdownText: {get:@prototype.getMarkdownText, set:@prototype.setMarkdownText} - valid: {get:@prototype.getValid} + + imageBase: + get: -> return @_imageBase + set: (imageBase)-> + @_imageBase = imageBase + @trigger c.event.change + + markdownText: + get: -> return @model.markdownText + set: (markdownText)-> + @model.markdownText = markdownText + @trigger c.event.change + + valid: + get: -> return @_valid + set: -> throw new Error "valid cannot be assigned" # BaseController Overrides ##################################################################### @@ -66,7 +63,7 @@ module.exports = class MarkdownImageListController extends BaseController @_setValid @model.valid onDidRender: -> - @$imageContainer = @$('.image_container') + @$imageContainer = @$(".image_container") super refresh: -> @@ -90,10 +87,6 @@ module.exports = class MarkdownImageListController extends BaseController # Private Methods ############################################################################## - _setValid: (newValid)-> - oldValid = @_valid - return if newValid is oldValid - - @_valid = newValid - @trigger c.event.change + ':valid', this, oldValid, newValid + _setValid: (valid)-> + @_valid = valid @trigger c.event.change diff --git a/src/client/site/common/markdown_section/markdown_section_controller.coffee b/src/client/site/common/markdown_section/markdown_section_controller.coffee index fe758d45b..0f9020ff1 100644 --- a/src/client/site/common/markdown_section/markdown_section_controller.coffee +++ b/src/client/site/common/markdown_section/markdown_section_controller.coffee @@ -5,27 +5,28 @@ # All rights reserved. # -BaseController = require '../../base_controller' -convertMarkdown = require 'marked' -MarkdownImageListController = require './markdown_image_list/markdown_image_list_controller' +BaseController = require "../../base_controller" +convertMarkdown = require "marked" +ItemDisplay = require "../../../models/site/item_display" +MarkdownImageListController = require "./markdown_image_list/markdown_image_list_controller" ######################################################################################################################## module.exports = class MarkdownSectionController extends BaseController @::State = - appologizing: 'applogizing' - confirming: 'confirming' - creating: 'creating' - editing: 'editing' - previewing: 'previewing' - viewing: 'viewing' - waiting: 'waiting' + appologizing: "applogizing" + confirming: "confirming" + creating: "creating" + editing: "editing" + previewing: "previewing" + viewing: "viewing" + waiting: "waiting" constructor: (options={})-> - if not options.modPack? then throw new Error 'options.modPack is required' + if not options.modPack? then throw new Error "options.modPack is required" options.model ?= null - options.templateName = 'common/markdown_section' + options.templateName = "common/markdown_section" @_state = @State.waiting super options @@ -33,9 +34,9 @@ module.exports = class MarkdownSectionController extends BaseController @_confirmationMessage = options.confirmationMessage @_confirmDuration = options.confirmationDuration or 5000 @_enterFeedback = options.enterFeedback or -> # do nothing - @_imageBase = options.imageBase or '' + @_imageBase = options.imageBase or "" @_modPack = options.modPack - @_title = options.title or 'Description' + @_title = options.title or "Description" # @_beginEditing must be a function returning a promise which resolves when all actions necessary prior to an # editing session have been completed (e.g., loading the latest content from a remote server). The promise must @@ -60,7 +61,7 @@ module.exports = class MarkdownSectionController extends BaseController # Event Methods ################################################################################ onCancelClicked: (event)-> - tracker.trackEvent c.tracking.category.markdown, 'cancel' + tracker.trackEvent c.tracking.category.markdown, "cancel" @model = @_originalModel @resetToDefaultState() @@ -71,7 +72,7 @@ module.exports = class MarkdownSectionController extends BaseController onEditClicked: (event)-> return false unless @editable - tracker.trackEvent c.tracking.category.markdown, 'edit' + tracker.trackEvent c.tracking.category.markdown, "edit" @_originalModel = @model @state = @State.waiting @_beginEditing() @@ -85,22 +86,22 @@ module.exports = class MarkdownSectionController extends BaseController return false onQuestionClicked: (event)-> - @_enterFeedback '' + @_enterFeedback "" return false onPreviewClicked: (event)-> - tracker.trackEvent c.tracking.category.markdown, 'preview' + tracker.trackEvent c.tracking.category.markdown, "preview" @_updatePreview() @state = @State.previewing return false onReturnClicked: (event)-> - tracker.trackEvent c.tracking.category.markdown, 'return' + tracker.trackEvent c.tracking.category.markdown, "return" @state = @State.editing return false onSaveClicked: (event)-> - tracker.trackEvent c.tracking.category.markdown, 'save' + tracker.trackEvent c.tracking.category.markdown, "save" @state = @State.waiting @_endEditing() .then => @@ -132,7 +133,7 @@ module.exports = class MarkdownSectionController extends BaseController return unless newImageBase isnt oldImageBase @_imageBase = newImageBase - @trigger c.event.change + ':imageBase', this, oldImageBase, newImageBase + @trigger c.event.change + ":imageBase", this, oldImageBase, newImageBase @trigger c.event.change, this getImageFiles: -> @@ -147,7 +148,7 @@ module.exports = class MarkdownSectionController extends BaseController @_state = newState logger.verbose => "MarkdownSectionController.#{@cid} changed state from #{oldState} to #{newState}" - @trigger c.event.change + ':state', this, oldState, newState + @trigger c.event.change + ":state", this, oldState, newState @tryRefresh() Object.defineProperties @prototype, @@ -159,21 +160,21 @@ module.exports = class MarkdownSectionController extends BaseController # BaseController Overrides ##################################################################### onDidRender: -> - @_imageListController = @addChild MarkdownImageListController, '.view__markdown_image_list', + @_imageListController = @addChild MarkdownImageListController, ".view__markdown_image_list", client: @_client imageBase: @_imageBase - @on c.event.change + ':imageBase', => @_imageListController.model.imageBase = @_imageBase - @listenTo @_imageListController, c.event.change + ':valid', => @tryRefresh() + @on c.event.change + ":imageBase", => @_imageListController.model.imageBase = @_imageBase + @listenTo @_imageListController, c.event.change + ":valid", => @tryRefresh() - @$errorPanel = @$('.error') - @$errorText = @$('.error p') - @$markdownPanel = @$('.markdown') - @$previewButton = @$('.button.preview') - @$questionPanel = @$('.question') - @$saveButton = @$('.button.save') - @$sizer = @$('.sizer') - @$textarea = @$('textarea') - @$title = @$('h2') + @$errorPanel = @$(".error") + @$errorText = @$(".error p") + @$markdownPanel = @$(".markdown") + @$previewButton = @$(".button.preview") + @$questionPanel = @$(".question") + @$saveButton = @$(".button.save") + @$sizer = @$(".sizer") + @$textarea = @$("textarea") + @$title = @$("h2") @resetToDefaultState() @@ -199,14 +200,14 @@ module.exports = class MarkdownSectionController extends BaseController events: -> return _.extend super, - 'click .markdown a': 'routeLinkClick' - 'click .button.cancel': 'onCancelClicked' - 'click .button.edit': 'onEditClicked' - 'click .button.preview': 'onPreviewClicked' - 'click .button.return': 'onReturnClicked' - 'click .button.save': 'onSaveClicked' - 'click .question a': 'onQuestionClicked' - 'input textarea': 'onTextChanged' + "click .markdown a": "routeLinkClick" + "click .button.cancel": "onCancelClicked" + "click .button.edit": "onEditClicked" + "click .button.preview": "onPreviewClicked" + "click .button.return": "onReturnClicked" + "click .button.save": "onSaveClicked" + "click .question a": "onQuestionClicked" + "input textarea": "onTextChanged" # Private Methods ############################################################################## @@ -219,22 +220,22 @@ module.exports = class MarkdownSectionController extends BaseController result = match item = @_modPack.findItemByName name if item? - display = @_modPack.findItemDisplay item.slug - result = "[#{name}](#{display.itemUrl})" + display = new ItemDisplay item + result = "[#{name}](#{display.url})" return result _updateButtonStates: -> for $button in [ @$previewButton, @$saveButton ] if @_imageListController.valid - $button.prop 'disabled', false + $button.prop "disabled", false else - $button.prop 'disabled', true + $button.prop "disabled", true _updateSizer: -> text = @model if @model? - text = text.replace /\n/g, '
' + text = text.replace /\n/g, "
" @$sizer.html text @@ -254,22 +255,22 @@ module.exports = class MarkdownSectionController extends BaseController logger.verbose => "Updating markdown section visibility for state: #{@state}" elements = - appologizingPanel: @$('.appologizing') - cancelButton: @$('.button.cancel') - confirmingPanel: @$('.confirming') - creatingPanel: @$('.creating') - editButton: @$('.button.edit') - editorPanel: @$('.editor') - footerPanel: @$('.footer') - imageList: @$('.view__markdown_image_list') + appologizingPanel: @$(".appologizing") + cancelButton: @$(".button.cancel") + confirmingPanel: @$(".confirming") + creatingPanel: @$(".creating") + editButton: @$(".button.edit") + editorPanel: @$(".editor") + footerPanel: @$(".footer") + imageList: @$(".view__markdown_image_list") markdownPanel: @$markdownPanel previewButton: @$previewButton - returnButton: @$('.button.return') + returnButton: @$(".button.return") saveButton: @$saveButton - waitingPanel: @$('.waiting') + waitingPanel: @$(".waiting") visible = {} - errorText = '' + errorText = "" if @state is @State.appologizing visible = appologizingPanel:true diff --git a/src/client/site/common/mod_version_selector/mod_version_selector.jade b/src/client/site/common/mod_version_selector/mod_version_selector.jade index af77d0254..158b81d48 100644 --- a/src/client/site/common/mod_version_selector/mod_version_selector.jade +++ b/src/client/site/common/mod_version_selector/mod_version_selector.jade @@ -2,8 +2,5 @@ .toggle span.checkbox span.label I have this mod in my modpack - .version - span Version: - select .warning. PLEASE NOTE: Crafting plans, search, and other features will ignore items and recipes from this mod. diff --git a/src/client/site/common/mod_version_selector/mod_version_selector_controller.coffee b/src/client/site/common/mod_version_selector/mod_version_selector_controller.coffee index 125a8debd..b50805a05 100644 --- a/src/client/site/common/mod_version_selector/mod_version_selector_controller.coffee +++ b/src/client/site/common/mod_version_selector/mod_version_selector_controller.coffee @@ -5,97 +5,59 @@ # All rights reserved. # -BaseController = require '../../base_controller' -{Mod} = require('crafting-guide-common').deprecated.game +BaseController = require "../../base_controller" +{Mod} = require("crafting-guide-common").models ######################################################################################################################## module.exports = class ModVersionSelectorController extends BaseController constructor: (options={})-> - if not options.model? then throw new Error 'options.model is required' - options.templateName = 'common/mod_version_selector' + if options.model?.constructor isnt Mod then throw new Error "options.model must be a Mod" + options.templateName = "common/mod_version_selector" super options # Event Methods ################################################################################ onToggleEnabled: -> - if @model.activeVersion is Mod.Version.None - tracker.trackEvent c.tracking.category.modPack, 'toggle-on', @model.slug - @model.activeVersion = Mod.Version.Latest + if not @model.isEnabled + tracker.trackEvent c.tracking.category.modPack, "toggle-on", @model.id + @model.isEnabled = true else - tracker.trackEvent c.tracking.category.modPack, 'toggle-off', @model.slug - @model.activeVersion = Mod.Version.None + tracker.trackEvent c.tracking.category.modPack, "toggle-off", @model.id + @model.isEnabled = false return false - onVersionChanged: -> - @model.activeVersion = @$versionSelector.val() - tracker.trackEvent c.tracking.category.modPack, 'select-version', "#{@model.slug}@#{@model.activeVersion}" - return false - - # Property Methods ############################################################################# - - Object.defineProperties @prototype, - - effectiveModVersion: - get: -> - modVersion = @model.activeModVersion - modVersion ?= @model.getModVersion Mod.Version.Latest - modVersion.fetch() if modVersion? - return modVersion - # BaseController Overrides ##################################################################### onDidRender: -> - @$toggleSection = @$('.toggle') - @$versionSection = @$('.version') - @$versionSelector = @$('.version select') - @$warning = @$('.warning') + @$toggleSection = @$(".toggle") + @$warning = @$(".warning") super refresh: -> + console.log "refreshing" @_refreshEnabled() - @_refreshVersionSelector() super # Backbone.View Overrides ###################################################################### events: -> return _.extend super, - 'change .version select': 'onVersionChanged' - 'click .toggle': 'onToggleEnabled' + "click .toggle": "onToggleEnabled" # Private Methods ############################################################################## _refreshEnabled: -> - if @model.slug in c.requiredMods + if @model.id in c.requiredMods @hide @$toggleSection else @show @$toggleSection - if @model.activeVersion is Mod.Version.None - @$toggleSection.removeClass 'enabled' + if not @model.isEnabled + @$toggleSection.removeClass "enabled" @show @$warning else - @$toggleSection.addClass 'enabled' + @$toggleSection.addClass "enabled" @hide @$warning - - _refreshVersionSelector: -> - modVersions = @model.modVersions - - if (@model.activeVersion is Mod.Version.None) or modVersions.length < 2 - @hide @$versionSection - else - @show @$versionSection - - selectedModVersion = @effectiveModVersion - - @$versionSelector.empty() - - for modVersion in @model.modVersions - $option = $("") - if modVersion is selectedModVersion - $option.attr 'selected', 'true' - @$versionSelector.append $option - @$versionSelector.css display:'' diff --git a/src/client/site/common/recipe/crafting_table/crafting_table.jade b/src/client/site/common/recipe/crafting_table/crafting_table.jade new file mode 100644 index 000000000..16d805b81 --- /dev/null +++ b/src/client/site/common/recipe/crafting_table/crafting_table.jade @@ -0,0 +1,19 @@ +//- +//- Crafting Guide - crafting_table.jade +//- +//- Copyright (c) 2015-2017 by Redwood Labs +//- All rights reserved. +//- + +.view__crafting_table + .input_inventory + .view__inventory + .grid_block + .input_grid + .view__crafting_grid + .tool + .output_slot + .view__slot + .multiplier + .output_inventory + .view__inventory diff --git a/src/client/site/common/recipe/crafting_table/crafting_table.scss b/src/client/site/common/recipe/crafting_table/crafting_table.scss new file mode 100644 index 000000000..3f8d5d173 --- /dev/null +++ b/src/client/site/common/recipe/crafting_table/crafting_table.scss @@ -0,0 +1,103 @@ +// +// Crafting Guide - crafting_table.scss +// +// Copyright © 2014-2017 by Redwood Labs +// All rights reserved. +// + +.view__crafting_table { + display: flex; + + .input_inventory { + flex: 1 1 100%; + + display: flex; + margin-right: $size-margin-large; + } + + .grid_block { + flex: 1 1 100%; + + display: flex; + align-items: center; + justify-content: center; + + .input_grid { + flex: 0 0 auto; + + align-items : center; + display : flex; + flex-direction : column; + + .view__crafting_grid { + flex: 0 0 auto; + } + + .tool { + margin-top : $size-margin-small; + + font-family : $font-family-text; + font-size : $font-size-medium; + } + } + + .output_slot { + flex: 0 0 auto; + margin-left: $size-margin-large; + + display : flex; + flex-direction : column; + justify-content : center; + align-items : center; + + .view__slot { + border: $size-border-medium solid $color-gray-medium; + } + + .multiplier { + font-family : $font-family-header; + font-size : $font-size-large; + margin-top : $size-margin-medium; + } + } + } + + .output_inventory { + flex: 1 1 100%; + display: flex; + margin-left: $size-margin-large; + } +} + +@include screen-size(mobile) { + .view__crafting_table { + border-bottom: 1px solid $color-gray-light; + padding-bottom: $size-margin-medium; + + flex-direction: column; + align-items: center; + + .input_inventory { + flex: 0 0 auto; + margin-bottom: $size-margin-small; + } + + .grid_block { + flex: 0 0 auto; + + .tool { + margin-bottom: $size-margin-medium; + } + } + + .output_inventory { + flex: 0 0 auto; + margin-left: 0; + } + + .view__inventory { + margin-left: $size-margin-medium; + margin-right: $size-margin-medium; + } + } +} diff --git a/src/client/site/common/recipe/crafting_table/crafting_table_controller.coffee b/src/client/site/common/recipe/crafting_table/crafting_table_controller.coffee new file mode 100644 index 000000000..dc1d59b3a --- /dev/null +++ b/src/client/site/common/recipe/crafting_table/crafting_table_controller.coffee @@ -0,0 +1,95 @@ +# +# Crafting Guide - crafting_table_controller.coffee +# +# Copyright © 2014-2017 by Redwood Labs +# All rights reserved. +# + +BaseController = require "../../../base_controller" +CraftingGridController = require "../../crafting_grid/crafting_grid_controller" +InventoryController = require "../../inventory/inventory_controller" +ItemDisplay = require "../../../../models/site/item_display" +RecipeDisplay = require "../../../../models/site/recipe_display" +SlotController = require "../../slot/slot_controller" +{StringBuilder} = require("crafting-guide-common").util + +######################################################################################################################## + +module.exports = class CraftingTableController extends BaseController + + constructor: (options={})-> + if not options.imageLoader? then throw new Error "options.imageLoader is required" + if not options.modPack? then throw new Error "options.modPack is required" + if not options.router? then throw new Error "options.router is required" + options.templateName = "common/recipe/crafting_table" + super options + + @_imageLoader = options.imageLoader + @_modPack = options.modPack + @_router = options.router + + # BaseController Overrides ##################################################################### + + onDidRender: -> + options = editable:false, modPack:@_modPack, imageLoader:@_imageLoader, router:@_router + + @_inputController = @addChild InventoryController, ".input_inventory .view__inventory", options + @_gridController = @addChild CraftingGridController, ".input_grid .view__crafting_grid", options + @_outputSlotController = @addChild SlotController, ".output_slot .view__slot", options + @_outputController = @addChild InventoryController, ".output_inventory .view__inventory", options + + @$inputInventorySection = @$(".input_inventory") + @$multiplier = @$(".multiplier") + @$outputImg = @$(".output.slot img") + @$outputInventorySection = @$(".output_inventory") + @$outputLink = @$(".output.slot a") + @$outputQuantity = @$(".quantity") + @$outputSlotSection = @$(".output_slot") + @$toolContainer = @$(".tool") + super + + onWillChangeModel: (oldModel, newModel)-> + if not newModel? then throw new Error "model is required" + if newModel.constructor isnt RecipeDisplay then throw new Error "model must be a RecipeDisplay" + return super oldModel, newModel + + refresh: -> + @_inputController.model = @model?.getInventory() + @_gridController.model = @model?.recipe + @_outputSlotController.model = @model?.recipe.output + @_outputController.model = @model?.getOutputInventory() + + @_refreshMultiplier() + @_refreshSections() + @_refreshTools() + super + + # Backbone.View Methods ######################################################################## + + events: -> + return _.extend super, + "click a": "routeLinkClick" + + # Private Methods ############################################################################## + + _refreshMultiplier: -> + if @model.multiplier > 1 + @$multiplier.html "x#{@model.multiplier}" + else + @$multiplier.html "" + + _refreshSections: -> + @$inputInventorySection.css display:(if @model.showInputInventory then "" else "none") + @$outputInventorySection.css display:(if @model.showOutputInventory then "" else "none") + @$outputSlotSection.css display:(if @model.showOutputSlot then "" else "none") + + _refreshTools: -> + @$toolContainer.empty() + return unless @model? + + toolLinks = [] + for itemId, item of @model.tools + display = new ItemDisplay item + toolLinks.push "#{display.name}" + + @$toolContainer.html toolLinks.join ", " diff --git a/src/client/site/item_page/multiblock_viewer/multiblock/multiblock.jade b/src/client/site/common/recipe/multiblock_viewer/multiblock/multiblock.jade similarity index 100% rename from src/client/site/item_page/multiblock_viewer/multiblock/multiblock.jade rename to src/client/site/common/recipe/multiblock_viewer/multiblock/multiblock.jade diff --git a/src/client/site/item_page/multiblock_viewer/multiblock/multiblock.scss b/src/client/site/common/recipe/multiblock_viewer/multiblock/multiblock.scss similarity index 100% rename from src/client/site/item_page/multiblock_viewer/multiblock/multiblock.scss rename to src/client/site/common/recipe/multiblock_viewer/multiblock/multiblock.scss diff --git a/src/client/site/item_page/multiblock_viewer/multiblock/multiblock_controller.coffee b/src/client/site/common/recipe/multiblock_viewer/multiblock/multiblock_controller.coffee similarity index 79% rename from src/client/site/item_page/multiblock_viewer/multiblock/multiblock_controller.coffee rename to src/client/site/common/recipe/multiblock_viewer/multiblock/multiblock_controller.coffee index 914e230fb..678cec969 100644 --- a/src/client/site/item_page/multiblock_viewer/multiblock/multiblock_controller.coffee +++ b/src/client/site/common/recipe/multiblock_viewer/multiblock/multiblock_controller.coffee @@ -1,11 +1,12 @@ -### -Crafting Guide - multiblock_controller.coffee +# +# Crafting Guide - multiblock_controller.coffee +# +# Copyright (c) 2014-2017 by Redwood Labs +# All rights reserved. +# -Copyright (c) 2014-2015 by Redwood Labs -All rights reserved. -### - -BaseController = require '../../../base_controller' +BaseController = require "../../../../base_controller" +ItemDisplay = require "../../../../../models/site/item_display" ######################################################################################################################## @@ -25,9 +26,9 @@ module.exports = class MultiblockController extends BaseController @::MAX_DROP_DELAY = 250 # ms constructor: (options={})-> - if not options.imageLoader? then throw new Error 'options.imageLoader is required' - if not options.modPack? then throw new Error 'options.modPack is required' - options.templateName = 'item_page/multiblock_viewer/multiblock' + if not options.imageLoader? then throw new Error "options.imageLoader is required" + if not options.modPack? then throw new Error "options.modPack is required" + options.templateName = "common/recipe/multiblock_viewer/multiblock" super options @_currentLayer = 0 @@ -63,11 +64,11 @@ module.exports = class MultiblockController extends BaseController # BaseController Overrides ##################################################################### onDidRender: -> - @$outline = @$('.outline') + @$outline = @$(".outline") super refresh: -> - @$el.css 'height':@_computeMinHeight(), 'width':@_computeMinWidth() + @$el.css "height":@_computeMinHeight(), "width":@_computeMinWidth() @_refreshBlockCache() @_refreshAllBlocks() @@ -76,7 +77,7 @@ module.exports = class MultiblockController extends BaseController # Private Methods ############################################################################## _computePosition: (x, y, z, options={})-> - if not @model? then return left:0, top:-@IMAGE_SIZE, 'z-index':0, opacity:0.0 + if not @model? then return left:0, top:-@IMAGE_SIZE, "z-index":0, opacity:0.0 options.hideUpperLayers ?= false pxWidth = @$el.width() @@ -93,7 +94,7 @@ module.exports = class MultiblockController extends BaseController zindex = ((@model.width - x) + (@model.depth - z) + ((@model.width * @model.depth) * y)) * 2 - return left:left, top:top, 'z-index':zindex, opacity:opacity + return left:left, top:top, "z-index":zindex, opacity:opacity _computeMinHeight: -> return 0 unless @model? @@ -130,23 +131,23 @@ module.exports = class MultiblockController extends BaseController for z in [0...@model.depth] @_blockCache[x][y][z] ?= null - for el in @$('.block') + for el in @$(".block") $el = $(el) - @_blockCache[$el.data('x')][$el.data('y')][$el.data('z')] = $el + @_blockCache[$el.data("x")][$el.data("y")][$el.data("z")] = $el _refreshBlock: (x, y, z)-> return unless @model? - stack = @model.getStackAt x, y, z + stack = @model.getInputAt x, y, z $block = @_blockCache[x][y][z] position = @_computePosition x, y, z, hideUpperLayers:true move = false if stack? - itemDisplay = @_modPack.findItemDisplay stack.itemSlug + itemDisplay = new ItemDisplay stack.item if not $block? - $block = $("#{itemDisplay.itemName}") + $block = $("\"#{itemDisplay.itemName}\"") $block.css position, top:-@IMAGE_SIZE, opacity:0.0 @_registerHoverHandlers $block, y, itemDisplay @_imageLoader.load itemDisplay.iconUrl, $block @@ -154,10 +155,10 @@ module.exports = class MultiblockController extends BaseController @$el.append $block move = true else - $block.attr 'src', itemDisplay.iconUrl + $block.attr "src", itemDisplay.iconUrl move = true else if $block? - $block.attr 'src', '' + $block.attr "src", "" move = true if move then _.delay (-> $block.css position), @_randomDropDelay() @@ -174,10 +175,10 @@ module.exports = class MultiblockController extends BaseController _registerHoverHandlers: ($el, y, itemDisplay)-> startHovering = => return unless y is @_currentLayer - zIndex = parseInt($el.css('z-index')) + 1 + zIndex = parseInt($el.css("z-index")) + 1 zIndex = if _.isNaN(zIndex) then 0 else zIndex - @$outline.css opacity:1.0, top:$el.css('top'), left:$el.css('left'), 'z-index':zIndex + @$outline.css opacity:1.0, top:$el.css("top"), left:$el.css("left"), "z-index":zIndex @_onHovering itemDisplay if @_hoverTimer? then clearTimeout @_hoverTimer diff --git a/src/client/site/item_page/multiblock_viewer/multiblock_viewer.jade b/src/client/site/common/recipe/multiblock_viewer/multiblock_viewer.jade similarity index 100% rename from src/client/site/item_page/multiblock_viewer/multiblock_viewer.jade rename to src/client/site/common/recipe/multiblock_viewer/multiblock_viewer.jade diff --git a/src/client/site/item_page/multiblock_viewer/multiblock_viewer.scss b/src/client/site/common/recipe/multiblock_viewer/multiblock_viewer.scss similarity index 100% rename from src/client/site/item_page/multiblock_viewer/multiblock_viewer.scss rename to src/client/site/common/recipe/multiblock_viewer/multiblock_viewer.scss diff --git a/src/client/site/common/recipe/multiblock_viewer/multiblock_viewer_controller.coffee b/src/client/site/common/recipe/multiblock_viewer/multiblock_viewer_controller.coffee new file mode 100644 index 000000000..2a6e40c5f --- /dev/null +++ b/src/client/site/common/recipe/multiblock_viewer/multiblock_viewer_controller.coffee @@ -0,0 +1,96 @@ +# +# Crafting Guide - multiblock_viewer_controller.coffee +# +# Copyright © 2014-2017 by Redwood Labs +# All rights reserved. +# + +BaseController = require "../../../base_controller" +InventoryController = require "../../inventory/inventory_controller" +MultiblockController = require "./multiblock/multiblock_controller" +RecipeDisplay = require "../../../../models/site/recipe_display" + +######################################################################################################################## + +module.exports = class MultiblockViewerController extends BaseController + + constructor: (options={})-> + if not options.imageLoader? then throw new Error "options.imageLoader is required" + if not options.modPack? then throw new Error "options.modPack is required" + if not options.router? then throw new Error "options.router is required" + options.templateName = "common/recipe/multiblock_viewer" + super options + + @_imageLoader = options.imageLoader + @_modPack = options.modPack + @_hoverTimer = null + @_router = options.router + + # Event Methods ################################################################################ + + onBackClicked: -> + return if @$backButton.hasClass "disabled" + tracker.trackEvent c.tracking.category.multiblock, "back" + @multiblockController.goBackLayer() + @refresh() + + onNextClicked: -> + return if @$nextButton.hasClass "disabled" + tracker.trackEvent c.tracking.category.multiblock, "next" + @multiblockController.goNextLayer() + @refresh() + + onBlockHovered: (itemDisplay)-> + if itemDisplay? + @$captionText.html itemDisplay.name + @_imageLoader.load itemDisplay.iconUrl, @$captionIcon + else + @$captionText.html " " + @$captionIcon.attr "src", "/images/empty.png" + + # BaseController Overrides ##################################################################### + + onDidRender: -> + baseOptions = imageLoader:@_imageLoader, modPack:@_modPack, router:@_router + + options = _.extend {editable:false}, baseOptions + @completeInventoryController = @addChild InventoryController, ".view__inventory.complete", options + @layerInventoryController = @addChild InventoryController, ".view__inventory.layer", options + + options = _.extend {onHovering:(itemDisplay)=> @onBlockHovered(itemDisplay)}, baseOptions + @multiblockController = @addChild MultiblockController, ".view__multiblock", options + + @$backButton = @$(".button.back") + @$nextButton = @$(".button.next") + @$captionText = @$(".caption p") + @$captionIcon = @$(".caption img") + super + + onWillChangeModel: (oldModel, newModel)-> + if not newModel? then throw new Error "model is required" + if newModel.constructor isnt RecipeDisplay then throw new Error "model must be a RecipeDisplay" + return super oldModel, newModel + + refresh: -> + @completeInventoryController.model = @model.getInventory() + @layerInventoryController.model = @model.getInventory @multiblockController.currentLayer + @multiblockController.model = @model + + if @multiblockController.hasBackLayer() + @$backButton.removeClass "disabled" + else + @$backButton.addClass "disabled" + + if @multiblockController.hasNextLayer() + @$nextButton.removeClass "disabled" + else + @$nextButton.addClass "disabled" + + super + + # Backbone.View Overrides ###################################################################### + + events: -> + _.extend super, + "click .button.back": "onBackClicked" + "click .button.next": "onNextClicked" diff --git a/src/client/site/common/recipe/recipe.jade b/src/client/site/common/recipe/recipe.jade index 0acf46b76..95ae08bb5 100644 --- a/src/client/site/common/recipe/recipe.jade +++ b/src/client/site/common/recipe/recipe.jade @@ -1,14 +1,8 @@ //- //- Crafting Guide - recipe.jade //- -//- Copyright (c) 2015 by Redwood Labs +//- Copyright (c) 2014-2017 by Redwood Labs //- All rights reserved. //- .view__recipe - .input - .view__crafting_grid - .tool - .output - .view__slot - .multiplier \ No newline at end of file diff --git a/src/client/site/common/recipe/recipe.scss b/src/client/site/common/recipe/recipe.scss index 5d9bf6d57..1c9244d26 100644 --- a/src/client/site/common/recipe/recipe.scss +++ b/src/client/site/common/recipe/recipe.scss @@ -46,4 +46,4 @@ margin-top : $size-margin-medium; } } -} \ No newline at end of file +} diff --git a/src/client/site/common/recipe/recipe_controller.coffee b/src/client/site/common/recipe/recipe_controller.coffee index 9089af172..f625427eb 100644 --- a/src/client/site/common/recipe/recipe_controller.coffee +++ b/src/client/site/common/recipe/recipe_controller.coffee @@ -5,93 +5,57 @@ # All rights reserved. # -BaseController = require '../../base_controller' -CraftingGridController = require '../crafting_grid/crafting_grid_controller' -SlotController = require '../slot/slot_controller' -{StringBuilder} = require('crafting-guide-common').util +BaseController = require "../../base_controller" +CraftingTableController = require "./crafting_table/crafting_table_controller" +MultiblockViewerController = require "./multiblock_viewer/multiblock_viewer_controller" +RecipeDisplay = require "../../../models/site/recipe_display" ######################################################################################################################## module.exports = class RecipeController extends BaseController constructor: (options={})-> - if not options.imageLoader? then throw new Error 'options.imageLoader is required' - if not options.modPack? then throw new Error 'options.modPack is required' - if not options.router? then throw new Error 'options.router is required' - options.templateName = 'common/recipe' + if not options.imageLoader? then throw new Error "options.imageLoader is required" + if not options.modPack? then throw new Error "options.modPack is required" + if not options.router? then throw new Error "options.router is required" + options.templateName = "common/recipe" super options @_imageLoader = options.imageLoader @_modPack = options.modPack - @_multiplier = options.multiplier @_router = options.router # BaseController Overrides ##################################################################### - onDidRender: -> - @_gridController = @addChild CraftingGridController, '.view__crafting_grid', - modPack: @_modPack - imageLoader: @_imageLoader - router: @_router - - @_outputSlotController = @addChild SlotController, '.output .view__slot', - imageLoader: @_imageLoader - modPack: @_modPack - router: @_router - - @$multiplier = @$('.multiplier') - @$outputImg = @$('.output img') - @$outputLink = @$('.output a') - @$outputQuantity = @$('.quantity') - @$toolContainer = @$('.tool') - super + onWillChangeModel: (oldModel, newModel)-> + if not newModel? then throw new Error "model is required" + if newModel.constructor isnt RecipeDisplay then throw new Error "model must be a RecipeDisplay" + if @_typeController? then @_typeController.model = newModel + return super oldModel, newModel refresh: -> - @_gridController.model = @model - @_outputSlotController.model = @model?.output?[0] - - @_refreshMultiplier() - @_refreshTools() + return unless @model? + @_refreshRecipeType() super - # Property Methods ############################################################################# - - Object.defineProperties @prototype, - multiplier: - get: -> - @_multiplier ?= 1 - return @_multiplier - - set: (newMultiplier)-> - oldMultiplier = @_multiplier - return if newMultiplier is oldMultiplier - - @_multiplier = newMultiplier - @_refreshMultiplier() - - @trigger Event.change + ':multiplier', this, oldMultiplier, newMultiplier - @trigger Event.change, this - - # Backbone.View Methods ######################################################################## - - events: -> - return _.extend super, - 'click a': 'routeLinkClick' - # Private Methods ############################################################################## - _refreshMultiplier: -> - if @multiplier > 1 - @$multiplier.html "x#{@multiplier}" - else - @$multiplier.html '' + _lookupControllerFor: (recipeType)-> + if recipeType is RecipeDisplay::RECIPE_TYPE.CRAFTING_TABLE then return CraftingTableController + if recipeType is RecipeDisplay::RECIPE_TYPE.MULTIBLOCK then return MultiblockViewerController - _refreshTools: -> - @$toolContainer.empty() - return unless @model? + _refreshRecipeType: -> + return if @_renderedRecipeType is @model.type + @_renderedRecipeType = @model.type - builder = new StringBuilder - builder.loop @model.tools, delimiter:', ', onEach:(b, stack)=> - display = @_modPack.findItemDisplay stack.itemSlug - b.push "#{display.itemName}" - @$toolContainer.html builder.toString() + if @_typeController? + @_typeController.remove() + @_typeController = null + + return unless @_renderedRecipeType? + + TypeController = @_lookupControllerFor @model.type + + @$el.append "
" + options = imageLoader:@_imageLoader, model:@model, modPack:@_modPack, router:@_router + @_typeController = @addChild TypeController, ".view__#{@model.type}", options diff --git a/src/client/site/common/slot/slot_controller.coffee b/src/client/site/common/slot/slot_controller.coffee index ecde0b23d..a5f710f25 100644 --- a/src/client/site/common/slot/slot_controller.coffee +++ b/src/client/site/common/slot/slot_controller.coffee @@ -5,18 +5,19 @@ # All rights reserved. # -BaseController = require '../../base_controller' +BaseController = require "../../base_controller" +ItemDisplay = require "../../../models/site/item_display" +{Stack} = require("crafting-guide-common").models ######################################################################################################################## module.exports = class SlotController extends BaseController constructor: (options={})-> - if not options.imageLoader? then throw new Error 'options.imageLoader is required' - if not options.modPack? then throw new Error 'options.modPack is required' - if not options.router? then throw new Error 'options.router is required' - # options.model should be a Stack - options.templateName = 'common/slot' + if not options.imageLoader? then throw new Error "options.imageLoader is required" + if not options.modPack? then throw new Error "options.modPack is required" + if not options.router? then throw new Error "options.router is required" + options.templateName = "common/slot" options.useAnimations = false super options @@ -27,27 +28,31 @@ module.exports = class SlotController extends BaseController # BaseController Overrides ##################################################################### onDidRender: -> - @$link = @$('a') - @$image = @$('img') - @$quantity = @$('.quantity') + @$link = @$("a") + @$image = @$("img") + @$quantity = @$(".quantity") + super + + onWillChangeModel: (oldModel, newModel)-> + if newModel? and (newModel.constructor isnt Stack) then throw new Error "newModel must be a Stack" super refresh: -> if @model? - display = @_modPack.findItemDisplay @model.itemSlug - @$link.attr 'href', display.itemUrl + display = new ItemDisplay @model.item + @$link.attr "href", display.url @_imageLoader.load display.iconUrl, @$image if @model.quantity > 1 @$quantity.html @model.quantity else - @$quantity.html '' + @$quantity.html "" else - @$link.removeAttr 'href' - @$quantity.html '' + @$link.removeAttr "href" + @$quantity.html "" - @$image.attr 'src', '/images/empty.png' + @$image.attr "src", "/images/empty.png" super @@ -55,4 +60,4 @@ module.exports = class SlotController extends BaseController events: -> return _.extend super, - 'click a': 'routeLinkClick' + "click a": "routeLinkClick" diff --git a/src/client/site/common/stack/stack_controller.coffee b/src/client/site/common/stack/stack_controller.coffee index 4e939ec36..4026c6ede 100644 --- a/src/client/site/common/stack/stack_controller.coffee +++ b/src/client/site/common/stack/stack_controller.coffee @@ -6,6 +6,7 @@ # BaseController = require '../../base_controller' +ItemDisplay = require "../../../models/site/item_display" ######################################################################################################################## @@ -38,8 +39,6 @@ module.exports = class StackController extends BaseController @_shouldEnableButton = options.shouldEnableButton ?= (model, button)-> true @_trackingContext = options.trackingContext ?= null - @_modPack.on c.event.change, => @tryRefresh() - # Event Methods ################################################################################ onFirstButtonClicked: (event)-> @@ -71,7 +70,7 @@ module.exports = class StackController extends BaseController @trigger c.event.change + ':quantity', this, oldQuantity, newQuantity @trigger c.event.change, this - tracker.trackEvent @_trackingContext, 'update-quantity', @model.itemSlug, @model.quantity + tracker.trackEvent @_trackingContext, 'update-quantity', @model.item.id, @model.quantity onQuantityFieldChanged: -> return unless @_editable @@ -119,11 +118,11 @@ module.exports = class StackController extends BaseController refresh: -> if not @model? then throw new Error "must have a model to render" - display = @_modPack.findItemDisplay @model.itemSlug + display = new ItemDisplay @model.item @_imageLoader.load display.iconUrl, @$image - @$nameLink.html display.itemName - @$nameLink.attr 'href', display.itemUrl + @$nameLink.html display.name + @$nameLink.attr 'href', display.url quantityText = if @model.quantity > 10000 then "#{@model.quantity / 1000}k" else "#{@model.quantity}" @$quantityField.val quantityText diff --git a/src/client/site/common/video/video_controller.coffee b/src/client/site/common/video/video_controller.coffee index f4f72bdab..4d675fa12 100644 --- a/src/client/site/common/video/video_controller.coffee +++ b/src/client/site/common/video/video_controller.coffee @@ -5,30 +5,31 @@ # All rights reserved. # -BaseController = require '../../base_controller' +BaseController = require "../../base_controller" ######################################################################################################################## module.exports = class VideoController extends BaseController constructor: (options={})-> - if not options.model? then throw new Error 'options.model is required' - options.templateName = 'common/video' + if not options.model? then throw new Error "options.model is required" + options.templateName = "common/video" super options # BaseController Overrides ##################################################################### onDidRender: -> - @$iframe = @$('iframe') - @$caption = @$('.caption p') + @$iframe = @$("iframe") + @$caption = @$(".caption p") super refresh: -> @$caption.html @model.name - @$iframe.attr 'src', @_createYouTubeUrl() + @$iframe.attr "src", @_createYouTubeUrl() super # Private ###################################################################################### _createYouTubeUrl: -> return "http://www.youtube.com/embed/#{@model.youTubeId}?modestbranding=1&autohide=1&showinfo=0" + diff --git a/src/client/site/craft_page/craft_page.jade b/src/client/site/craft_page/craft_page.jade index bcafb4bcf..32d51aec6 100644 --- a/src/client/site/craft_page/craft_page.jade +++ b/src/client/site/craft_page/craft_page.jade @@ -53,4 +53,4 @@ h2 Steps .panel - section.view__craftsman_working + section.view__working_panel diff --git a/src/client/site/craft_page/craft_page_controller.coffee b/src/client/site/craft_page/craft_page_controller.coffee index 48467c18c..d292a51d5 100644 --- a/src/client/site/craft_page/craft_page_controller.coffee +++ b/src/client/site/craft_page/craft_page_controller.coffee @@ -5,28 +5,28 @@ # All rights reserved. # -BaseController = require '../base_controller' -CraftPage = require '../../models/site/craft_page' -{Craftsman} = require('crafting-guide-common').deprecated.crafting -CraftsmanWorkingController = require './craftsman_working/craftsman_working_controller' -InventoryController = require '../common/inventory/inventory_controller' -PageController = require '../page_controller' -{SimpleInventory} = require('crafting-guide-common').deprecated.crafting -StepController = require './step/step_controller' +CraftPage = require "../../models/site/craft_page" +WorkingPanelController = require "./working_panel/working_panel_controller" +{Inventory} = require("crafting-guide-common").models +InventoryController = require "../common/inventory/inventory_controller" +{Observable} = require("crafting-guide-common").util +PageController = require "../page_controller" +StepController = require "./step/step_controller" ######################################################################################################################## module.exports = class CraftPageController extends PageController @::SCROLL_BUFFER = 8 # px + @::STEP_RENDER_DELAY = 25 # ms constructor: (options={})-> - if not options.imageLoader? then throw new Error 'options.imageLoader is required' - if not options.modPack? then throw new Error 'options.modPack is required' - if not options.router? then throw new Error 'options.router is required' - if not options.storage? then throw new Error 'options.storage is required' + if not options.imageLoader? then throw new Error "options.imageLoader is required" + if not options.modPack? then throw new Error "options.modPack is required" + if not options.router? then throw new Error "options.router is required" + if not options.storage? then throw new Error "options.storage is required" - options.model ?= new CraftPage modPack:options.modPack + options.model ?= new CraftPage modPack:options.modPack, params:options.params options.templateName = 'craft_page' super options @@ -35,41 +35,44 @@ module.exports = class CraftPageController extends PageController @_router = options.router @_storage = options.storage + @model.have.on Observable::ANY, this, "onHaveInventoryChanged" + @model.want.on Observable::ANY, this, "onWantInventoryChanged" + # Event Methods ################################################################################ onHaveInventoryChanged: -> - @_storage.store 'crafting-plan:have', @model.craftsman.have.unparse() + @_storage.store 'crafting-plan:have', @model.have.toUrlString() - onMoveNeedToHave: (itemSlug)-> - quantity = @_needInventoryController.model.quantityOf itemSlug - @model.craftsman.have.add itemSlug, quantity + onMoveNeedToHave: (item)-> + quantity = @_needInventoryController.model.getQuantity item + @model.have.add item, quantity - onRemoveFromHaveInventory: (itemSlug)-> - @model.craftsman.have.remove itemSlug + onRemoveFromHave: (item)-> + @model.have.remove item - onRemoveFromWant: (itemSlug)-> - @model.craftsman.want.remove itemSlug - @onWantInventoryChanged() + onRemoveFromWant: (item)-> + @model.want.remove item onSampleClicked: (event)-> $el = $(event.target) while $el.length > 0 - inventoryText = $el.attr 'data-slug' + inventoryText = $el.attr "data-slug" break if inventoryText $el = $el.parent() if inventoryText? - tracker.trackEvent c.tracking.category.craft, 'add-sample', inventoryText - sampleInventory = new SimpleInventory - sampleInventory.parse inventoryText - @model.craftsman.want.addInventory sampleInventory - @_scrollTo @$workingSection - @onWantInventoryChanged() + try + tracker.trackEvent c.tracking.category.craft, "add-sample", inventoryText + sampleInventory = Inventory.fromUrlString inventoryText, @_modPack + @model.want.merge sampleInventory + @_scrollTo @$workingSection + catch e + logger.error e return false onWantInventoryChanged: -> - text = @model.craftsman.want.unparse() + text = @model.want.toUrlString() url = c.url.crafting inventoryText:text @router.navigate url @@ -79,7 +82,7 @@ module.exports = class CraftPageController extends PageController return c.text.craftDescription() getTitle: -> - description = @model.craftsman.want.toDescription() + description = @model.want.toDescription() return null unless description? return "Crafting Plan for #{description}" @@ -91,21 +94,19 @@ module.exports = class CraftPageController extends PageController imageLoader: @_imageLoader isAcceptable: (item)=> item.isCraftable modPack: @_modPack - model: @model.craftsman.want + model: @model.want router: @_router trackingContext: c.tracking.category.craftWant - @_wantInventoryController.on c.event.button.first, (c, s)=> @onRemoveFromWant(s) - @_wantInventoryController.on c.event.change, (c)=> @onWantInventoryChanged() + @_wantInventoryController.on c.event.button.first, (controller, item)=> @onRemoveFromWant item @_haveInventoryController = @addChild InventoryController, '.have .view__inventory', firstButtonType: 'down' imageLoader: @_imageLoader modPack: @_modPack - model: @model.craftsman.have + model: @model.have router: @_router trackingContext: c.tracking.category.craftHave - @_haveInventoryController.on c.event.button.first, (controller, itemSlug)=> - @onRemoveFromHaveInventory itemSlug + @_haveInventoryController.on c.event.button.first, (controller, item)=> @onRemoveFromHave item @_needInventoryController = @addChild InventoryController, '.need .view__inventory', editable: false @@ -115,11 +116,9 @@ module.exports = class CraftPageController extends PageController model: null router: @_router trackingContext: c.tracking.category.craftNeed - @_needInventoryController.on c.event.button.first, (c, s)=> @onMoveNeedToHave(s) + @_needInventoryController.on c.event.button.first, (controller, item)=> @onMoveNeedToHave item - @_workingSectionController = @addChild CraftsmanWorkingController, '.view__craftsman_working', - model: @model.craftsman - @_workingSectionController.on c.event.click, => @_scrollTo @$workingSection + @_workingPanelController = @addChild WorkingPanelController, '.view__working_panel', model:@model @$haveSection = @$('section.have') @$instructionsSection = @$('section.instructions') @@ -128,7 +127,7 @@ module.exports = class CraftPageController extends PageController @$stepsContainer = @$('section.steps .panel') @$stepsSection = @$('section.steps') @$toolsSection = @$('section.tools') - @$workingSection = @$('.view__craftsman_working') + @$workingSection = @$('.view__working_panel') if c.screen.type.compute() is c.screen.type.mobile @$('.view__inventory.large').removeClass 'large' @@ -136,20 +135,15 @@ module.exports = class CraftPageController extends PageController super onWillRender: -> - @model.craftsman.have.clear() - @model.craftsman.have.parse @_storage.load('crafting-plan:have') - @model.craftsman.have.on c.event.change, => @onHaveInventoryChanged() - - @model.craftsman.want.on c.event.change, => @refresh() - - @model.craftsman.on c.event.change + ":stage", => - return unless @model.craftsman.stage is Craftsman::STAGE.COMPLETE - @_scrollTo @$needSection + @model.have.clear() + @model.have.merge Inventory.fromUrlString @_storage.load('crafting-plan:have') + @model.have.on Observable::ANY, this, "onHaveInventoryChanged" + @model.want.on Observable::ANY, this, "tryRefresh" super refresh: -> - @_needInventoryController.model = @model.craftsman.plan?.need + @_needInventoryController.model = @model.currentPlan?.need @_refreshOutdated() @_refreshSectionVisibility() @_refreshSteps() @@ -165,33 +159,30 @@ module.exports = class CraftPageController extends PageController # Private Methods ################################################################################ _addTools: (controller)-> - controller.model.addToolsTo @model.craftsman.want + controller.model.addToolsTo @model.want _completeStep: (controller)-> - controller.markComplete @model.craftsman.have + controller.markComplete @model.have _isAddingToolsPossible: (controller)-> - tools = controller.model.recipe.tools + tools = (item for itemId, item of controller.model.recipe.tools) return false unless tools.length > 0 - have = @model.craftsman.have - want = @model.craftsman.want + have = @model.have + want = @model.want - for stack in tools - return false if have.hasAtLeast stack.itemSlug - return false if want.hasAtLeast stack.itemSlug + for item in tools + return false if @model.have.contains item + return false if @model.want.contains item return true _isStepCompletable: (controller)-> - recipe = controller.model.recipe - for stack in recipe.output - return false if @model.craftsman.want.hasAtLeast stack.itemSlug - - return true + userWantsItem = @model.want.contains controller.model.recipe.output.item + return not userWantsItem _refreshOutdated: -> - if @model.craftsman.stage is Craftsman::STAGE.OUTDATED + if @model.isOutdated @$el.addClass 'outdated' else @$el.removeClass 'outdated' @@ -205,22 +196,25 @@ module.exports = class CraftPageController extends PageController visibleSections = [] - if @model.craftsman.want.isEmpty + # TODO: Figure out what to do if the planner can't make a valid plan + # else if @model.craftsman.stage is Craftsman::STAGE.INVALID + # visibleSections.push el for el in [@$wantSection, @$haveSection, @$workingSection] + # TODO: Play around and see if the algo ever takes too long + # else if not @model.craftsman.complete + # visibleSections.push el for el in [@$wantSection, @$haveSection, @$workingSection] + + if @model.want.isEmpty visibleSections.push el for el in [@$instructionsSection, @$wantSection] - else if @model.craftsman.stage is Craftsman::STAGE.INVALID - visibleSections.push el for el in [@$wantSection, @$haveSection, @$workingSection] - else if not @model.craftsman.complete - visibleSections.push el for el in [@$wantSection, @$haveSection, @$workingSection] else visibleSections.push el for el in [@$haveSection, @$wantSection, @$workingSection] - if @model.craftsman.plan? + if @model.currentPlan? visibleSections.push el for el in [@$needSection, @$stepsSection] @hide $el for $el in allSections @show $el for $el in visibleSections _refreshSteps: -> - steps = @model.craftsman.plan?.steps or [] + steps = @model.currentPlan?.steps or [] @_stepControllers ?= [] index = 0 @@ -236,10 +230,14 @@ module.exports = class CraftPageController extends PageController model: step modPack: @_modPack router: @_router - controller.render() - @$stepsContainer.append controller.$el - @_stepControllers.push controller + do (controller, index)=> + _.delay (=> + controller.render() + + @$stepsContainer.append controller.$el + @_stepControllers.push controller + ), (index * @STEP_RENDER_DELAY) else controller.model = step diff --git a/src/client/site/craft_page/craftsman_working/craftsman_working_controller.coffee b/src/client/site/craft_page/craftsman_working/craftsman_working_controller.coffee deleted file mode 100644 index f2e214538..000000000 --- a/src/client/site/craft_page/craftsman_working/craftsman_working_controller.coffee +++ /dev/null @@ -1,106 +0,0 @@ -# -# Crafting Guide - craftsman_working_controller.coffee -# -# Copyright © 2014-2017 by Redwood Labs -# All rights reserved. -# - -BaseController = require '../../base_controller' -{Craftsman} = require('crafting-guide-common').deprecated.crafting - -######################################################################################################################## - -module.exports = class CraftsmanWorkingController extends BaseController - - @::HIDE_TIMER_DURATION = 2000 - - constructor: (options={})-> - if not options.model then throw new Error 'options.model is required' - options.templateName = 'craft_page/craftsman_working' - super options - - @_hideTimer = null - - # Event Methods ################################################################################ - - onButtonClicked: -> - tracker.trackEvent c.tracking.category.craft, 'start' - @trigger c.event.click - @model.reset() - @model.work() - return false - - # BaseController Methods ####################################################################### - - onDidModelChange: -> - @refresh() - - onDidRender: -> - @$button = @$('.button') - @$count = @$('.count p') - @$message = @$('.message p') - @$outdated = @$('.outdated') - @$waiting = @$('.waiting') - - @_controls = [@$button, @$count, @$message, @$outdated, @$waiting] - super - - refresh: -> - return unless @$message? and @$count? - - button = count = message = outdated = waiting = null - - switch @model.stage - when Craftsman::STAGE.READY - message = 'Ready to compute crafting plan!' - count = 'Click "Calculate" to continue.' - button = true - when Craftsman::STAGE.GRAPHING - message = 'Researching recipes...' - count = "Found #{@model.stageCount} recipes so far..." - watiing = true - when Craftsman::STAGE.PLANNING - message = 'Figuring out possible crafting plans...' - count = "Found #{@model.stageCount} possibilities so far..." - watiing = true - when Craftsman::STAGE.ANALYZING - message = 'Looking for the best plan...' - count = "Finished checking #{@model.stageCount} so far..." - watiing = true - when Craftsman::STAGE.COMPLETE - message = 'Crafting plan is complete.' - when Craftsman::STAGE.INVALID - message = 'Couldn\'t make a crafting plan!' - count = 'Please report this problem using the Feedback box.' - when Craftsman::STAGE.OUTDATED - message = 'Your crafting plan is out of date!' - count = 'Click "Calculate" to re-compute.' - button = true - outdated = true - - @hide(control) for control in @_controls - - if button? - @show @$button - - if count? - @show @$count - @$count.html count - - if message? - @show @$message - @$message.html message - - if outdated? - @show @$outdated - - if waiting? - @show @$waiting - - super - - # Backbone.View Overrides ###################################################################### - - events: -> - return _.extend super, - 'click .button': 'onButtonClicked' diff --git a/src/client/site/craft_page/step/step.jade b/src/client/site/craft_page/step/step.jade index 913cb6ef9..2fb9eed80 100644 --- a/src/client/site/craft_page/step/step.jade +++ b/src/client/site/craft_page/step/step.jade @@ -7,9 +7,7 @@ .view__step h3 - .main_content - .view__inventory - .view__recipe + .view__recipe .buttons a.button.tool: .bezel: p show plan for tools .button.complete: .bezel: p complete step diff --git a/src/client/site/craft_page/step/step.scss b/src/client/site/craft_page/step/step.scss index c79068001..8a0b4cf89 100644 --- a/src/client/site/craft_page/step/step.scss +++ b/src/client/site/craft_page/step/step.scss @@ -25,24 +25,7 @@ margin-bottom: 1em; } - .main_content { - display: flex; - - .view__inventory { - flex: 50%; - margin-left: $size-margin-large; - - .buttons { - display: none; - } - } - - .view__recipe { - flex: 50%; - } - } - - .buttons { + & > .buttons { margin-top: $size-margin-large; opacity: 0; diff --git a/src/client/site/craft_page/step/step_controller.coffee b/src/client/site/craft_page/step/step_controller.coffee index eef7e330e..4c1c3f27f 100644 --- a/src/client/site/craft_page/step/step_controller.coffee +++ b/src/client/site/craft_page/step/step_controller.coffee @@ -5,20 +5,23 @@ # All rights reserved. # -BaseController = require '../../base_controller' -InventoryController = require '../../common/inventory/inventory_controller' -RecipeController = require '../../common/recipe/recipe_controller' -{SimpleInventory} = require('crafting-guide-common').deprecated.crafting +BaseController = require "../../base_controller" +{Inventory} = require("crafting-guide-common").models +{CraftingPlanStep} = require("crafting-guide-common").crafting +InventoryController = require "../../common/inventory/inventory_controller" +RecipeController = require "../../common/recipe/recipe_controller" +RecipeDisplay = require "../../../models/site/recipe_display" ######################################################################################################################## module.exports = class StepController extends BaseController constructor: (options={})-> - if not options.model? then throw new Error 'options.model is required' - if not options.modPack? then throw new Error 'options.modPack is required' - if not options.imageLoader? then throw new Error 'options.imageLoader is required' - options.templateName = 'craft_page/step' + if options.model?.constructor isnt CraftingPlanStep + throw new Error "options.model must be a CraftingPlanStep" + if not options.modPack? then throw new Error "options.modPack is required" + if not options.imageLoader? then throw new Error "options.imageLoader is required" + options.templateName = "craft_page/step" super options @_imageLoader = options.imageLoader @@ -33,57 +36,49 @@ module.exports = class StepController extends BaseController # Public Methods ############################################################################### markComplete: (targetInventory)-> - @$el.addClass 'complete' - @$completeButton.addClass 'disabled' + @$el.addClass "complete" + @$completeButton.addClass "disabled" @model.completeInto targetInventory # Event Methods ################################################################################ onCompleteButtonClicked: (event)-> - return if @$completeButton.hasClass 'disabled' - tracker.trackEvent c.tracking.category.craft, 'mark-complete', null, @model.number + return false if @$completeButton.hasClass "disabled" + tracker.trackEvent c.tracking.category.craft, "mark-complete", null, @model.count @onComplete this onShowToolPlan: (event)-> - tracker.trackEvent c.tracking.category.navigate, 'show-tool-plan', @$toolButton.attr 'target' + return false if @$toolButton.hasClass "disabled" + tracker.trackEvent c.tracking.category.navigate, "show-tool-plan", @$toolButton.attr "target" return true # BaseController Overrides ##################################################################### onDidRender: -> - @inventoryController = @addChild InventoryController, '.view__inventory', - editable: false - imageLoader: @_imageLoader - model: @model.inventory - modPack: @_modPack - router: @_router + options = imageLoader:@_imageLoader, modPack:@_modPack, router:@_router + @recipeController = @addChild RecipeController, ".view__recipe", options - @recipeController = @addChild RecipeController, '.view__recipe', - imageLoader: @_imageLoader - model: @model.recipe - modPack: @_modPack - router: @_router - - @$completeButton = @$('.button.complete') - @$header = @$('h3') - @$toolButton = @$('.button.tool') - @$toolButtonLabel = @$('.button.tool p') + @$completeButton = @$(".button.complete") + @$header = @$("h3") + @$toolButton = @$(".button.tool") + @$toolButtonLabel = @$(".button.tool p") super onWillChangeModel: (oldModel, newModel)-> - if not newModel? then throw new Error 'model cannot be null' + if not newModel? then throw new Error "model cannot be null" if @rendered - @$el.removeClass 'complete' - @$completeButton.removeClass 'disabled' + @$el.removeClass "complete" + @$completeButton.removeClass "disabled" return super refresh: -> - itemDisplay = @_modPack.findItemDisplay @model.recipe.output[0].itemSlug - @$header.html "#{@model.number}. #{itemDisplay.itemName}" + @$header.html "#{@model.number}. #{@model.recipe.output.item.displayName}" - @inventoryController.model = @model.inventory - @recipeController.model = @model.recipe - @recipeController.multiplier = @model.multiplier + @recipeController.model = new RecipeDisplay + multiplier: @model.count + recipe: @model.recipe + showInputInventory: true + showOutputSlot: true @_refreshCompleteButton() @_refreshToolButton() @@ -94,28 +89,27 @@ module.exports = class StepController extends BaseController events: -> return _.extend super, - 'click .button.complete': 'onCompleteButtonClicked' - 'click a.button.tool': 'onShowToolPlan' + "click .button.complete": "onCompleteButtonClicked" + "click .button.tool": "onShowToolPlan" # Private Methods ############################################################################## _refreshToolButton: -> - inventory = new SimpleInventory {}, modPack:@_modPack - for toolStack in @model.recipe.tools - inventory.add toolStack.itemSlug, toolStack.quantity - inventory.localize() + inventory = new Inventory + for itemId, item of @model.recipe.tools + inventory.add item - inventoryText = inventory.unparse() - @$toolButton.attr 'href', "/craft/#{inventoryText}" - @$toolButton.attr 'target', inventoryText + inventoryText = inventory.toUrlString() + @$toolButton.attr "href", "/craft/#{inventoryText}" + @$toolButton.attr "target", inventoryText if @canAddTools this - @$toolButton.removeClass 'disabled' + @$toolButton.removeClass "disabled" else - @$toolButton.addClass 'disabled' + @$toolButton.addClass "disabled" _refreshCompleteButton: -> if @canComplete this - @$completeButton.removeClass 'disabled' + @$completeButton.removeClass "disabled" else - @$completeButton.addClass 'disabled' + @$completeButton.addClass "disabled" diff --git a/src/client/site/craft_page/craftsman_working/craftsman_working.jade b/src/client/site/craft_page/working_panel/working_panel.jade similarity index 100% rename from src/client/site/craft_page/craftsman_working/craftsman_working.jade rename to src/client/site/craft_page/working_panel/working_panel.jade diff --git a/src/client/site/craft_page/craftsman_working/craftsman_working.scss b/src/client/site/craft_page/working_panel/working_panel.scss similarity index 100% rename from src/client/site/craft_page/craftsman_working/craftsman_working.scss rename to src/client/site/craft_page/working_panel/working_panel.scss diff --git a/src/client/site/craft_page/working_panel/working_panel_controller.coffee b/src/client/site/craft_page/working_panel/working_panel_controller.coffee new file mode 100644 index 000000000..06da9fa4a --- /dev/null +++ b/src/client/site/craft_page/working_panel/working_panel_controller.coffee @@ -0,0 +1,89 @@ +# +# Crafting Guide - working_panel_controller.coffee +# +# Copyright © 2014-2017 by Redwood Labs +# All rights reserved. +# + +BaseController = require '../../base_controller' +CraftPage = require "../../../models/site/craft_page" + +######################################################################################################################## + +module.exports = class WorkingPanelController extends BaseController + + @::HIDE_TIMER_DURATION = 2000 + + constructor: (options={})-> + if not options.model?.constructor is CraftPage then throw new Error "options.model must be a CraftPage" + options.templateName = "craft_page/working_panel" + super options + + @_hideTimer = null + + # Event Methods ################################################################################ + + onButtonClicked: -> + tracker.trackEvent c.tracking.category.craft, "start" + @trigger c.event.click + @model.createPlan() + return false + + # BaseController Methods ####################################################################### + + onDidModelChange: -> + @refresh() + + onDidRender: -> + @$button = @$('.button') + @$count = @$('.count p') + @$message = @$('.message p') + @$outdated = @$('.outdated') + @$waiting = @$('.waiting') + + @_controls = [@$button, @$count, @$message, @$outdated, @$waiting] + super + + refresh: -> + return unless @$message? and @$count? + + button = count = message = outdated = null + + if @model.isOutdated + message = "Your crafting plan is out of date!" + count = 'Click "Calculate" to re-compute.' + button = true + outdated = true + else if @model.currentPlan? + message = "Crafting plan is complete." + else + message = "Ready to compute crafting plan!" + count = 'Click "Calculate" to continue.' + button = true + + @hide(control) for control in @_controls + + if button? + @show @$button + + if count? + @show @$count + @$count.html count + + if message? + @show @$message + @$message.html message + + if outdated? + @show @$outdated + + if waiting? + @show @$waiting + + super + + # Backbone.View Overrides ###################################################################### + + events: -> + return _.extend super, + 'click .button': 'onButtonClicked' diff --git a/src/client/site/header/header_controller.coffee b/src/client/site/header/header_controller.coffee index d00f9cf8c..2c9ca71a8 100644 --- a/src/client/site/header/header_controller.coffee +++ b/src/client/site/header/header_controller.coffee @@ -6,6 +6,7 @@ # BaseController = require '../base_controller' +ItemDisplay = require "../../models/site/item_display" ItemSelectorController = require '../common/item_selector/item_selector_controller' UrlParams = require '../url_params' @@ -52,14 +53,14 @@ module.exports = class HeaderController extends BaseController onSearch: (event, hint='')-> tracker.trackEvent c.tracking.category.search, 'launch' @_selector.launch hint - .then (itemSlug)=> - if not itemSlug? - tracker.trackEvent c.tracking.category.search, 'cancel', itemSlug + .then (item)=> + if not item? + tracker.trackEvent c.tracking.category.search, 'cancel' return - tracker.trackEvent c.tracking.category.search, 'complete', itemSlug - itemDisplay = @_modPack.findItemDisplay itemSlug - @router.navigate itemDisplay.itemUrl, trigger:true + tracker.trackEvent c.tracking.category.search, 'complete', item.slug + itemDisplay = new ItemDisplay item + @router.navigate itemDisplay.url, trigger:true return false # BaseController Overrides ##################################################################### diff --git a/src/client/site/item_page/item_page.jade b/src/client/site/item_page/item_page.jade index 906d9ec96..c98a873ff 100644 --- a/src/client/site/item_page/item_page.jade +++ b/src/client/site/item_page/item_page.jade @@ -7,7 +7,7 @@ .content.view__item_page .left - include ../common/youtube/youtube.jade + // include ../common/youtube/youtube.jade .right .about @@ -24,11 +24,6 @@ section.description.view__markdown_section - section.multiblock - h2 Multiblock Construction - .panel - .view__multiblock_viewer - section.recipes h2 Recipes .panel @@ -43,4 +38,4 @@ section.view__item_group.usedAsToolToMake - section.view__item_group.similar \ No newline at end of file + section.view__item_group.similar diff --git a/src/client/site/item_page/item_page.scss b/src/client/site/item_page/item_page.scss index 4af4faa20..81d5401ab 100644 --- a/src/client/site/item_page/item_page.scss +++ b/src/client/site/item_page/item_page.scss @@ -57,6 +57,10 @@ flex: 0 0 auto; } } + + .view__recipe + .view__recipe { + margin-top: $size-margin-large; + } } @include screen-size(mobile) { diff --git a/src/client/site/item_page/item_page_controller.coffee b/src/client/site/item_page/item_page_controller.coffee index 3012c864b..c1a2215ea 100644 --- a/src/client/site/item_page/item_page_controller.coffee +++ b/src/client/site/item_page/item_page_controller.coffee @@ -5,17 +5,19 @@ # All rights reserved. # -EditableFile = require '../../models/site/editable_file' -{Item} = require('crafting-guide-common').deprecated.game -ItemGroupController = require '../common/item_group/item_group_controller' -ItemPage = require '../../models/site/item_page' -{ItemSlug} = require('crafting-guide-common').deprecated.game -MarkdownSectionController = require '../common/markdown_section/markdown_section_controller' -MultiblockViewerController = require './multiblock_viewer/multiblock_viewer_controller' -PageController = require '../page_controller' -RecipeDetailController = require './recipe_detail/recipe_detail_controller' -VideoController = require '../common/video/video_controller' -w = require "when" +EditableFile = require "../../models/site/editable_file" +{Item} = require("crafting-guide-common").models +{ItemDetail} = require("crafting-guide-common").models +{ItemDetailJsonParser} = require("crafting-guide-common").parsing +ItemDisplay = require "../../models/site/item_display" +ItemGroupController = require "../common/item_group/item_group_controller" +ItemPage = require "../../models/site/item_page" +MarkdownSectionController = require "../common/markdown_section/markdown_section_controller" +PageController = require "../page_controller" +RecipeController = require "../common/recipe/recipe_controller" +RecipeDisplay = require "../../models/site/recipe_display" +VideoController = require "../common/video/video_controller" +w = require "when" ######################################################################################################################## @@ -24,71 +26,52 @@ module.exports = class ItemPageController extends PageController @::FILE_UPLOAD_DELAY = 250 constructor: (options={})-> - if not options.client? then throw new Error 'options.client is required' - if not options.itemSlug? then throw new Error 'options.itemSlug is required' - if not options.imageLoader? then throw new Error 'options.imageLoader is required' - if not options.modPack? then throw new Error 'options.modPack is required' - if not options.router? then throw new Error 'options.router is required' - - options.model ?= new ItemPage modPack:options.modPack - options.templateName ?= 'item_page' + if not options.model?.constructor is ItemPage then throw new Error "options.model must be an ItemPage instance" + if not options.client? then throw new Error "options.client is required" + if not options.imageLoader? then throw new Error "options.imageLoader is required" + if not options.modPack? then throw new Error "options.modPack is required" + if not options.router? then throw new Error "options.router is required" + options.templateName ?= "item_page" super options @_client = options.client @_descriptionFile = null @_enterFeedback = options.enterFeedback @_imageLoader = options.imageLoader - @_itemSlug = options.itemSlug @_modPack = options.modPack @_router = options.router @_triggerEditing = options.login - @_modPack.on c.event.change, => - @tryRefresh() - @trigger c.event.change - # Event Methods ################################################################################ craftingPlanButtonClicked: -> - tracker.trackEvent c.tracking.category.craft, 'view-crafting-plan', @model.item.slug - display = @_modPack.findItemDisplay @model.item.slug - @_router.navigate display.craftingUrl, trigger:true + tracker.trackEvent c.tracking.category.craft, "view-crafting-plan", @model.item.slug + @_router.navigate @model.itemDisplay.craftingUrl, trigger:true return false # PageController Overrides ##################################################################### getBreadcrumbs: -> - return [] unless @_itemSlug? - - display = @_modPack.findItemDisplay @_itemSlug - return [] unless display.itemName? and display.modName - return [ - $("Browse") - $("#{display.modName}") - $("#{display.itemName}") + $("Browse") + $("#{@model.itemDisplay.mod.displayName}") + $("#{@model.itemDisplay.name}") ] getExtraNav: -> - itemSlug = @_modPack.chooseRandomItem() - return null unless itemSlug? + item = @_modPack.chooseRandomItem() + return null unless item? - itemDisplay = @_modPack.findItemDisplay itemSlug - return $("Random Item") + display = new ItemDisplay item + return $("Random Item") getMetaDescription: -> - return null unless @_itemSlug? - display = @_modPack.findItemDisplay @_itemSlug - return c.text.itemDescription display + data = itemName:@model.item.displayName, modName:@model.item.mod.displayName + return c.text.itemDescription data getTitle: -> - return null unless @_itemSlug? - - display = @_modPack.findItemDisplay @_itemSlug - return null unless display.itemName? and display.modName? - - return "#{display.itemName} from #{display.modName}" + return "#{@model.item.displayName} from #{@model.item.mod.displayName}" # BaseController Overrides ##################################################################### @@ -98,12 +81,11 @@ module.exports = class ItemPageController extends PageController onDidRender: -> options = imageLoader:@_imageLoader, modPack:@_modPack, router:@_router, show:false - @_multiblockController = @addChild MultiblockViewerController, '.view__multiblock_viewer', options - @_similarItemsController = @addChild ItemGroupController, '.view__item_group.similar', options - @_usedAsToolToMakeController = @addChild ItemGroupController, '.view__item_group.usedAsToolToMake ', options - @_usedToMakeController = @addChild ItemGroupController, '.view__item_group.usedToMake', options + @_similarItemsController = @addChild ItemGroupController, ".view__item_group.similar", options + @_usedAsToolToMakeController = @addChild ItemGroupController, ".view__item_group.usedAsToolToMake ", options + @_usedToMakeController = @addChild ItemGroupController, ".view__item_group.usedToMake", options - @_descriptionController = @addChild MarkdownSectionController, '.view__markdown_section', + @_descriptionController = @addChild MarkdownSectionController, ".view__markdown_section", client: @_client editable: true modPack: @_modPack @@ -112,37 +94,34 @@ module.exports = class ItemPageController extends PageController endEditing: => @_endEditingDescription() enterFeedback: @_enterFeedback - @$aboutImage = @$('.about img') - @$craftingPlanButton = @$('.button.craftingPlan') - @$name = @$('.about .title') - @$officialLink = @$('.about a.officialLink') - @$sourceModLink = @$('.about a.sourceMod') - @$aboutLinks = @$('.about .right') + @$aboutImage = @$(".about img") + @$craftingPlanButton = @$(".button.craftingPlan") + @$name = @$(".about .title") + @$officialLink = @$(".about a.officialLink") + @$sourceModLink = @$(".about a.sourceMod") + @$aboutLinks = @$(".about .right") - @$multiblockSection = @$('section.multiblock') - @$recipeContainer = @$('section.recipes .panel') - @$recipesSection = @$('section.recipes') - @$recipesSectionTitle = @$('section.recipes h2') - @$similarSection = @$('section.similar') - @$usedAsToolToMakeSection = @$('section.usedAsToolToMake') - @$usedToMakeSection = @$('section.usedToMake') - @$videosContainer = @$('section.videos .panel') - @$videosSection = @$('section.videos') - @$videosSectionTitle = @$('section.videos h2') + @$multiblockSection = @$("section.multiblock") + @$recipeContainer = @$("section.recipes .panel") + @$recipesSection = @$("section.recipes") + @$recipesSectionTitle = @$("section.recipes h2") + @$similarSection = @$("section.similar") + @$usedAsToolToMakeSection = @$("section.usedAsToolToMake") + @$usedToMakeSection = @$("section.usedToMake") + @$videosContainer = @$("section.videos .panel") + @$videosSection = @$("section.videos") + @$videosSectionTitle = @$("section.videos h2") super refresh: -> - @_resolveItemSlug() - if @model.item? - display = @_modPack.findItemDisplay @model.item.slug - @_imageLoader.load display.iconUrl, @$aboutImage - @$name.text display.itemName + @_imageLoader.load @model.itemDisplay.iconUrl, @$aboutImage + @$name.text @model.itemDisplay.name - @_descriptionController.imageBase = c.url.itemImageDir display + @_descriptionController.imageBase = c.url.itemImageDir @model.itemDisplay - if @model.item.officialUrl? - @$officialLink.attr 'href', @model.item.officialUrl + if @model.item.detail?.links.length > 0 + @$officialLink.attr "href", @model.item.detail.links[0] @show @$aboutLinks else @hide @$aboutLinks @@ -162,7 +141,6 @@ module.exports = class ItemPageController extends PageController @_refreshSourceMod() @_refreshDescription() - @_refreshMultiblock() @_refreshRecipes() @_refreshSimilarItems() @_refreshUsedAsToolToMake() @@ -179,22 +157,22 @@ module.exports = class ItemPageController extends PageController events: -> return _.extend super, - 'click a.craftingPlan': 'routeLinkClick' - 'click a.sourceMod': 'routeLinkClick' - 'click .markdown a': 'routeLinkClick' - 'click .button.craftingPlan': 'craftingPlanButtonClicked' + "click a.craftingPlan": "routeLinkClick" + "click a.sourceMod": "routeLinkClick" + "click .markdown a": "routeLinkClick" + "click .button.craftingPlan": "craftingPlanButtonClicked" # Private Methods ############################################################################## _beginEditingDescription: -> if not @user? global.site.login() - return w.reject new Error 'must be logged in to edit' + return w.reject new Error "must be logged in to edit" if not @model.item? - return w.reject new Error 'must have an item' + return w.reject new Error "must have an item" - pathArgs = modSlug:@_itemSlug.mod, itemSlug:@_itemSlug.item + pathArgs = modSlug:@model.item.mod.id, itemSlug:@model.itemDisplay.itemSlug attributes = fileName: c.gitHub.file.itemDescription.fileName pathArgs path: c.gitHub.file.itemDescription.path pathArgs @@ -203,27 +181,29 @@ module.exports = class ItemPageController extends PageController @_descriptionFile.fetch() .then => if @_descriptionFile.encodedData?.length > 0 - @model.item.parse @_descriptionFile.getDecodedData 'utf8' + parser = new ItemDetailJsonParser item:@model.item + parser.parse @_descriptionFile.getDecodedData "utf8" else - @model.item.description = '' + @model.item.detail = new ItemDetail item:@model.item - @_descriptionController.model = @model.item.description + @_descriptionController.model = @model.item.detail.description _endEditingDescription: -> - oldDescription = @model.item.description + oldDescription = @model.item.detail.description promises = [] saveList = [] for imageFile in @_descriptionController.imageFiles saveList.push file: imageFile - message: "User-submitted image for #{@model.item.name} from #{global.hostName}" + message: "User-submitted image for #{@model.item.displayName} from #{global.hostName}" - @model.item.description = @_descriptionController.model - @_descriptionFile.setDecodedData @model.item.unparse() + @model.item.detail.description = @_descriptionController.model + parser = new ItemDetailJsonParser item:@model.item + @_descriptionFile.setDecodedData parser.format @model.item.detail saveList.push file: @_descriptionFile - message: "User-submitted text for #{@model.item.name} from #{global.hostName}" + message: "User-submitted text for #{@model.item.displayName} from #{global.hostName}" saveNextFile = (fileList)-> return w(true) if fileList.length is 0 @@ -235,42 +215,39 @@ module.exports = class ItemPageController extends PageController saveNextFile saveList .catch (e)=> - @model.item.description = oldDescription + @model.item.detail.description = oldDescription throw e _refreshDescription: -> - if @model.item?.description?.length > 0 - @_descriptionController.model = @model.item.description + if @model.item.detail?.description.length > 0 + @_descriptionController.model = @model.item.detail.description @_descriptionController.resetToDefaultState() - _refreshMultiblock: -> - if @model.item?.multiblock? - @_multiblockController.model = @model.item.multiblock - @show @$multiblockSection - else - @hide @$multiblockSection - _refreshRecipes: -> @_recipeControllers ?= [] index = 0 recipes = @model.findRecipes() if recipes?.length > 0 - @$recipesSectionTitle.html if recipes.length is 1 then 'Recipe' else 'Recipes' + @$recipesSectionTitle.html if recipes.length is 1 then "Recipe" else "Recipes" - for recipe in @model.findRecipes() + for recipe in recipes controller = @_recipeControllers[index] + model = new RecipeDisplay + recipe: recipe + showInputInventory: true + showOutputInventory: true if not controller? - controller = new RecipeDetailController + controller = new RecipeController imageLoader: @_imageLoader modPack: @_modPack - model: recipe + model: model router: @_router @_recipeControllers.push controller @$recipeContainer.append controller.$el controller.render() else - controller.model = recipe + controller.model = model index++ @show @$recipesSection @@ -281,38 +258,34 @@ module.exports = class ItemPageController extends PageController @_recipeControllers.pop().remove() _refreshSimilarItems: -> - group = @model.item?.group - if group? and group isnt Item.Group.Other - @_similarItemsController.title = "Other #{group}" + groupName = @model.item.groupName + if groupName? and groupName isnt Item::DEFAULT_GROUP_NAME + @_similarItemsController.title = "Other #{groupName}" @_similarItemsController.model = @model.findSimilarItems() else @_similarItemsController.model = null _refreshSourceMod: -> - mod = @model.item?.modVersion?.mod - if mod?.name?.length > 0 - @$sourceModLink.attr 'href', c.url.mod modSlug:mod.slug - @$sourceModLink.text mod.name - - @show @$sourceModLink - else - @hide @$sourceModLink + mod = @model.item.mod + @$sourceModLink.attr "href", c.url.mod @model.itemDisplay + @$sourceModLink.text mod.name + @show @$sourceModLink _refreshUsedAsToolToMake: -> - @_usedAsToolToMakeController.title = 'Used as Tool to Make' - @_usedAsToolToMakeController.model = @model.findToolForRecipes() + @_usedAsToolToMakeController.title = "Used as Tool to Make" + @_usedAsToolToMakeController.model = @model.findToolForItems() _refreshUsedToMake: -> - @_usedToMakeController.title = 'Used to Make' + @_usedToMakeController.title = "Used to Make" @_usedToMakeController.model = @model.findComponentInItems() _refreshVideos: -> @_videoControllers ?= [] index = 0 - videos = @model?.item?.videos or [] + videos = @model.item.detail?.videos if videos? and videos.length > 0 - @$videosSectionTitle.html if videos.length is 1 then 'Video' else 'Videos' + @$videosSectionTitle.html if videos.length is 1 then "Video" else "Videos" for video in videos controller = @_videoControllers[index] @@ -332,15 +305,3 @@ module.exports = class ItemPageController extends PageController while @_videoControllers.length > index @_videoControllers.pop().remove() - _resolveItemSlug: -> - return if @model.item? - - item = @_modPack.findItem @_itemSlug, includeDisabled:true - if item? - if not ItemSlug.equal item.slug, @_itemSlug - @_router.navigate c.url.item(modSlug:item.slug.mod, itemSlug:item.slug.item), trigger:true - return - - @model.item = item - item.fetch() - item.on c.event.sync, => @refresh() diff --git a/src/client/site/item_page/multiblock_viewer/multiblock_viewer_controller.coffee b/src/client/site/item_page/multiblock_viewer/multiblock_viewer_controller.coffee deleted file mode 100644 index 068118934..000000000 --- a/src/client/site/item_page/multiblock_viewer/multiblock_viewer_controller.coffee +++ /dev/null @@ -1,99 +0,0 @@ -# -# Crafting Guide - multiblock_viewer_controller.coffee -# -# Copyright © 2014-2017 by Redwood Labs -# All rights reserved. -# - -BaseController = require '../../base_controller' -InventoryController = require '../../common/inventory/inventory_controller' -MultiblockController = require './multiblock/multiblock_controller' - -######################################################################################################################## - -module.exports = class MultiblockViewerController extends BaseController - - constructor: (options={})-> - if not options.imageLoader? then throw new Error 'options.imageLoader is required' - if not options.modPack? then throw new Error 'options.modPack is required' - if not options.router? then throw new Error 'options.router is required' - options.templateName = 'item_page/multiblock_viewer' - super options - - @_imageLoader = options.imageLoader - @_modPack = options.modPack - @_hoverTimer = null - @_router = options.router - - # Event Methods ################################################################################ - - onBackClicked: -> - return if @$backButton.hasClass 'disabled' - tracker.trackEvent c.tracking.category.multiblock, 'back' - @multiblockController.goBackLayer() - @refresh() - - onNextClicked: -> - return if @$nextButton.hasClass 'disabled' - tracker.trackEvent c.tracking.category.multiblock, 'next' - @multiblockController.goNextLayer() - @refresh() - - onBlockHovered: (itemDisplay)-> - if itemDisplay? - @$captionText.html itemDisplay.itemName - @_imageLoader.load itemDisplay.iconUrl, @$captionIcon - else - @$captionText.html ' ' - @$captionIcon.attr 'src', '/images/empty.png' - - # BaseController Overrides ##################################################################### - - onDidRender: -> - @completeInventoryController = @addChild InventoryController, '.view__inventory.complete', - editable: false - imageLoader: @_imageLoader - modPack: @_modPack - router: @_router - - @layerInventoryController = @addChild InventoryController, '.view__inventory.layer', - editable: false - imageLoader: @_imageLoader - modPack: @_modPack - router: @_router - - @multiblockController = @addChild MultiblockController, '.view__multiblock', - imageLoader: @_imageLoader - modPack: @_modPack - onHovering: (itemDisplay)=> @onBlockHovered(itemDisplay) - - @$backButton = @$('.button.back') - @$nextButton = @$('.button.next') - @$captionText = @$('.caption p') - @$captionIcon = @$('.caption img') - super - - refresh: -> - if @model? - @completeInventoryController.model = @model.inventory - @layerInventoryController.model = @model.getLayerInventory @multiblockController.currentLayer - @multiblockController.model = @model - - if @multiblockController.hasBackLayer() - @$backButton.removeClass 'disabled' - else - @$backButton.addClass 'disabled' - - if @multiblockController.hasNextLayer() - @$nextButton.removeClass 'disabled' - else - @$nextButton.addClass 'disabled' - - super - - # Backbone.View Overrides ###################################################################### - - events: -> - _.extend super, - 'click .button.back': 'onBackClicked' - 'click .button.next': 'onNextClicked' diff --git a/src/client/site/item_page/recipe_detail/recipe_detail_controller.coffee b/src/client/site/item_page/recipe_detail/recipe_detail_controller.coffee index bcf81d47e..3be268ebd 100644 --- a/src/client/site/item_page/recipe_detail/recipe_detail_controller.coffee +++ b/src/client/site/item_page/recipe_detail/recipe_detail_controller.coffee @@ -5,21 +5,22 @@ # All rights reserved. # -BaseController = require '../../base_controller' -CraftingGridController = require '../../common/crafting_grid/crafting_grid_controller' -{Inventory} = require('crafting-guide-common').deprecated.game -InventoryController = require '../../common/inventory/inventory_controller' -{StringBuilder} = require('crafting-guide-common').util +BaseController = require "../../base_controller" +CraftingGridController = require "../../common/crafting_grid/crafting_grid_controller" +{Inventory} = require("crafting-guide-common").models +InventoryController = require "../../common/inventory/inventory_controller" +ItemDisplay = require "../../../models/site/item_display" +{StringBuilder} = require("crafting-guide-common").util ######################################################################################################################## module.exports = class RecipeDetailController extends BaseController constructor: (options={})-> - if not options.imageLoader? then throw new Error 'options.imageLoader is required' - if not options.modPack? then throw new Error 'options.modPack is required' - if not options.router? then throw new Error 'options.router is required' - options.templateName = 'item_page/recipe_detail' + if not options.imageLoader? then throw new Error "options.imageLoader is required" + if not options.modPack? then throw new Error "options.modPack is required" + if not options.router? then throw new Error "options.router is required" + options.templateName = "item_page/recipe_detail" super options @_imageLoader = options.imageLoader @@ -29,26 +30,26 @@ module.exports = class RecipeDetailController extends BaseController # BaseController Overrides ##################################################################### onDidRender: -> - @gridController = @addChild CraftingGridController, '.view__crafting_grid', + @gridController = @addChild CraftingGridController, ".view__crafting_grid", imageLoader: @_imageLoader modPack: @_modPack router: @_router - @inputController = @addChild InventoryController, '.input .view__inventory', + @inputController = @addChild InventoryController, ".input .view__inventory", editable: false imageLoader: @_imageLoader model: new Inventory modPack: @_modPack router: @_router - @outputController = @addChild InventoryController, '.output .view__inventory', + @outputController = @addChild InventoryController, ".output .view__inventory", editable: false imageLoader: @_imageLoader model: new Inventory modPack: @_modPack router: @_router - @$toolContainer = @$('.tool') + @$toolContainer = @$(".tool") super refresh: -> @@ -67,33 +68,33 @@ module.exports = class RecipeDetailController extends BaseController events: -> return _.extend super, - 'click a': 'routeLinkClick' + "click a": "routeLinkClick" # Private Methods ############################################################################## _refreshInputs: -> inputs = @inputController.model inputs.clear() + return unless @model? - if @model? - for stack in @model.input - inputs.add stack.itemSlug, @model.getQuantityRequired stack.itemSlug - + for itemId, item of @model.inputs + inputs.add item, @model.computeQuantityRequired item _refreshOutputs: -> outputs = @outputController.model outputs.clear() + return unless @model? - if @model? - for stack in @model.output - outputs.add stack.itemSlug, @model.getQuantityProduced stack.itemSlug + outputs.add @model.output.item, @model.output.quantity + for itemId, item of @model.extras + outputs.add item, @model.computeQuantityProduced item _refreshTools: -> @$toolContainer.empty() return unless @model? - builder = new StringBuilder - builder.loop @model.tools, delimiter:', ', onEach:(b, stack)=> - display = @_modPack.findItemDisplay stack.itemSlug - b.push "#{display.itemName}" - @$toolContainer.html builder.toString() + toolLinks = [] + for itemId, item of @model.tools + display = new ItemDisplay item + toolLinks.push "#{display.name}" + @$toolContainer.html toolLinks.join ", " diff --git a/src/client/site/mod_page/mod_page_controller.coffee b/src/client/site/mod_page/mod_page_controller.coffee index 98448dedc..7feebe00f 100644 --- a/src/client/site/mod_page/mod_page_controller.coffee +++ b/src/client/site/mod_page/mod_page_controller.coffee @@ -28,27 +28,16 @@ module.exports = class ModPageController extends PageController @_modPack = options.modPack @_router = options.router - # Property Methods ############################################################################# - - Object.defineProperties @prototype, - - effectiveModVersion: - get: -> - modVersion = @model.activeModVersion - modVersion ?= @model.getModVersion Mod.Version.Latest - modVersion.fetch() if modVersion? - return modVersion - # PageController Overrides ##################################################################### getBreadcrumbs: -> return [ $('Browse') - $("#{@model.name}") + $("#{@model.displayName}") ] getTitle: -> - return @model.name + return @model.displayName # BaseController Overrides ##################################################################### @@ -92,8 +81,8 @@ module.exports = class ModPageController extends PageController @$documentationLink.attr 'href', @model.documentationUrl @$downloadLink.attr 'href', @model.downloadUrl @$homePageLink.attr 'href', @model.homePageUrl - @$logo.attr 'src', c.url.modIcon modSlug:@model.slug - @$title.text @model.name + @$logo.attr 'src', c.url.modIcon modId:@model.id + @$title.text @model.displayName else @$author.text '' @$description.text '' @@ -106,29 +95,24 @@ module.exports = class ModPageController extends PageController _refreshItemGroups: -> @_groupControllers ?= [] groupIndex = 0 - modVersion = @effectiveModVersion - if modVersion? - modVersion.eachGroup (group)=> - controller = @_groupControllers[groupIndex] - items = modVersion.allItemsInGroup group - if not controller? - controller = new ItemGroupController - imageLoader: @_imageLoader - model: items - modPack: @_modPack - router: @_router - title: if group is Item.Group.Other then 'Items' else group + for groupName, items of @model.itemGroups + controller = @_groupControllers[groupIndex] + if not controller? + controller = new ItemGroupController + imageLoader: @_imageLoader + model: items + modPack: @_modPack + router: @_router + title: groupName - _.defer => - @_groupControllers.push controller - @$itemGroups.append controller.$el - controller.render() - else - controller.modVersion = modVersion - controller.model = items - controller.refresh() - groupIndex++ + @_groupControllers.push controller + @$itemGroups.append controller.$el + controller.render() + else + controller.model = items + controller.refresh() + groupIndex++ while @_groupControllers.length > groupIndex + 1 @_groupControllers.pop().remove() diff --git a/src/client/site/router.coffee b/src/client/site/router.coffee index bec2bf4de..74e3412f3 100644 --- a/src/client/site/router.coffee +++ b/src/client/site/router.coffee @@ -5,15 +5,16 @@ # All rights reserved. # -BrowsePageController = require './browse_page/browse_page_controller' -CraftPageController = require './craft_page/craft_page_controller' -ItemPageController = require './item_page/item_page_controller' -{ItemSlug} = require('crafting-guide-common').deprecated.game -LoginPageController = require './login_page/login_page_controller' -ModPageController = require './mod_page/mod_page_controller' -NewsPageController = require './news_page/news_page_controller' -TutorialPageController = require './tutorial_page/tutorial_page_controller' -UrlParams = require './url_params' +BrowsePageController = require "./browse_page/browse_page_controller" +CraftPageController = require "./craft_page/craft_page_controller" +ItemPage = require "../models/site/item_page" +ItemPageController = require "./item_page/item_page_controller" +{ItemSlug} = require("crafting-guide-common").deprecated.game +LoginPageController = require "./login_page/login_page_controller" +ModPageController = require "./mod_page/mod_page_controller" +NewsPageController = require "./news_page/news_page_controller" +TutorialPageController = require "./tutorial_page/tutorial_page_controller" +UrlParams = require "./url_params" ######################################################################################################################## @@ -34,50 +35,50 @@ module.exports = class Router extends Backbone.Router tracker.trackPageView() routes: - '': 'route__home' - '/': 'route__home' - '/index.html': 'route__home' + '': 'route__home' + '/': 'route__home' + '/index.html': 'route__home' - 'browse': 'route__browse' - 'browse/': 'route__browse' - 'browse/index.html': 'route__browse' + 'browse': 'route__browse' + 'browse/': 'route__browse' + 'browse/index.html': 'route__browse' - 'browse/:modSlug': 'route__browseMod' - 'browse/:modSlug/': 'route__browseMod' - 'browse/:modSlug/index.html': 'route__browseMod' + 'browse/:modId': 'route__browseMod' + 'browse/:modId/': 'route__browseMod' + 'browse/:modId/index.html': 'route__browseMod' - 'browse/:modSlug/:itemSlug': 'route__browseModItem' - 'browse/:modSlug/:itemSlug/': 'route__browseModItem' - 'browse/:modSlug/:itemSlug/index.html': 'route__browseModItem' + 'browse/:modId/:itemSlug': 'route__browseModItem' + 'browse/:modId/:itemSlug/': 'route__browseModItem' + 'browse/:modId/:itemSlug/index.html': 'route__browseModItem' - 'browse/:modSlug/tutorials/:tutorialSlug': 'route__browseTutorial' - 'browse/:modSlug/tutorials/:tutorialSlug/': 'route__browseTutorial' - 'browse/:modSlug/tutorials/:tutorialSlug/index.html': 'route__browseTutorial' + 'browse/:modId/tutorials/:tutorialSlug': 'route__browseTutorial' + 'browse/:modId/tutorials/:tutorialSlug/': 'route__browseTutorial' + 'browse/:modId/tutorials/:tutorialSlug/index.html': 'route__browseTutorial' - 'configure': 'route__configure' - 'configure/': 'route__configure' - 'configure/index.html': 'route__configure' + 'configure': 'route__configure' + 'configure/': 'route__configure' + 'configure/index.html': 'route__configure' - 'craft': 'route__craft' - 'craft/': 'route__craft' - 'craft/index.html': 'route__craft' + 'craft': 'route__craft' + 'craft/': 'route__craft' + 'craft/index.html': 'route__craft' - 'craft/:text': 'route__craft' - 'craft/:text/': 'route__craft' - 'craft/:text/index.html': 'route__craft' + 'craft/:text': 'route__craft' + 'craft/:text/': 'route__craft' + 'craft/:text/index.html': 'route__craft' - 'login': 'route__login' - 'login/': 'route__login' - 'login/index.html': 'route__login' + 'login': 'route__login' + 'login/': 'route__login' + 'login/index.html': 'route__login' - 'news': 'route__news' - 'news/': 'route__news' - 'news/index.html': 'route__news' + 'news': 'route__news' + 'news/': 'route__news' + 'news/index.html': 'route__news' - 'item/:itemSlug': 'deprecated__item' - 'crafting/(:text)': 'deprecated__crafting' - 'mod/:modSlug': 'deprecated__mod' - 'mod/:modSlug/:itemSlug': 'deprecated__modItem' + 'item/:itemSlug': 'deprecated__item' + 'crafting/(:text)': 'deprecated__crafting' + 'mod/:modSlug': 'deprecated__mod' + 'mod/:modSlug/:itemSlug': 'deprecated__modItem' # Route Methods ################################################################################ @@ -92,15 +93,20 @@ module.exports = class Router extends Backbone.Router route__browse: -> @_siteController.setPage 'browse', new BrowsePageController @_makeOptions {} - route__browseMod: (modSlug)-> + route__browseMod: (modId)-> controller = new ModPageController @_makeOptions() - controller.model = @_siteController.modPack.getMod modSlug + controller.model = @_siteController.modPack.mods[modId] @_siteController.setPage 'browseMod', controller - route__browseModItem: (modSlug, itemSlug)-> + route__browseModItem: (modId, itemSlug)-> + item = @_siteController.modPack.findItemBySlug itemSlug, modId:modId + if not item? then throw new Error "could not find item #{modId}__#{itemSlug}" + + itemPage = new ItemPage item + itemPage.loadDetails() + params = new UrlParams login:{type:'boolean', default:false} - slug = new ItemSlug modSlug, itemSlug - controller = new ItemPageController @_makeOptions {itemSlug:slug, login:params.login} + controller = new ItemPageController @_makeOptions {model:itemPage, login:params.login} @_siteController.setPage 'browseModItem', controller route__browseTutorial: (modSlug, tutorialSlug)-> @@ -113,8 +119,7 @@ module.exports = class Router extends Backbone.Router @route__craft() route__craft: (text)-> - controller = new CraftPageController @_makeOptions {} - controller.model.params = inventoryText:text + controller = new CraftPageController @_makeOptions params:inventoryText:text @_siteController.setPage 'craft', controller route__login: -> diff --git a/src/client/site/site_controller.coffee b/src/client/site/site_controller.coffee index f44ef194b..c0bbeb6cc 100644 --- a/src/client/site/site_controller.coffee +++ b/src/client/site/site_controller.coffee @@ -7,6 +7,7 @@ AdsenseController = require './common/adsense/adsense_controller' BaseController = require './base_controller' +c = require "../../common/constants" FeedbackController = require './feedback/feedback_controller' FileCache = require '../models/site/file_cache' FooterController = require './footer/footer_controller' @@ -23,14 +24,14 @@ module.exports = class SiteController extends BaseController constructor: (options={})-> if not options.client? then throw new Error 'options.client is required' + if not options.modPack? then throw new Error 'options.modPack is required' if not options.storage? then throw new Error 'options.storage is required' options.el = 'html' super options @client = options.client - @fileCache = new FileCache c.url.modpackArchive() @imageLoader = new ImageLoader defaultUrl:'/images/unknown.png' - @modPack = new ModPack {}, fileCache:@fileCache + @modPack = options.modPack @router = new Router this @storage = options.storage @@ -41,23 +42,6 @@ module.exports = class SiteController extends BaseController # Public Methods ############################################################################### - loadDefaultModPack: -> - makeResponder = (m)-> return -> - m.activeModVersion.fetch() if m.activeModVersion? - - for modSlug, modData of c.defaultMods - mod = new Mod {slug:modSlug}, {fileCache:@fileCache} - mod.on c.event.change + ':activeModVersion', makeResponder mod - @storage.register "mod:#{mod.slug}", mod, 'activeVersion', modData.defaultVersion - mod.fetch() - - @modPack.addMod mod - - if global.env isnt 'prerender' - @modPack.once c.event.sync, => - @$pageContent.removeClass 'hidden' - @$pageContentLoading.addClass 'hidden' - loadCurrentUser: -> @client.getCurrentUser() .then (response)=> @@ -129,6 +113,10 @@ module.exports = class SiteController extends BaseController @_feedbackController = @addChild FeedbackController, '.view__feedback' + if global.env isnt "prerender" + @$pageContent.removeClass "hidden" + @$pageContentLoading.addClass "hidden" + # Private Methods ############################################################################## setPage: (page, controller)-> diff --git a/src/common/constants.coffee b/src/common/constants.coffee index 9ba786139..4799b4d04 100644 --- a/src/common/constants.coffee +++ b/src/common/constants.coffee @@ -81,7 +81,7 @@ duration.slow = 1200 exports.gitHub = gitHub = {} gitHub.file = {} gitHub.file.itemDescription = {} -gitHub.file.itemDescription.fileName = _.template "item.cg" +gitHub.file.itemDescription.fileName = _.template "item.json" gitHub.file.itemDescription.path = _.template "/data/<%= modSlug %>/items/<%= itemSlug %>" exports.key = key = {} @@ -99,9 +99,6 @@ login.clientIds = 'staging': '3d75ed772ce5004180d6' 'production': 'ce71be7f66926ff6ff38' -exports.modpack = modpack = {} -modpack.default = "crafting-guide-default" - exports.opacity = opacity = {} opacity.hidden = 1e-6 opacity.shown = 1 diff --git a/src/server/crafting_guide_server.coffee b/src/server/crafting_guide_server.coffee index 3b8cd6423..296e87ba6 100644 --- a/src/server/crafting_guide_server.coffee +++ b/src/server/crafting_guide_server.coffee @@ -41,3 +41,4 @@ module.exports = class CraftingGuideServer console.log "CraftingGuide is shutting down" @httpServer.close() => resolve this + diff --git a/src/server/middleware.coffee b/src/server/middleware.coffee index 200ec9ad1..1887df898 100644 --- a/src/server/middleware.coffee +++ b/src/server/middleware.coffee @@ -26,7 +26,7 @@ exports.installBefore = (app)-> ] exports.installAfter = (app)-> - app.use '/data', express.static '../../crafting-guide-data/data/', etag:false, maxAge: 0 + app.use '/data', express.static '/src/crafting-guide/data/data/', etag:false, maxAge: 0 app.use express.static './static', etag: false, maxAge: 0 # Middleware Functions #####################################################################################