diff --git a/DOCS.md b/DOCS.md new file mode 100644 index 0000000..39ecb2b --- /dev/null +++ b/DOCS.md @@ -0,0 +1,136 @@ +# Doodle3D Slicer +This document explains how the slice process works. + +In this slicer Z is the "up" vector. + +Requisites + - 2D Vector math + - 3D Vector math + - 2D Boolean operations (union, difference) + - 2D Path offsetting + +### Step 0: Preparation +The first step is to prepare the data for slicing. Most of the model data is mapped into `typed arrays`. This way they can be send to the worker very efficiently (due to the transferable nature of typed arrays). +``` +Vertices: Float32Array +Faces: Uint32Array +ObjectIndexes: UInt8Array +OpenObjectIndexes: [...Int] +Settings: + startCode: String + endcode: String + dimensions: + x: Number + y: Number + z: Number + heatedBed: Bool + nozzleDiameter: Number + filamentThickness: Number + temperature: Number + bedTemperature: Number + layerHeight: Number + combing: Bool + thickness: + top: Number + bottom: Number + shell: Number + retraction: + enabled: Bool + amount: Number + speed: Number + minDistance: Number + travel: + speed: Number + support: + enabled: Bool + minArea: Number + distanceY: Number + density: Number + margin: Number + flowRate: Number + speed: Number + innerShell: + flowRate: Number + speed: Number + outerShell: + flowRate: Number + speed: Number + innerInfill: + flowRate: Number + speed: Number + density: Number + outerInfill: + flowRate: Number + speed: Number + brim: + size: Number + flowRate: Number + speed: Number + firstLayer: + flowRate: Number + speed: Number +``` + - Vertices: List of points in 3d + - Faces: Indexes refering to points in the vertices list that make a triangular surface + - ObjectIndexes: Describes of what object each face is part of (important for the generating of 2d shapes) + - OpenObjectIndexes: Determines weather a object is open or closed (important for the generating of 2d shapes) + - Settings: object containing all the settings for slicing. We go in depth in this object when it's needed + +### Step 1: Creating lines +In this we take the 3d model and look at each surface to extract all individual lines. Note some lines are part of multiple surfaces. In addition we also add some additional data to each line, like the surfaces it is part of we'll also store the 2d normal. + +``` +function calculateNormal(vertices, a, b, c) { + a = getVertex(vertices, a); + b = getVertex(vertices, b); + c = getVertex(vertices, c); + + const cb = vector3.subtract(c, b); + const ab = vector3.subtract(a, b); + const normal = vector3.normalize(vector3.cross(cb, ab)); + + return normal; +} +``` + +In order to extract all unique lines from the model we'll loop through each face of the model. + +### Step 2: Calculate Layers Intersections +This is a fairly straight forward step. We take the lines and calculate on what layers that line will be intersecting. Additinally we calculate the coordinates where the line intersects each layer. + +### Step 3: Intersections To Shapes +### Step 4: Shapes To Slices +### Step 5: Generate Inner Lines +### Step 6: Generate Outlines +### Step 7: Generate Infills +### Step 8: Generate Support +### Step 9: AddBrim + +``` +let { + brim: { size: brimSize }, + nozzleDiameter +} = settings; + +nozzleDiameter /= PRECISION; +brimSize /= PRECISION; +const nozzleRadius = nozzleDiameter / 2; + +const [firstLayer] = slices; + +const brim = firstLayer.parts.reduce((brim, { shape }) => ( + brim.join(shape.offset(nozzleRadius, { + endType: shape.closed ? 'etClosedPolygon' : 'etOpenRound' + })) +), new Shape([], true)).simplify('pftNonZero'); + +firstLayer.brim = new Shape([], true); + +for (let offset = 0; offset < brimSize; offset += nozzleDiameter) { + const brimPart = brim.offset(offset, OFFSET_OPTIONS); + firstLayer.brim = firstLayer.brim.join(brimPart); +} +``` + +### Step 10: Optimize Paths +### Step 11: Slices To GCode diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000..921abdd Binary files /dev/null and b/favicon.ico differ diff --git a/img/logo.png b/img/logo.png new file mode 100644 index 0000000..128b70b Binary files /dev/null and b/img/logo.png differ diff --git a/index.js b/index.js index 54d517b..922f2d2 100644 --- a/index.js +++ b/index.js @@ -1,17 +1,23 @@ import 'babel-polyfill' import React from 'react'; import { Interface } from 'doodle3d-slicer'; -import doodleURL from '!url-loader!./models/Doodle_2.d3sketch'; import { render } from 'react-dom'; import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'; import injectTapEventPlugin from 'react-tap-event-plugin'; import jss from 'jss'; import preset from 'jss-preset-default'; import normalize from 'normalize-jss'; -import JSONToSketchData from 'doodle3d-core/shape/JSONToSketchData'; -import createSceneData from 'doodle3d-core/d3/createSceneData.js'; -import { generateExportMesh } from 'doodle3d-core/utils/exportUtils.js'; -import { Matrix4 } from 'three/src/math/Matrix4.js'; +import queryString from 'query-string'; +import getMuiTheme from 'material-ui/styles/getMuiTheme'; +import { grey400, blue500, blue700 } from 'material-ui/styles/colors'; + +const muiTheme = getMuiTheme({ + palette: { + primary1Color: blue500, + primary2Color: blue700, + accent1Color: blue500, + } +}); injectTapEventPlugin(); @@ -26,17 +32,11 @@ jss.createStyleSheet({ } }).attach(); -function init(mesh) { - render(( - - - - ), document.getElementById('app')); -} +let { file, selectedPrinter, actions } = queryString.parse(location.search); +if (actions) actions = JSON.parse(actions); -fetch(doodleURL) - .then(resonse => resonse.json()) - .then(json => JSONToSketchData(json)) - .then(file => createSceneData(file)) - .then(sketch => generateExportMesh(sketch, { offsetSingleWalls: false, matrix: new Matrix4() })) - .then(init); +render(( + + + +), document.getElementById('app')); diff --git a/package-lock.json b/package-lock.json index cd11baa..e37aa04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,13 +7,12 @@ "@doodle3d/cal": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/@doodle3d/cal/-/cal-0.0.8.tgz", - "integrity": "sha512-1qXg62qaZkc/zYPan37CXvUtaJk4aFVLz2y8cqnkN9Y0r1Er5soIZ5esMz4YYyjUrQGawBoYcGvatRALYnzlvg==", - "dev": true + "integrity": "sha512-1qXg62qaZkc/zYPan37CXvUtaJk4aFVLz2y8cqnkN9Y0r1Er5soIZ5esMz4YYyjUrQGawBoYcGvatRALYnzlvg==" }, "@doodle3d/clipper-js": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@doodle3d/clipper-js/-/clipper-js-1.0.7.tgz", - "integrity": "sha512-8Ji8rrFWZ7LAEpIp1SQZJgewxt0FUBFeDku+ZRIR5PS0Jc6Abbq5KykQLVh1zOh3oqX2Cgl+myhqMhFeZXqutA==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@doodle3d/clipper-js/-/clipper-js-1.0.10.tgz", + "integrity": "sha512-BSLvOvS9ECFyV90BsG1rXPb9W/g0j+azlPu5ntohFdIyUJPIzmRNAYq4lreQKBO8FSF0e9BVGG0QX8vC6ZQa4w==", "requires": { "@doodle3d/clipper-lib": "6.4.2-b" } @@ -23,28 +22,39 @@ "resolved": "https://registry.npmjs.org/@doodle3d/clipper-lib/-/clipper-lib-6.4.2-b.tgz", "integrity": "sha512-glELSijsD9b+/0d9iOdasBwqH3s+xPxD59tJ7aXkBx7klugygGOMXn7PB05AdhVyA1OYMj7GUCegaQa7nvLtmQ==" }, + "@doodle3d/doodle3d-api": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@doodle3d/doodle3d-api/-/doodle3d-api-1.0.5.tgz", + "integrity": "sha512-D64VhS6hSv1gM0jU+vPSoVHodyF+YNfolokPyAxeBDYtBiQZFtpvGnY49ukZ3gv7XtXlFhhRTXMex69LoCuT0Q==", + "requires": { + "eventdispatcher.js": "0.0.2", + "url-search-params-polyfill": "2.0.2", + "whatwg-fetch": "2.0.3" + } + }, "@doodle3d/doodle3d-core": { - "version": "github:doodle3d/doodle3d-core#0c4e410a27ea2df8336a956e966ee16ad8ac04d7", - "dev": true, + "version": "github:doodle3d/doodle3d-core#b9ed59c8d936a205ac3660fe6f23af66228d92bb", "requires": { "@doodle3d/cal": "0.0.8", - "@doodle3d/clipper-js": "1.0.7", + "@doodle3d/clipper-js": "1.0.10", "@doodle3d/fill-path": "1.0.7", "@doodle3d/potrace-js": "0.0.6", "@doodle3d/threejs-export-obj": "0.0.8", "@doodle3d/threejs-export-stl": "0.0.5", "@doodle3d/touch-events": "0.0.7", "babel-polyfill": "6.26.0", - "bezier-js": "2.2.3", + "bezier-js": "2.2.5", "blueimp-canvas-to-blob": "3.14.0", "bowser": "1.8.1", "fit-curve": "0.1.6", + "google-fonts-webpack-plugin": "0.4.4", "imports-loader": "0.7.1", - "jss": "9.4.0", + "jss": "9.8.0", "keycode": "2.1.9", "lodash": "4.17.4", "memoizee": "0.3.10", - "pouchdb": "6.4.0", + "normalize-wheel": "1.0.1", + "pouchdb": "6.4.2", "proptypes": "1.1.0", "raf": "3.4.0", "ramda": "0.21.0", @@ -54,8 +64,8 @@ "react-notification-system-redux": "1.2.0", "react-redux": "5.0.6", "react-resize-detector": "1.1.0", - "react-svg-inline": "2.0.1", - "redux-form": "7.2.0", + "react-svg-inline": "2.1.0", + "redux-form": "7.2.1", "redux-undo": "1.0.0-beta9-9-7", "reselect": "3.0.1", "semver": "5.4.1", @@ -66,21 +76,22 @@ }, "dependencies": { "jss": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/jss/-/jss-9.4.0.tgz", - "integrity": "sha512-ckJpElL5CimehboeLDQoHeY7mlxn0KPnPn2EZVbn6pomhfbTXiQJ6fAJXSp9rUM2hPtE0PG8Swzdy9vhB2v82w==", - "dev": true, + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/jss/-/jss-9.8.0.tgz", + "integrity": "sha512-1E9pn6k1Qd1BxKz845supoedukHuwMeBiqybCQV9l60v8JE7owkZSvVJfjw3wm50SjG1C/ABPtQ8PrGfhfrzLw==", "requires": { "is-in-browser": "1.1.3", - "symbol-observable": "1.1.0", + "symbol-observable": "1.2.0", "warning": "3.0.0" } }, "symbol-observable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.1.0.tgz", - "integrity": "sha512-dQoid9tqQ+uotGhuTKEY11X4xhyYePVnqGSoSm3OGKh2E8LZ6RPULp1uXTctk33IeERlrRJYoVSBglsL05F5Uw==", - "dev": true + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" + }, + "three-js-csg": { + "version": "github:Doodle3D/three-js-csg#a36f23da6e9be2405a9094de5709cb0ae8f58045" } } }, @@ -88,22 +99,19 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/@doodle3d/fill-path/-/fill-path-1.0.7.tgz", "integrity": "sha512-4sdgWQ28JgRsmnyy1OnuKHE+DZ8kDGpluGqFmMASh2/6dlyjp2/oXnNEgNefG4/xiEitV8AtzEij9Bijh6yNRw==", - "dev": true, "requires": { - "@doodle3d/clipper-js": "1.0.7" + "@doodle3d/clipper-js": "1.0.10" } }, "@doodle3d/potrace-js": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/@doodle3d/potrace-js/-/potrace-js-0.0.6.tgz", - "integrity": "sha512-w1+sG3ClsSaQwo3ks5wl6QLe4aWEHBe8QePq0IeAcj+lypqo770sUcWVfEZWUFBumAhSlCJg3GRc8MsycHy8LA==", - "dev": true + "integrity": "sha512-w1+sG3ClsSaQwo3ks5wl6QLe4aWEHBe8QePq0IeAcj+lypqo770sUcWVfEZWUFBumAhSlCJg3GRc8MsycHy8LA==" }, "@doodle3d/threejs-export-obj": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/@doodle3d/threejs-export-obj/-/threejs-export-obj-0.0.8.tgz", "integrity": "sha512-HVnJCvrjj3FqHJ5+CLVT1oZ0OjS2eOvrpMKjo71Jg7bdrusluIRlF7w9JdaoZs3ScWASAucu2cvTKJ+OAm3Rhw==", - "dev": true, "requires": { "jszip": "3.1.5", "three": "0.88.0" @@ -113,7 +121,6 @@ "version": "0.0.5", "resolved": "https://registry.npmjs.org/@doodle3d/threejs-export-stl/-/threejs-export-stl-0.0.5.tgz", "integrity": "sha512-GeApmYL657Dug8/+WOHGGijJbQ52dN2AWkhz9FsCe9sehZRhCg0fOg4LKXNS0XGKWMQbyumlbrmCWZrK73sfJA==", - "dev": true, "requires": { "babel-preset-env": "1.6.1", "three": "0.88.0" @@ -123,7 +130,6 @@ "version": "0.0.7", "resolved": "https://registry.npmjs.org/@doodle3d/touch-events/-/touch-events-0.0.7.tgz", "integrity": "sha512-EpL8IEGKKy2gqFFlxA4n84IeAyPTrEzle0jwmRv+mmVBzwGr6xDl5Ga5vJIrg2WcYs4Xc7qWbiKSHEXvEpDLlg==", - "dev": true, "requires": { "eventdispatcher.js": "0.0.2", "pepjs": "0.4.3" @@ -133,7 +139,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-3.0.0.tgz", "integrity": "sha512-KUWx9UWGQD12zsmLNj64/pndaz4iJh/Pj7nopgkfDG6RlCcbMZvT6+9l7dchK4idog2Is8VdC/PvNbFuFmalIQ==", - "dev": true, "requires": { "xtend": "4.0.1" } @@ -142,7 +147,6 @@ "version": "1.3.4", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz", "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=", - "dev": true, "requires": { "mime-types": "2.1.17", "negotiator": "0.6.1" @@ -151,8 +155,7 @@ "acorn": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.2.1.tgz", - "integrity": "sha512-jG0u7c4Ly+3QkkW18V+NRDN+4bWHdln30NL1ZL2AvFZZmQe/BfopYCtghCKKVBUSetZ4QKcyA0pY6/4Gw8Pv8w==", - "dev": true + "integrity": "sha512-jG0u7c4Ly+3QkkW18V+NRDN+4bWHdln30NL1ZL2AvFZZmQe/BfopYCtghCKKVBUSetZ4QKcyA0pY6/4Gw8Pv8w==" }, "acorn-dynamic-import": { "version": "2.0.2", @@ -175,7 +178,6 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.3.0.tgz", "integrity": "sha1-RBT/dKUIecII7l/cgm4ywwNUnto=", - "dev": true, "requires": { "co": "4.6.0", "fast-deep-equal": "1.0.0", @@ -229,14 +231,12 @@ "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" }, "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, "requires": { "delegates": "1.0.0", "readable-stream": "2.3.3" @@ -254,8 +254,7 @@ "argsarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/argsarray/-/argsarray-0.0.1.tgz", - "integrity": "sha1-bnIHtOzbObCviDA/pa4ivajfYcs=", - "dev": true + "integrity": "sha1-bnIHtOzbObCviDA/pa4ivajfYcs=" }, "arr-diff": { "version": "2.0.0", @@ -329,8 +328,7 @@ "asn1": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", - "dev": true + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" }, "asn1.js": { "version": "4.9.2", @@ -353,10 +351,9 @@ } }, "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 + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, "async": { "version": "2.6.0", @@ -373,29 +370,30 @@ "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", "dev": true }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "attempt-x": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/attempt-x/-/attempt-x-1.1.1.tgz", - "integrity": "sha512-hIp37ojJRRW8ExWSxxLpkDHUufk/DFfsb7/cUC1cVbBg7JV4gJTkCTRa44dlL9e5jx1P3VNrjL7QOQfi4MyltA==", - "dev": true + "integrity": "sha512-hIp37ojJRRW8ExWSxxLpkDHUufk/DFfsb7/cUC1cVbBg7JV4gJTkCTRa44dlL9e5jx1P3VNrjL7QOQfi4MyltA==" }, "aws-sign2": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", - "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", - "dev": true + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" }, "aws4": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", - "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", - "dev": true + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" }, "babel-cli": { "version": "6.24.1", @@ -488,7 +486,6 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=", - "dev": true, "requires": { "babel-helper-explode-assignable-expression": "6.24.1", "babel-runtime": "6.26.0", @@ -540,7 +537,6 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", - "dev": true, "requires": { "babel-helper-hoist-variables": "6.24.1", "babel-runtime": "6.26.0", @@ -552,7 +548,6 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", - "dev": true, "requires": { "babel-helper-function-name": "6.24.1", "babel-runtime": "6.26.0", @@ -564,7 +559,6 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dev": true, "requires": { "core-js": "2.4.1", "regenerator-runtime": "0.11.0" @@ -574,7 +568,6 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "dev": true, "requires": { "babel-runtime": "6.26.0", "esutils": "2.0.2", @@ -585,8 +578,7 @@ "regenerator-runtime": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz", - "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==", - "dev": true + "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==" } } }, @@ -594,7 +586,6 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=", - "dev": true, "requires": { "babel-runtime": "6.26.0", "babel-traverse": "6.25.0", @@ -638,7 +629,6 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", - "dev": true, "requires": { "babel-runtime": "6.26.0", "babel-types": "6.25.0" @@ -648,7 +638,6 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", - "dev": true, "requires": { "babel-runtime": "6.26.0", "babel-types": "6.25.0" @@ -658,7 +647,6 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", - "dev": true, "requires": { "babel-runtime": "6.26.0", "babel-types": "6.26.0", @@ -669,7 +657,6 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dev": true, "requires": { "core-js": "2.4.1", "regenerator-runtime": "0.11.0" @@ -679,7 +666,6 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "dev": true, "requires": { "babel-runtime": "6.26.0", "esutils": "2.0.2", @@ -690,8 +676,7 @@ "regenerator-runtime": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz", - "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==", - "dev": true + "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==" } } }, @@ -699,7 +684,6 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz", "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=", - "dev": true, "requires": { "babel-helper-function-name": "6.24.1", "babel-runtime": "6.26.0", @@ -712,7 +696,6 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", - "dev": true, "requires": { "babel-helper-optimise-call-expression": "6.24.1", "babel-messages": "6.23.0", @@ -755,7 +738,6 @@ "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", - "dev": true, "requires": { "babel-runtime": "6.26.0" } @@ -763,8 +745,7 @@ "babel-plugin-syntax-async-functions": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", - "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=", - "dev": true + "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=" }, "babel-plugin-syntax-async-generators": { "version": "6.13.0", @@ -804,8 +785,7 @@ "babel-plugin-syntax-exponentiation-operator": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", - "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=", - "dev": true + "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=" }, "babel-plugin-syntax-export-extensions": { "version": "6.13.0", @@ -840,8 +820,7 @@ "babel-plugin-syntax-trailing-function-commas": { "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", - "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=", - "dev": true + "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=" }, "babel-plugin-transform-async-generator-functions": { "version": "6.24.1", @@ -858,7 +837,6 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=", - "dev": true, "requires": { "babel-helper-remap-async-to-generator": "6.24.1", "babel-plugin-syntax-async-functions": "6.13.0", @@ -914,7 +892,6 @@ "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", - "dev": true, "requires": { "babel-runtime": "6.26.0" } @@ -923,7 +900,6 @@ "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", - "dev": true, "requires": { "babel-runtime": "6.26.0" } @@ -932,7 +908,6 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", - "dev": true, "requires": { "babel-runtime": "6.26.0", "babel-template": "6.26.0", @@ -945,7 +920,6 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "dev": true, "requires": { "chalk": "1.1.3", "esutils": "2.0.2", @@ -956,7 +930,6 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dev": true, "requires": { "core-js": "2.4.1", "regenerator-runtime": "0.11.0" @@ -966,7 +939,6 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", - "dev": true, "requires": { "babel-runtime": "6.26.0", "babel-traverse": "6.26.0", @@ -979,7 +951,6 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", - "dev": true, "requires": { "babel-code-frame": "6.26.0", "babel-messages": "6.23.0", @@ -996,7 +967,6 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "dev": true, "requires": { "babel-runtime": "6.26.0", "esutils": "2.0.2", @@ -1007,14 +977,12 @@ "babylon": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", - "dev": true + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" }, "regenerator-runtime": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz", - "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==", - "dev": true + "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==" } } }, @@ -1022,7 +990,6 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", - "dev": true, "requires": { "babel-helper-define-map": "6.26.0", "babel-helper-function-name": "6.24.1", @@ -1039,7 +1006,6 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", - "dev": true, "requires": { "babel-runtime": "6.26.0", "babel-template": "6.25.0" @@ -1049,7 +1015,6 @@ "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", - "dev": true, "requires": { "babel-runtime": "6.26.0" } @@ -1058,7 +1023,6 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", - "dev": true, "requires": { "babel-runtime": "6.26.0", "babel-types": "6.25.0" @@ -1068,7 +1032,6 @@ "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", - "dev": true, "requires": { "babel-runtime": "6.26.0" } @@ -1077,7 +1040,6 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", - "dev": true, "requires": { "babel-helper-function-name": "6.24.1", "babel-runtime": "6.26.0", @@ -1088,7 +1050,6 @@ "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", - "dev": true, "requires": { "babel-runtime": "6.26.0" } @@ -1097,7 +1058,6 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", - "dev": true, "requires": { "babel-plugin-transform-es2015-modules-commonjs": "6.26.0", "babel-runtime": "6.26.0", @@ -1108,7 +1068,6 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz", "integrity": "sha1-DYOUApt9xqvhqX7xgeAHWN0uXYo=", - "dev": true, "requires": { "babel-plugin-transform-strict-mode": "6.24.1", "babel-runtime": "6.26.0", @@ -1120,7 +1079,6 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "dev": true, "requires": { "chalk": "1.1.3", "esutils": "2.0.2", @@ -1131,7 +1089,6 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dev": true, "requires": { "core-js": "2.4.1", "regenerator-runtime": "0.11.0" @@ -1141,7 +1098,6 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", - "dev": true, "requires": { "babel-runtime": "6.26.0", "babel-traverse": "6.26.0", @@ -1154,7 +1110,6 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", - "dev": true, "requires": { "babel-code-frame": "6.26.0", "babel-messages": "6.23.0", @@ -1171,7 +1126,6 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "dev": true, "requires": { "babel-runtime": "6.26.0", "esutils": "2.0.2", @@ -1182,14 +1136,12 @@ "babylon": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", - "dev": true + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" }, "regenerator-runtime": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz", - "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==", - "dev": true + "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==" } } }, @@ -1197,7 +1149,6 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", - "dev": true, "requires": { "babel-helper-hoist-variables": "6.24.1", "babel-runtime": "6.26.0", @@ -1208,7 +1159,6 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", - "dev": true, "requires": { "babel-plugin-transform-es2015-modules-amd": "6.24.1", "babel-runtime": "6.26.0", @@ -1219,7 +1169,6 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", - "dev": true, "requires": { "babel-helper-replace-supers": "6.24.1", "babel-runtime": "6.26.0" @@ -1229,7 +1178,6 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", - "dev": true, "requires": { "babel-helper-call-delegate": "6.24.1", "babel-helper-get-function-arity": "6.24.1", @@ -1243,7 +1191,6 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", - "dev": true, "requires": { "babel-runtime": "6.26.0", "babel-types": "6.25.0" @@ -1253,7 +1200,6 @@ "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", - "dev": true, "requires": { "babel-runtime": "6.26.0" } @@ -1262,7 +1208,6 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", - "dev": true, "requires": { "babel-helper-regex": "6.26.0", "babel-runtime": "6.26.0", @@ -1273,7 +1218,6 @@ "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", - "dev": true, "requires": { "babel-runtime": "6.26.0" } @@ -1282,7 +1226,6 @@ "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", - "dev": true, "requires": { "babel-runtime": "6.26.0" } @@ -1291,7 +1234,6 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", - "dev": true, "requires": { "babel-helper-regex": "6.26.0", "babel-runtime": "6.26.0", @@ -1302,7 +1244,6 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=", - "dev": true, "requires": { "babel-helper-builder-binary-assignment-operator-visitor": "6.24.1", "babel-plugin-syntax-exponentiation-operator": "6.13.0", @@ -1411,7 +1352,6 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", - "dev": true, "requires": { "regenerator-transform": "0.10.1" } @@ -1429,7 +1369,6 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", - "dev": true, "requires": { "babel-runtime": "6.26.0", "babel-types": "6.25.0" @@ -1439,7 +1378,6 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", - "dev": true, "requires": { "babel-runtime": "6.26.0", "core-js": "2.5.3", @@ -1450,7 +1388,6 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dev": true, "requires": { "core-js": "2.5.3", "regenerator-runtime": "0.11.1" @@ -1459,16 +1396,14 @@ "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" } } }, "core-js": { "version": "2.5.3", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz", - "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=", - "dev": true + "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=" } } }, @@ -1476,7 +1411,6 @@ "version": "1.6.1", "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.6.1.tgz", "integrity": "sha512-W6VIyA6Ch9ePMI7VptNn2wBM6dbG0eSz25HEiL40nQXCsXGTGZSTZu1Iap+cj3Q0S5a7T9+529l/5Bkvd+afNA==", - "dev": true, "requires": { "babel-plugin-check-es2015-constants": "6.22.0", "babel-plugin-syntax-trailing-function-commas": "6.22.0", @@ -1709,23 +1643,20 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", - "dev": true, "optional": true, "requires": { "tweetnacl": "0.14.5" } }, "bezier-js": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/bezier-js/-/bezier-js-2.2.3.tgz", - "integrity": "sha1-xVdBFqSjVkpxU41z4LDVFdqN3sU=", - "dev": true + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/bezier-js/-/bezier-js-2.2.5.tgz", + "integrity": "sha512-HGh+GevPguxrAmnWF2/A+8c8FEatnKcE6WttpYWA5fn1CfpJz4reFbr11DuyFs2gwaIo9vF7aVXW2xg1iaqvyg==" }, "big.js": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", - "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", - "dev": true + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==" }, "binary-extensions": { "version": "1.8.0", @@ -1736,14 +1667,12 @@ "bindings": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.0.tgz", - "integrity": "sha512-DpLh5EzMR2kzvX1KIlVC0VkC3iZtHKTgdtZ0a3pglBZdaQFjt5S9g9xd1lE+YvXyfd6mtCeRnrUfOLYiTMlNSw==", - "dev": true + "integrity": "sha512-DpLh5EzMR2kzvX1KIlVC0VkC3iZtHKTgdtZ0a3pglBZdaQFjt5S9g9xd1lE+YvXyfd6mtCeRnrUfOLYiTMlNSw==" }, "bl": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.1.tgz", "integrity": "sha1-ysMo977kVzDUBLaSID/LWQ4XLV4=", - "dev": true, "requires": { "readable-stream": "2.3.3" } @@ -1757,8 +1686,7 @@ "blueimp-canvas-to-blob": { "version": "3.14.0", "resolved": "https://registry.npmjs.org/blueimp-canvas-to-blob/-/blueimp-canvas-to-blob-3.14.0.tgz", - "integrity": "sha512-i6I2CiX1VR8YwUNYBo+dM8tg89ns4TTHxSpWjaDeHKcYS3yFalpLCwDaY21/EsJMufLy2tnG4j0JN5L8OVNkKQ==", - "dev": true + "integrity": "sha512-i6I2CiX1VR8YwUNYBo+dM8tg89ns4TTHxSpWjaDeHKcYS3yFalpLCwDaY21/EsJMufLy2tnG4j0JN5L8OVNkKQ==" }, "bn.js": { "version": "4.11.8", @@ -1770,7 +1698,6 @@ "version": "1.18.2", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", - "dev": true, "requires": { "bytes": "3.0.0", "content-type": "1.0.4", @@ -1788,7 +1715,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "requires": { "ms": "2.0.0" } @@ -1816,12 +1742,11 @@ "dev": true }, "boom": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", - "dev": true, + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", "requires": { - "hoek": "2.16.3" + "hoek": "4.2.0" } }, "bowser": { @@ -1935,7 +1860,6 @@ "version": "2.8.0", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-2.8.0.tgz", "integrity": "sha512-iiWHM1Et6Q4TQpB7Ar6pxuM3TNMXasVJY4Y/oh3q38EwR3Z+IdZ9MyVf7PI4MJFB4xpwMcZgs9bEUnPG2E3TCA==", - "dev": true, "requires": { "caniuse-lite": "1.0.30000760", "electron-to-chromium": "1.3.27" @@ -1952,11 +1876,15 @@ "isarray": "1.0.0" } }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + }, "buffer-from": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-0.1.1.tgz", "integrity": "sha1-V7GLHaChnsBvM4N6UnWiQjUb114=", - "dev": true, "requires": { "is-array-buffer-x": "1.7.0" } @@ -1988,14 +1916,12 @@ "bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", - "dev": true + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" }, "cached-constructors-x": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/cached-constructors-x/-/cached-constructors-x-1.0.0.tgz", - "integrity": "sha512-JVP0oilYlPgBTD8bkQ+of7hSIJRtydCCJiMtzdRMXVQ98gdj0NyrJTZzbu5wtlO26Ev/1HXRTtbBNsVlLJ3+3A==", - "dev": true + "integrity": "sha512-JVP0oilYlPgBTD8bkQ+of7hSIJRtydCCJiMtzdRMXVQ98gdj0NyrJTZzbu5wtlO26Ev/1HXRTtbBNsVlLJ3+3A==" }, "camel-case": { "version": "3.0.0", @@ -2034,14 +1960,12 @@ "caniuse-lite": { "version": "1.0.30000760", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000760.tgz", - "integrity": "sha1-7HIDlXQvHH7IlH/W3SYE53qPmP8=", - "dev": true + "integrity": "sha1-7HIDlXQvHH7IlH/W3SYE53qPmP8=" }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, "center-align": { "version": "0.1.3", @@ -2095,8 +2019,7 @@ "chownr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz", - "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", - "dev": true + "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=" }, "cipher-base": { "version": "1.0.4", @@ -2111,8 +2034,7 @@ "classnames": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.5.tgz", - "integrity": "sha1-+zgB1FNGdknvNgPH1hoCvRKb3m0=", - "dev": true + "integrity": "sha1-+zgB1FNGdknvNgPH1hoCvRKb3m0=" }, "clean-css": { "version": "4.1.9", @@ -2137,26 +2059,22 @@ "clone-buffer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", - "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", - "dev": true + "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=" }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" }, "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 + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "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, "requires": { "delayed-stream": "1.0.0" } @@ -2164,8 +2082,7 @@ "commander": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", - "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", - "dev": true + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==" }, "commondir": { "version": "1.0.1", @@ -2232,8 +2149,7 @@ "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 + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, "constants-browserify": { "version": "1.0.0", @@ -2244,14 +2160,12 @@ "content-disposition": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", - "dev": true + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" }, "content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "dev": true + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" }, "convert-source-map": { "version": "1.5.0", @@ -2262,14 +2176,12 @@ "cookie": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", - "dev": true + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" }, "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", - "dev": true + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, "core-js": { "version": "2.4.1", @@ -2279,8 +2191,7 @@ "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "create-ecdh": { "version": "4.0.0", @@ -2340,12 +2251,21 @@ } }, "cryptiles": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", - "dev": true, + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", "requires": { - "boom": "2.10.1" + "boom": "5.2.0" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "requires": { + "hoek": "4.2.0" + } + } } }, "crypto-browserify": { @@ -2414,7 +2334,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", - "dev": true, "requires": { "es5-ext": "0.10.35" } @@ -2423,17 +2342,8 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, "requires": { "assert-plus": "1.0.0" - }, - "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 - } } }, "date-now": { @@ -2456,23 +2366,25 @@ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + }, "deep-equal": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", - "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", - "dev": true + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=" }, "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 + "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=" }, "deferred-leveldown": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-2.0.3.tgz", "integrity": "sha512-8c2Hv+vIwKNc7qqy4zE3t5DIsln+FQnudcyjLYstHwLFg7XnXZT/H8gQb8lj6xi8xqGM0Bz633ZWcCkonycBTA==", - "dev": true, "requires": { "abstract-leveldown": "3.0.0" } @@ -2512,20 +2424,17 @@ "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 + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, "delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "dev": true + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" }, "depd": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", - "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=", - "dev": true + "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" }, "des.js": { "version": "1.0.0", @@ -2540,8 +2449,7 @@ "destroy": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", - "dev": true + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, "detect-indent": { "version": "4.0.0", @@ -2552,6 +2460,11 @@ "repeating": "2.0.1" } }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" + }, "detect-node": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.3.tgz", @@ -2668,14 +2581,17 @@ "double-ended-queue": { "version": "2.1.0-0", "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz", - "integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=", - "dev": true + "integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=" + }, + "duplexer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=" }, "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, "requires": { "jsbn": "0.1.1" @@ -2684,14 +2600,17 @@ "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", - "dev": true + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "ejs": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.5.7.tgz", + "integrity": "sha1-zIcsFoiArjxxiXYv1f/ACJbJUYo=" }, "electron-to-chromium": { "version": "1.3.27", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.27.tgz", - "integrity": "sha1-eOy4o5kGYYe7N07t412ccFZagD0=", - "dev": true + "integrity": "sha1-eOy4o5kGYYe7N07t412ccFZagD0=" }, "elliptic": { "version": "6.4.0", @@ -2711,14 +2630,12 @@ "emojis-list": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", - "dev": true + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" }, "encodeurl": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz", - "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA=", - "dev": true + "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA=" }, "encoding": { "version": "0.1.12", @@ -2729,10 +2646,9 @@ } }, "encoding-down": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-3.0.0.tgz", - "integrity": "sha1-IGjLZ7E3G14frJtfF44FpVUr+l4=", - "dev": true, + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-3.0.1.tgz", + "integrity": "sha512-uvx+39YNqiPLqhXAvOSGBVy/oYBh4p2ShwG9YFCipwgfOhnVIOxuOPE3R9dEGM44bn0VHIrC3ojXq6lNf2ulwg==", "requires": { "abstract-leveldown": "3.0.0", "level-codec": "8.0.0", @@ -2742,16 +2658,14 @@ "level-codec": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-8.0.0.tgz", - "integrity": "sha512-gNZlo1HRHz0BWxzGCyNf7xntAs2HKOPvvRBWtXsoDvEX4vMYnSTBS6ZnxoaiX7nhxSBPpegRa8CQ/hnfGBKk3Q==", - "dev": true + "integrity": "sha512-gNZlo1HRHz0BWxzGCyNf7xntAs2HKOPvvRBWtXsoDvEX4vMYnSTBS6ZnxoaiX7nhxSBPpegRa8CQ/hnfGBKk3Q==" } } }, "end-of-stream": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.0.tgz", - "integrity": "sha1-epDYM+/abPpurA9JSduw+tOmMgY=", - "dev": true, + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "requires": { "once": "1.4.0" } @@ -2760,7 +2674,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/end-stream/-/end-stream-0.1.0.tgz", "integrity": "sha1-MgA/P0OKKwFDFoE3+PpumGbIHtU=", - "dev": true, "requires": { "write-stream": "0.4.3" } @@ -2787,7 +2700,6 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz", "integrity": "sha1-uJbiOp5ei6M4cfyZar02NfyaHH0=", - "dev": true, "requires": { "prr": "0.0.0" } @@ -2829,23 +2741,20 @@ "version": "0.10.35", "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.35.tgz", "integrity": "sha1-GO6FjOajxFx9eekcFfzKnsVoSU8=", - "dev": true, "requires": { "es6-iterator": "2.0.3", "es6-symbol": "3.1.1" } }, "es6-error": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.0.2.tgz", - "integrity": "sha1-7sXHJurO9Rt/a3PCDbbhsTsGnJg=", - "dev": true + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==" }, "es6-iterator": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "dev": true, "requires": { "d": "1.0.0", "es5-ext": "0.10.35", @@ -2869,8 +2778,7 @@ "es6-promise": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz", - "integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=", - "dev": true + "integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=" }, "es6-set": { "version": "0.1.5", @@ -2889,7 +2797,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", - "dev": true, "requires": { "d": "1.0.0", "es5-ext": "0.10.35" @@ -2910,8 +2817,7 @@ "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" }, "escape-string-regexp": { "version": "1.0.5", @@ -2960,14 +2866,12 @@ "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "dev": true + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, "event-emitter": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", - "dev": true, "requires": { "d": "1.0.0", "es5-ext": "0.10.35" @@ -2976,8 +2880,7 @@ "eventdispatcher.js": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/eventdispatcher.js/-/eventdispatcher.js-0.0.2.tgz", - "integrity": "sha1-wntZzkEEa2iUEu3M/UzYr8ZM2DU=", - "dev": true + "integrity": "sha1-wntZzkEEa2iUEu3M/UzYr8ZM2DU=" }, "eventemitter3": { "version": "1.2.0", @@ -3046,14 +2949,12 @@ "expand-template": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-1.1.0.tgz", - "integrity": "sha512-kkjwkMqj0h4w/sb32ERCDxCQkREMCAgS39DscDnSwDsbxnwwM1BTZySdC3Bn1lhY7vL08n9GoO/fVTynjDgRyQ==", - "dev": true + "integrity": "sha512-kkjwkMqj0h4w/sb32ERCDxCQkREMCAgS39DscDnSwDsbxnwwM1BTZySdC3Bn1lhY7vL08n9GoO/fVTynjDgRyQ==" }, "express": { "version": "4.16.2", "resolved": "https://registry.npmjs.org/express/-/express-4.16.2.tgz", "integrity": "sha1-41xt/i1kt9ygpc1PIXgb4ymeB2w=", - "dev": true, "requires": { "accepts": "1.3.4", "array-flatten": "1.1.1", @@ -3090,14 +2991,12 @@ "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", - "dev": true + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "requires": { "ms": "2.0.0" } @@ -3107,8 +3006,7 @@ "extend": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", - "dev": true + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" }, "extglob": { "version": "0.3.2", @@ -3122,26 +3020,22 @@ "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, "fast-deep-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", - "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=", - "dev": true + "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=" }, "fast-future": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/fast-future/-/fast-future-1.0.2.tgz", - "integrity": "sha1-hDWpqqAteSSNF9cE52JZMB2ZKAo=", - "dev": true + "integrity": "sha1-hDWpqqAteSSNF9cE52JZMB2ZKAo=" }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, "faye-websocket": { "version": "0.10.0", @@ -3173,6 +3067,14 @@ } } }, + "fd-slicer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", + "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "requires": { + "pend": "1.2.0" + } + }, "file-saver": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-1.3.3.tgz", @@ -3184,6 +3086,11 @@ "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", "dev": true }, + "filesize": { + "version": "3.5.11", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.5.11.tgz", + "integrity": "sha512-ZH7loueKBoDb7yG9esn1U+fgq7BzlzW6NRi5/rMdxIZ05dj7GFD/Xc5rq2CDt5Yq86CyfSYVyx4242QQNZbx1g==" + }, "fill-range": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", @@ -3201,7 +3108,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", - "dev": true, "requires": { "debug": "2.6.9", "encodeurl": "1.0.1", @@ -3216,7 +3122,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "requires": { "ms": "2.0.0" } @@ -3247,8 +3152,7 @@ "fit-curve": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/fit-curve/-/fit-curve-0.1.6.tgz", - "integrity": "sha1-w72+b1oqO+j4Aerr2kBpGRJWqVs=", - "dev": true + "integrity": "sha1-w72+b1oqO+j4Aerr2kBpGRJWqVs=" }, "for-in": { "version": "1.0.2", @@ -3274,14 +3178,12 @@ "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" }, "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, + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", + "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", "requires": { "asynckit": "0.4.0", "combined-stream": "1.0.5", @@ -3291,14 +3193,12 @@ "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", - "dev": true + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" }, "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "dev": true + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, "fs-readdir-recursive": { "version": "1.0.0", @@ -4081,14 +3981,6 @@ } } }, - "string_decoder": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, "string-width": { "version": "1.0.2", "bundled": true, @@ -4099,6 +3991,14 @@ "strip-ansi": "3.0.1" } }, + "string_decoder": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, "stringstream": { "version": "0.0.5", "bundled": true, @@ -4221,7 +4121,6 @@ "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "dev": true, "requires": { "aproba": "1.2.0", "console-control-strings": "1.1.0", @@ -4237,7 +4136,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, "requires": { "code-point-at": "1.1.0", "is-fullwidth-code-point": "1.0.0", @@ -4268,24 +4166,14 @@ "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, "requires": { "assert-plus": "1.0.0" - }, - "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 - } } }, "github-from-package": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=", - "dev": true + "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=" }, "glob": { "version": "7.1.2", @@ -4338,12 +4226,47 @@ "pinkie-promise": "2.0.1" } }, + "google-fonts-webpack-plugin": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/google-fonts-webpack-plugin/-/google-fonts-webpack-plugin-0.4.4.tgz", + "integrity": "sha512-+e2D9/DVBG9EDydRovzoqMZ658SsTBGbC0c65GyZqkwNvdj8vRSYQKXqbz7/yt7QaXsCPT1MpH45r3ivWOitcw==", + "requires": { + "lodash": "4.17.4", + "node-fetch": "1.7.3", + "webpack-sources": "0.2.3", + "yauzl": "2.9.1" + }, + "dependencies": { + "source-list-map": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-1.1.2.tgz", + "integrity": "sha1-mIkBnRAkzOVc3AaUmDN+9hhqEaE=" + }, + "webpack-sources": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-0.2.3.tgz", + "integrity": "sha1-F8Yr+vE8cH+dAsR54Nzd6DgGl/s=", + "requires": { + "source-list-map": "1.1.2", + "source-map": "0.5.6" + } + } + } + }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", "dev": true }, + "gzip-size": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-3.0.0.tgz", + "integrity": "sha1-VGGI6b3DN/Zzdy+BZgRks4nc5SA=", + "requires": { + "duplexer": "0.1.1" + } + }, "handle-thing": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-1.2.5.tgz", @@ -4351,31 +4274,17 @@ "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 + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" }, "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, + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" - }, - "dependencies": { - "ajv": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", - "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", - "dev": true, - "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" - } - } + "ajv": "5.3.0", + "har-schema": "2.0.0" } }, "has": { @@ -4405,7 +4314,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/has-own-property-x/-/has-own-property-x-3.2.0.tgz", "integrity": "sha512-HtRQTYpRFz/YVaQ7jh2mU5iorMAxFcML9FNOLMI1f8VNJ2K0hpOlXoi1a+nmVl6oUcGnhd6zYOFAVe7NUFStyQ==", - "dev": true, "requires": { "cached-constructors-x": "1.0.0", "to-object-x": "1.5.0", @@ -4415,14 +4323,12 @@ "has-symbol-support-x": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.1.tgz", - "integrity": "sha512-JkaetveU7hFbqnAC1EV1sF4rlojU2D4Usc5CmS69l6NfmPDnpnFUegzFg33eDkkpNCxZ0mQp65HwUDrNFS/8MA==", - "dev": true + "integrity": "sha512-JkaetveU7hFbqnAC1EV1sF4rlojU2D4Usc5CmS69l6NfmPDnpnFUegzFg33eDkkpNCxZ0mQp65HwUDrNFS/8MA==" }, "has-to-string-tag-x": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", - "dev": true, "requires": { "has-symbol-support-x": "1.4.1" } @@ -4430,8 +4336,7 @@ "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 + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" }, "hash-base": { "version": "2.0.2", @@ -4453,15 +4358,14 @@ } }, "hawk": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", - "dev": true, + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" + "boom": "4.3.1", + "cryptiles": "3.1.2", + "hoek": "4.2.0", + "sntp": "2.1.0" } }, "he": { @@ -4482,10 +4386,9 @@ } }, "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", - "dev": true + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz", + "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==" }, "hoist-non-react-statics": { "version": "1.2.0", @@ -4633,7 +4536,6 @@ "version": "1.6.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", - "dev": true, "requires": { "depd": "1.1.1", "inherits": "2.0.3", @@ -4644,8 +4546,7 @@ "setprototypeof": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", - "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=", - "dev": true + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" } } }, @@ -4695,12 +4596,11 @@ } }, "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, + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "requires": { - "assert-plus": "0.2.0", + "assert-plus": "1.0.0", "jsprim": "1.4.1", "sshpk": "1.13.1" } @@ -4730,8 +4630,7 @@ "immediate": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", - "dev": true + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=" }, "import-local": { "version": "0.1.1", @@ -4767,7 +4666,6 @@ "version": "0.7.1", "resolved": "https://registry.npmjs.org/imports-loader/-/imports-loader-0.7.1.tgz", "integrity": "sha1-8gS180cCoywdt9SNidXoZ6BEElM=", - "dev": true, "requires": { "loader-utils": "1.1.0", "source-map": "0.5.6" @@ -4791,8 +4689,7 @@ "infinity-x": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/infinity-x/-/infinity-x-1.0.0.tgz", - "integrity": "sha512-wjy2TupBtZ+aAniKt+xs/PO0xOkuaL6wBysUKbgD7aL1PMW/qY5xXDG59zXZ7dU+gk3zwXOu4yIEWPCEFBTgHQ==", - "dev": true + "integrity": "sha512-wjy2TupBtZ+aAniKt+xs/PO0xOkuaL6wBysUKbgD7aL1PMW/qY5xXDG59zXZ7dU+gk3zwXOu4yIEWPCEFBTgHQ==" }, "inflight": { "version": "1.0.6", @@ -4807,14 +4704,12 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "ini": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "dev": true + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, "inline-style-prefixer": { "version": "3.0.8", @@ -4863,14 +4758,12 @@ "ipaddr.js": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz", - "integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A=", - "dev": true + "integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A=" }, "is-array-buffer-x": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/is-array-buffer-x/-/is-array-buffer-x-1.7.0.tgz", "integrity": "sha512-ufSZRMY2WZX5xyNvk0NOZAG7cgi35B/sGQDGqv8w0X7MoQ2GC9vedanJhuYTPaC4PUCqLQsda1w7NF+dPZmAJw==", - "dev": true, "requires": { "attempt-x": "1.1.1", "has-to-string-tag-x": "1.4.1", @@ -4918,8 +4811,7 @@ "is-date-object": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", - "dev": true + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" }, "is-dotfile": { "version": "1.0.3", @@ -4952,7 +4844,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-falsey-x/-/is-falsey-x-1.0.1.tgz", "integrity": "sha512-XWNZC4A+3FX1ECoMjspuEFgSdio82IWjqY/suE0gZ10QA7nzHd/KraRq7Tc5VEHtFRgTRyTdY6W+ykPrDnyoAQ==", - "dev": true, "requires": { "to-boolean-x": "1.0.1" } @@ -4970,7 +4861,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/is-finite-x/-/is-finite-x-3.0.2.tgz", "integrity": "sha512-HyFrxJZsgmP5RtR1PVlVvHSP4VslZOqr4uoq4x3rDrSOFaYp4R9tfmiWtAzQxPzixXhac3cYEno3NuVn0OHk2Q==", - "dev": true, "requires": { "infinity-x": "1.0.0", "is-nan-x": "1.0.1" @@ -4980,7 +4870,6 @@ "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, "requires": { "number-is-nan": "1.0.1" } @@ -4994,7 +4883,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/is-function-x/-/is-function-x-3.3.0.tgz", "integrity": "sha512-SreSSU1dlgYaXR5c0mm4qJHKYHIiGiEY+7Cd8/aRLLoMP/VvofD2XcWgBnP833ajpU5XzXbUSpfysnfKZLJFlg==", - "dev": true, "requires": { "attempt-x": "1.1.1", "has-to-string-tag-x": "1.4.1", @@ -5024,7 +4912,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-index-x/-/is-index-x-1.1.0.tgz", "integrity": "sha512-qULKLMepQLGC8rSVdi8uF2vI4LiDrU9XSDg1D+Aa657GIB7GV1jHpga7uXgQvkt/cpQ5mVBHUFTpSehYSqT6+A==", - "dev": true, "requires": { "math-clamp-x": "1.2.0", "max-safe-integer": "1.0.1", @@ -5036,14 +4923,12 @@ "is-nan-x": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-nan-x/-/is-nan-x-1.0.1.tgz", - "integrity": "sha512-VfNJgfuT8USqKCYQss8g7sFvCzDnL+OOVMQoXhVoulZAyp0ZTj3oyZaaPrn2dxepAkKSQI2BiKHbBabX1DqVtw==", - "dev": true + "integrity": "sha512-VfNJgfuT8USqKCYQss8g7sFvCzDnL+OOVMQoXhVoulZAyp0ZTj3oyZaaPrn2dxepAkKSQI2BiKHbBabX1DqVtw==" }, "is-nil-x": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/is-nil-x/-/is-nil-x-1.4.1.tgz", "integrity": "sha512-cfTKWI5iSR04SSCzzugTH5tS2rYG7kwI8yl/AqWkyuxZ7k55cbA47Y7Lezdg1N9aaELd+UxLg628bdQeNQ6BUw==", - "dev": true, "requires": { "lodash.isnull": "3.0.0", "validate.io-undefined": "1.0.3" @@ -5062,7 +4947,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/is-object-like-x/-/is-object-like-x-1.6.0.tgz", "integrity": "sha512-mc3dBMv1jEOdk0f1i2RkJFsZDux0MuHqGwHOoRo770ShUOf4VE6tWThAW8dAZARr9a5RN+iNX1yzMDA5ad1clQ==", - "dev": true, "requires": { "is-function-x": "3.3.0", "is-primitive": "2.0.0" @@ -5116,14 +5000,12 @@ "is-primitive": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", - "dev": true + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=" }, "is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", - "dev": true + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" }, "is-regex": { "version": "1.0.4", @@ -5142,20 +5024,17 @@ "is-string": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.4.tgz", - "integrity": "sha1-zDqbaYV9Yh6WNyWiTK7shzuCbmQ=", - "dev": true + "integrity": "sha1-zDqbaYV9Yh6WNyWiTK7shzuCbmQ=" }, "is-symbol": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", - "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", - "dev": true + "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=" }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, "is-utf8": { "version": "0.2.1", @@ -5172,8 +5051,7 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "isexe": { "version": "2.0.0", @@ -5202,8 +5080,7 @@ "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 + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "js-tokens": { "version": "3.0.2", @@ -5224,7 +5101,6 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true, "optional": true }, "jsesc": { @@ -5242,29 +5118,17 @@ "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" }, "json-schema-traverse": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", - "dev": 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, - "requires": { - "jsonify": "0.0.0" - } + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" }, "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 + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, "json3": { "version": "3.3.2", @@ -5275,33 +5139,17 @@ "json5": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "dev": true - }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", - "dev": true + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", "json-schema": "0.2.3", "verror": "1.10.0" - }, - "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 - } } }, "jss": { @@ -5390,7 +5238,6 @@ "version": "3.1.5", "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.1.5.tgz", "integrity": "sha512-5W8NUaFRFRqTOL7ZDDrx5qWHJyBXy6velVudIzQUSoqAAYqzSh2Z7/m0Rf1QbmQJccegD0r+YZxBjzqoBiEeJQ==", - "dev": true, "requires": { "core-js": "2.3.0", "es6-promise": "3.0.2", @@ -5402,14 +5249,12 @@ "core-js": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.3.0.tgz", - "integrity": "sha1-+rg/uwstjchfpjbEudNMdUIMbWU=", - "dev": true + "integrity": "sha1-+rg/uwstjchfpjbEudNMdUIMbWU=" }, "readable-stream": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", - "dev": true, "requires": { "core-util-is": "1.0.2", "inherits": "2.0.3", @@ -5422,8 +5267,7 @@ "string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" } } }, @@ -5466,7 +5310,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/level/-/level-2.1.1.tgz", "integrity": "sha512-jhsItEs/L5bf5ctKsvIPcMzeh4nwXxnL3Tsxm4E9My07jcFfqEYwKP57Y9AZu7tmtECdyK6bvCqoClwuOBuY9w==", - "dev": true, "requires": { "level-packager": "2.1.0", "leveldown": "2.1.1" @@ -5475,14 +5318,12 @@ "level-codec": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-7.0.1.tgz", - "integrity": "sha512-Ua/R9B9r3RasXdRmOtd+t9TCOEIIlts+TN/7XTT2unhDaL6sJn83S3rUyljbr6lVtw49N3/yA0HHjpV6Kzb2aQ==", - "dev": true + "integrity": "sha512-Ua/R9B9r3RasXdRmOtd+t9TCOEIIlts+TN/7XTT2unhDaL6sJn83S3rUyljbr6lVtw49N3/yA0HHjpV6Kzb2aQ==" }, "level-errors": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-1.1.2.tgz", "integrity": "sha512-Sw/IJwWbPKF5Ai4Wz60B52yj0zYeqzObLh8k1Tk88jVmD51cJSKWSYpRyhVIvFzZdvsPqlH5wfhp/yxdsaQH4w==", - "dev": true, "requires": { "errno": "0.1.4" } @@ -5491,7 +5332,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-2.0.0.tgz", "integrity": "sha512-TWOYw8HR5mhj6xwoVLo0yu26RPL6v28KgvhK1kY1CJf9LyL+rJXjx99zhORTYhN9ysOBIH+iaxAiqRteA+C1/g==", - "dev": true, "requires": { "inherits": "2.0.3", "readable-stream": "2.3.3", @@ -5502,9 +5342,8 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/level-packager/-/level-packager-2.1.0.tgz", "integrity": "sha512-I97zvGOZ6fJ9OFfYv+QmgBpDWbC+UaP5ERJ3oraTyk1v+ABAL4tazris5ym5qL2iLe+qNjXNM/iP8LQcoZMEWw==", - "dev": true, "requires": { - "encoding-down": "3.0.0", + "encoding-down": "3.0.1", "levelup": "2.0.1" } }, @@ -5512,7 +5351,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/level-write-stream/-/level-write-stream-1.0.0.tgz", "integrity": "sha1-P3+7Z5pVE3wP6zA97nZuEu4Twdw=", - "dev": true, "requires": { "end-stream": "0.1.0" } @@ -5521,20 +5359,18 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-2.1.1.tgz", "integrity": "sha512-JNMCTSchq1YtQLMGePmT07UE7hIIYR4GHpZI7+nUXbM9XgNtRAwcBGhnyJyITwpTILTkUcNPBKZ9lZmTUj2E3g==", - "dev": true, "requires": { "abstract-leveldown": "3.0.0", "bindings": "1.3.0", "fast-future": "1.0.2", "nan": "2.8.0", - "prebuild-install": "2.4.1" + "prebuild-install": "2.5.0" }, "dependencies": { "nan": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.8.0.tgz", - "integrity": "sha1-7XFfP+neArV6XmJS2QqWZ14fCFo=", - "dev": true + "integrity": "sha1-7XFfP+neArV6XmJS2QqWZ14fCFo=" } } }, @@ -5542,7 +5378,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/levelup/-/levelup-2.0.1.tgz", "integrity": "sha1-PckbPmMtN8nlRiOchkEYsATJ+GA=", - "dev": true, "requires": { "deferred-leveldown": "2.0.3", "level-errors": "1.1.2", @@ -5554,7 +5389,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", "integrity": "sha1-mkNrLMd0bKWd56QfpGmz77dr2H4=", - "dev": true, "requires": { "immediate": "3.0.6" } @@ -5581,7 +5415,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", - "dev": true, "requires": { "big.js": "3.2.0", "emojis-list": "2.1.0", @@ -5614,14 +5447,12 @@ "lodash-es": { "version": "4.17.4", "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.4.tgz", - "integrity": "sha1-3MHXVS4VCgZABzupyzHXDwMpUOc=", - "dev": true + "integrity": "sha1-3MHXVS4VCgZABzupyzHXDwMpUOc=" }, "lodash.isnull": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash.isnull/-/lodash.isnull-3.0.0.tgz", - "integrity": "sha1-+vvlnqHcon7teGU0A53YTC4HxW4=", - "dev": true + "integrity": "sha1-+vvlnqHcon7teGU0A53YTC4HxW4=" }, "lodash.merge": { "version": "4.6.0", @@ -5683,7 +5514,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", - "dev": true, "requires": { "es5-ext": "0.10.35" } @@ -5691,8 +5521,7 @@ "ltgt": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.0.tgz", - "integrity": "sha1-tlul/LNJopkkyOMz98alVi8uSEI=", - "dev": true + "integrity": "sha1-tlul/LNJopkkyOMz98alVi8uSEI=" }, "map-obj": { "version": "1.0.1", @@ -5718,11 +5547,53 @@ "warning": "3.0.0" } }, + "material-ui-icons": { + "version": "1.0.0-beta.17", + "resolved": "https://registry.npmjs.org/material-ui-icons/-/material-ui-icons-1.0.0-beta.17.tgz", + "integrity": "sha1-XxmvVKLZnu7zR6VUFKaFPhyFDcM=", + "requires": { + "recompose": "0.26.0" + } + }, + "material-ui-textfield-icon": { + "version": "0.2.2-1", + "resolved": "https://registry.npmjs.org/material-ui-textfield-icon/-/material-ui-textfield-icon-0.2.2-1.tgz", + "integrity": "sha512-hvRDPs2YqIUjbkAIWmEHAvRtDXSz5miBWnZiAsRSZFMvjjbtCi6t1IHMrhKkzHRHjdEQkLPs37e/9HezZxBAxg==", + "requires": { + "material-ui": "0.19.4", + "react": "15.6.2", + "react-dom": "15.6.2" + }, + "dependencies": { + "react": { + "version": "15.6.2", + "resolved": "https://registry.npmjs.org/react/-/react-15.6.2.tgz", + "integrity": "sha1-26BDSrQ5z+gvEI8PURZjkIF5qnI=", + "requires": { + "create-react-class": "15.6.2", + "fbjs": "0.8.16", + "loose-envify": "1.3.1", + "object-assign": "4.1.1", + "prop-types": "15.6.0" + } + }, + "react-dom": { + "version": "15.6.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-15.6.2.tgz", + "integrity": "sha1-Qc+t9pO3V/rycIRDodH9WgK+9zA=", + "requires": { + "fbjs": "0.8.16", + "loose-envify": "1.3.1", + "object-assign": "4.1.1", + "prop-types": "15.6.0" + } + } + } + }, "math-clamp-x": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/math-clamp-x/-/math-clamp-x-1.2.0.tgz", "integrity": "sha512-tqpjpBcIf9UulApz3EjWXqTZpMlr2vLN9PryC9ghoyCuRmqZaf3JJhPddzgQpJnKLi2QhoFnvKBFtJekAIBSYg==", - "dev": true, "requires": { "to-number-x": "2.0.0" } @@ -5731,7 +5602,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/math-sign-x/-/math-sign-x-3.0.0.tgz", "integrity": "sha512-OzPas41Pn4d16KHnaXmGxxY3/l3zK4OIXtmIwdhgZsxz4FDDcNnbrABYPg2vGfxIkaT9ezGnzDviRH7RfF44jQ==", - "dev": true, "requires": { "is-nan-x": "1.0.1", "to-number-x": "2.0.0" @@ -5740,8 +5610,7 @@ "max-safe-integer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/max-safe-integer/-/max-safe-integer-1.0.1.tgz", - "integrity": "sha1-84BgvixWPYwC5tSK85Ei/YO29BA=", - "dev": true + "integrity": "sha1-84BgvixWPYwC5tSK85Ei/YO29BA=" }, "md5.js": { "version": "1.3.4", @@ -5768,8 +5637,7 @@ "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "dev": true + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, "mem": { "version": "1.1.0", @@ -5784,7 +5652,6 @@ "version": "0.3.10", "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.3.10.tgz", "integrity": "sha1-TsoNiu057J0Bf0xcLy9kMvQuXI8=", - "dev": true, "requires": { "d": "0.1.1", "es5-ext": "0.10.35", @@ -5799,7 +5666,6 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/d/-/d-0.1.1.tgz", "integrity": "sha1-2hhMU10Y2O57oqoim5FACfrhEwk=", - "dev": true, "requires": { "es5-ext": "0.10.35" } @@ -5808,7 +5674,6 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-0.1.3.tgz", "integrity": "sha1-1vWLjE/EE8JJtLqhl2j45NfIlE4=", - "dev": true, "requires": { "d": "0.1.1", "es5-ext": "0.10.35", @@ -5819,7 +5684,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-2.0.1.tgz", "integrity": "sha1-dhtcZ8/U8dGK+yNPaR1nhoLLO/M=", - "dev": true, "requires": { "d": "0.1.1", "es5-ext": "0.10.35" @@ -5829,7 +5693,6 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-0.1.4.tgz", "integrity": "sha1-cGzvnpmqI2undmwjnIueKG6n0ig=", - "dev": true, "requires": { "d": "0.1.1", "es5-ext": "0.10.35", @@ -5932,14 +5795,12 @@ "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", - "dev": true + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "dev": true + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" }, "micromatch": { "version": "2.3.11", @@ -5981,14 +5842,12 @@ "mime-db": { "version": "1.30.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", - "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", - "dev": true + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" }, "mime-types": { "version": "2.1.17", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", - "dev": true, "requires": { "mime-db": "1.30.0" } @@ -6023,14 +5882,12 @@ "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, "requires": { "minimist": "0.0.8" } @@ -6066,8 +5923,7 @@ "nan-x": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/nan-x/-/nan-x-1.0.0.tgz", - "integrity": "sha512-yw4Fhe2/UTzanQ4f0yHWkRnfTuHZFAi4GZDjXS4G+qv5BqXTqPJBbSxpa7MyyW9v4Y4ZySZQik1vcbNkhdnIOg==", - "dev": true + "integrity": "sha512-yw4Fhe2/UTzanQ4f0yHWkRnfTuHZFAi4GZDjXS4G+qv5BqXTqPJBbSxpa7MyyW9v4Y4ZySZQik1vcbNkhdnIOg==" }, "ncname": { "version": "1.0.0", @@ -6081,14 +5937,12 @@ "negotiator": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", - "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", - "dev": true + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" }, "next-tick": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-0.2.2.tgz", - "integrity": "sha1-ddpKkn7liH45BliABltzNkE7MQ0=", - "dev": true + "integrity": "sha1-ddpKkn7liH45BliABltzNkE7MQ0=" }, "no-case": { "version": "2.3.2", @@ -6100,10 +5954,9 @@ } }, "node-abi": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.1.2.tgz", - "integrity": "sha512-hmUtb8m75RSi7N+zZLYqe75XDvZB+6LyTBPkj2DConvNgQet2e3BIqEwe1LLvqMrfyjabuT5ZOrTioLCH1HTdA==", - "dev": true, + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.2.0.tgz", + "integrity": "sha512-FqVC0WNNL8fQWQK3GYTESfwZXZKDbSIiEEIvufq7HV6Lj0IDDZRVa4CU/KTA0JVlqY9eTDSuPiC8FS9UfGVuzA==", "requires": { "semver": "5.4.1" } @@ -6157,8 +6010,7 @@ "noop-logger": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", - "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=", - "dev": true + "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=" }, "normalize-jss": { "version": "4.0.0", @@ -6191,13 +6043,17 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-space-x/-/normalize-space-x-3.0.0.tgz", "integrity": "sha512-tbCJerqZCCHPst4rRKgsTanLf45fjOyeAU5zE3mhDxJtFJKt66q39g2XArWhXelgTFVib8mNBUm6Wrd0LxYcfQ==", - "dev": true, "requires": { "cached-constructors-x": "1.0.0", "trim-x": "3.0.0", "white-space-x": "3.0.0" } }, + "normalize-wheel": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/normalize-wheel/-/normalize-wheel-1.0.1.tgz", + "integrity": "sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU=" + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -6211,7 +6067,6 @@ "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, "requires": { "are-we-there-yet": "1.1.4", "console-control-strings": "1.1.0", @@ -6231,14 +6086,12 @@ "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "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 + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" }, "object-assign": { "version": "4.1.1", @@ -6249,7 +6102,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/object-get-own-property-descriptor-x/-/object-get-own-property-descriptor-x-3.2.0.tgz", "integrity": "sha512-Z/0fIrptD9YuzN+SNK/1kxAEaBcPQM4gSrtOSMSi9eplnL/AbyQcAyAlreAoAzmBon+DQ1Z+AdhxyQSvav5Fyg==", - "dev": true, "requires": { "attempt-x": "1.1.1", "has-own-property-x": "3.2.0", @@ -6289,7 +6141,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dev": true, "requires": { "ee-first": "1.1.1" } @@ -6304,11 +6155,15 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, "requires": { "wrappy": "1.0.2" } }, + "opener": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.4.3.tgz", + "integrity": "sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=" + }, "opn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/opn/-/opn-5.1.0.tgz", @@ -6348,8 +6203,7 @@ "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 + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" }, "os-locale": { "version": "2.1.0", @@ -6409,8 +6263,7 @@ "pako": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", - "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==", - "dev": true + "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==" }, "param-case": { "version": "2.1.1", @@ -6450,7 +6303,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/parse-int-x/-/parse-int-x-2.0.0.tgz", "integrity": "sha512-NIMm52gmd1+0qxJK8lV3OZ4zzWpRH1xcz9xCHXl+DNzddwUdS4NEtd7BmTeK7iCIXoaK5e6BoDMHgieH2eNIhg==", - "dev": true, "requires": { "cached-constructors-x": "1.0.0", "nan-x": "1.0.0", @@ -6470,8 +6322,7 @@ "parseurl": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", - "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", - "dev": true + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" }, "path-browserify": { "version": "0.0.0", @@ -6509,8 +6360,7 @@ "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", - "dev": true + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, "path-type": { "version": "2.0.0", @@ -6534,17 +6384,20 @@ "sha.js": "2.4.9" } }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + }, "pepjs": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/pepjs/-/pepjs-0.4.3.tgz", - "integrity": "sha1-FggOlwqud5kTdWwtrviOqnSG30E=", - "dev": true + "integrity": "sha1-FggOlwqud5kTdWwtrviOqnSG30E=" }, "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 + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "pify": { "version": "2.3.0", @@ -6596,15 +6449,14 @@ } }, "pouchdb": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/pouchdb/-/pouchdb-6.4.0.tgz", - "integrity": "sha512-R9sm7USMctC1/itY9UdtA8iVOF04Ui+rsGnNdO9zLTpolzglWskSL/0B3RQ2OchGYLNgsaZS0UzQ7AQ1SHXobg==", - "dev": true, + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/pouchdb/-/pouchdb-6.4.2.tgz", + "integrity": "sha512-z4rq2lLB/wYULcVb0O5G41hv/V/RMUqDNbmgDhAvvqeyBTkCf6RLL1bMCEo+m+igM4iFfITkKVJj8gnYehh/fg==", "requires": { "argsarray": "0.0.1", "buffer-from": "0.1.1", "clone-buffer": "1.0.0", - "debug": "3.0.1", + "debug": "3.1.0", "double-ended-queue": "2.1.0-0", "immediate": "3.0.6", "inherits": "2.0.3", @@ -6616,18 +6468,17 @@ "lie": "3.1.1", "ltgt": "2.2.0", "readable-stream": "1.0.33", - "request": "2.80.0", + "request": "2.83.0", "spark-md5": "3.0.0", "through2": "2.0.3", - "uuid": "3.1.0", + "uuid": "3.2.1", "vuvuzela": "1.0.3" }, "dependencies": { "debug": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.0.1.tgz", - "integrity": "sha512-6nVc6S36qbt/mutyt+UGMnawAMrPDZUPQjRZI3FS9tCtDRhvxJbK79unYBLPi+z5SLXQ3ftoVBFCblQtNSls8w==", - "dev": true, + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "requires": { "ms": "2.0.0" } @@ -6635,14 +6486,12 @@ "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" }, "readable-stream": { "version": "1.0.33", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz", "integrity": "sha1-OjYN1mwbHX/UcFOJhg7aHQ9hEmw=", - "dev": true, "requires": { "core-util-is": "1.0.2", "inherits": "2.0.3", @@ -6653,33 +6502,31 @@ "string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" }, "uuid": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", - "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", - "dev": true + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", + "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==" } } }, "prebuild-install": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-2.4.1.tgz", - "integrity": "sha512-99TyEFYTTkBWANT+mwSptmLb9ZCLQ6qKIUE36fXSIOtShB0JNprL2hzBD8F1yIuT9btjFrFEwbRHXhqDi1HmRA==", - "dev": true, + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-2.5.0.tgz", + "integrity": "sha512-3wlyZgmkeeyduOR8Ursu5gKr3yWAYObACa5aJOtt2farRRFV/+zXk/Y3wM6yQRMqmqHh+pHAwyKp5r82K699Rg==", "requires": { + "detect-libc": "1.0.3", "expand-template": "1.1.0", "github-from-package": "0.0.0", "minimist": "1.2.0", "mkdirp": "0.5.1", - "node-abi": "2.1.2", + "node-abi": "2.2.0", "noop-logger": "0.1.1", "npmlog": "4.1.2", "os-homedir": "1.0.2", "pump": "1.0.3", - "rc": "1.2.2", + "rc": "1.2.5", "simple-get": "1.4.3", "tar-fs": "1.16.0", "tunnel-agent": "0.6.0", @@ -6689,8 +6536,7 @@ "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" } } }, @@ -6713,8 +6559,7 @@ "private": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/private/-/private-0.1.7.tgz", - "integrity": "sha1-aM5eih7woju1cMwoU3tTMqumPvE=", - "dev": true + "integrity": "sha1-aM5eih7woju1cMwoU3tTMqumPvE=" }, "process": { "version": "0.11.10", @@ -6725,8 +6570,7 @@ "process-nextick-args": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" }, "promise": { "version": "7.3.1", @@ -6750,7 +6594,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/property-is-enumerable-x/-/property-is-enumerable-x-1.1.0.tgz", "integrity": "sha512-22cKy3w3OpRswU6to9iKWDDlg+F9vF2REcwGlGW23jyLjHb1U/jJEWA44sWupOnkhGfDgotU6Lw+N2oyhNi+5A==", - "dev": true, "requires": { "to-object-x": "1.5.0", "to-property-key-x": "2.0.2" @@ -6765,7 +6608,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz", "integrity": "sha1-ZXFQT0e7mI7IGAJT+F3X4UlSvew=", - "dev": true, "requires": { "forwarded": "0.1.2", "ipaddr.js": "1.5.2" @@ -6774,8 +6616,7 @@ "prr": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz", - "integrity": "sha1-GoS4WQgyVQFBGFPQCB7j+obikmo=", - "dev": true + "integrity": "sha1-GoS4WQgyVQFBGFPQCB7j+obikmo=" }, "pseudomap": { "version": "1.0.2", @@ -6800,23 +6641,30 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", - "dev": true, "requires": { - "end-of-stream": "1.4.0", + "end-of-stream": "1.4.1", "once": "1.4.0" } }, "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" }, "qs": { "version": "6.5.1", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", - "dev": true + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + }, + "query-string": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.0.1.tgz", + "integrity": "sha512-aM+MkQClojlNiKkO09tiN2Fv8jM/L7GWIjG2liWeKljlOdOPNWr+bW3KQ+w5V/uKprpezC7fAsAMsJtJ+2rLKA==", + "requires": { + "decode-uri-component": "0.2.0", + "object-assign": "4.1.1", + "strict-uri-encode": "1.1.0" + } }, "querystring": { "version": "0.2.0", @@ -6840,24 +6688,14 @@ "version": "3.4.0", "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.0.tgz", "integrity": "sha512-pDP/NMRAXoTfrhCfyfSEwJAKLaxBU9eApMeBPB1TkDouZmvPerIClV8lTAd+uF8ZiTaVl69e1FCxQrAd/VTjGw==", - "dev": true, "requires": { "performance-now": "2.1.0" - }, - "dependencies": { - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - } } }, "ramda": { "version": "0.21.0", "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.21.0.tgz", - "integrity": "sha1-oAGr7bP/YQd9T/HVd9RN536NCjU=", - "dev": true + "integrity": "sha1-oAGr7bP/YQd9T/HVd9RN536NCjU=" }, "randomatic": { "version": "1.1.7", @@ -6922,14 +6760,12 @@ "range-parser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", - "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", - "dev": true + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" }, "raw-body": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", - "dev": true, "requires": { "bytes": "3.0.0", "http-errors": "1.6.2", @@ -6944,10 +6780,9 @@ "dev": true }, "rc": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.2.tgz", - "integrity": "sha1-2M6ctX6NZNnHut2YdsfDTL48cHc=", - "dev": true, + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.5.tgz", + "integrity": "sha1-J1zWh/bjs2zHVrqibf7oCnkDAf0=", "requires": { "deep-extend": "0.4.2", "ini": "1.3.5", @@ -6958,8 +6793,7 @@ "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" } } }, @@ -6978,7 +6812,6 @@ "version": "15.6.2", "resolved": "https://registry.npmjs.org/react-addons-update/-/react-addons-update-15.6.2.tgz", "integrity": "sha1-5TdTxbNIh5dFEMiC1/sHWFHV5QQ=", - "dev": true, "requires": { "fbjs": "0.8.16", "object-assign": "4.1.1" @@ -7038,7 +6871,6 @@ "version": "0.2.16", "resolved": "https://registry.npmjs.org/react-notification-system/-/react-notification-system-0.2.16.tgz", "integrity": "sha1-m52iCw00eGtgBXxStCUW6hKVN0o=", - "dev": true, "requires": { "create-react-class": "15.6.2", "object-assign": "4.1.1", @@ -7049,7 +6881,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/react-notification-system-redux/-/react-notification-system-redux-1.2.0.tgz", "integrity": "sha1-FPsJFccuTBLZmD/+ByVOLNGexd8=", - "dev": true, "requires": { "prop-types": "15.6.0", "react-notification-system": "0.2.16" @@ -7059,7 +6890,6 @@ "version": "5.0.6", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-5.0.6.tgz", "integrity": "sha512-8taaaGu+J7PMJQDJrk/xiWEYQmdo3mkXw6wPr3K3LxvXis3Fymiq7c13S+Tpls/AyNUAsoONkU81AP0RA6y6Vw==", - "dev": true, "requires": { "hoist-non-react-statics": "2.3.1", "invariant": "2.2.2", @@ -7072,8 +6902,7 @@ "hoist-non-react-statics": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.3.1.tgz", - "integrity": "sha1-ND24TGAYxlB3iJgkATWhQg7iLOA=", - "dev": true + "integrity": "sha1-ND24TGAYxlB3iJgkATWhQg7iLOA=" } } }, @@ -7086,10 +6915,9 @@ } }, "react-svg-inline": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/react-svg-inline/-/react-svg-inline-2.0.1.tgz", - "integrity": "sha512-9YVqJ80g1gPWAvD9CS/z4cKPD45ZSMjjzwxFAmQJiMEoAo1Ajhz92WirXag3ftltDN5lPNkVWx/KOnEWB/PaMQ==", - "dev": true, + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/react-svg-inline/-/react-svg-inline-2.1.0.tgz", + "integrity": "sha512-GzRID5IcEQ8dnnaUtTb9MDTAbhuaOiVKKAVLgrCNuehHsg3DuZbe82bjc9JhmPv0zsDWhDrJwzADNgzEvE6VeQ==", "requires": { "classnames": "2.2.5", "prop-types": "15.6.0" @@ -7152,7 +6980,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", "integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=", - "dev": true, "requires": { "core-util-is": "1.0.2", "inherits": "2.0.3", @@ -7204,13 +7031,12 @@ } }, "redux-form": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/redux-form/-/redux-form-7.2.0.tgz", - "integrity": "sha512-qbgeI19drwnm9FeGAotDA1vsZO8q94XF7IxPDuJmSXxDYX2rqzhND6NROahCBJfBK5xM1cchvmgscO2rry1EEw==", - "dev": true, + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/redux-form/-/redux-form-7.2.1.tgz", + "integrity": "sha512-KWV+rq+L1QGoRSKoJXbGS8Mw2q4ta5FVyGxW5ZYnAEjXZAukvUCkqDUzobBmOqiRHvrZ3/ssEA7kJFdu7rV8+w==", "requires": { "deep-equal": "1.0.1", - "es6-error": "4.0.2", + "es6-error": "4.1.1", "hoist-non-react-statics": "2.3.1", "invariant": "2.2.2", "is-promise": "2.1.0", @@ -7222,34 +7048,29 @@ "hoist-non-react-statics": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.3.1.tgz", - "integrity": "sha1-ND24TGAYxlB3iJgkATWhQg7iLOA=", - "dev": true + "integrity": "sha1-ND24TGAYxlB3iJgkATWhQg7iLOA=" } } }, "redux-undo": { "version": "1.0.0-beta9-9-7", "resolved": "https://registry.npmjs.org/redux-undo/-/redux-undo-1.0.0-beta9-9-7.tgz", - "integrity": "sha1-/juqGycUI9fdu/w6gscbApotuLo=", - "dev": true + "integrity": "sha1-/juqGycUI9fdu/w6gscbApotuLo=" }, "regenerate": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz", - "integrity": "sha512-jVpo1GadrDAK59t/0jRx5VxYWQEDkkEKi6+HjE3joFVLfDOh9Xrdh0dF1eSq+BI/SwvTQ44gSscJ8N5zYL61sg==", - "dev": true + "integrity": "sha512-jVpo1GadrDAK59t/0jRx5VxYWQEDkkEKi6+HjE3joFVLfDOh9Xrdh0dF1eSq+BI/SwvTQ44gSscJ8N5zYL61sg==" }, "regenerator-runtime": { "version": "0.10.5", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", - "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=", - "dev": true + "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=" }, "regenerator-transform": { "version": "0.10.1", "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", - "dev": true, "requires": { "babel-runtime": "6.26.0", "babel-types": "6.25.0", @@ -7270,7 +7091,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", - "dev": true, "requires": { "regenerate": "1.3.3", "regjsgen": "0.2.0", @@ -7280,14 +7100,12 @@ "regjsgen": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", - "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", - "dev": true + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=" }, "regjsparser": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", - "dev": true, "requires": { "jsesc": "0.5.0" }, @@ -7295,8 +7113,7 @@ "jsesc": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" } } }, @@ -7358,58 +7175,44 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/replace-comments-x/-/replace-comments-x-2.0.0.tgz", "integrity": "sha512-+vMP4jqU+8HboLWms6YMNEiaZG5hh1oR6ENCnGYDF/UQ7aYiJUK/8tcl3+KZAHRCKKa3gqzrfiarlUBHQSgRlg==", - "dev": true, "requires": { "require-coercible-to-string-x": "1.0.0", "to-string-x": "1.4.2" } }, "request": { - "version": "2.80.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.80.0.tgz", - "integrity": "sha1-jMFi1215OBze/dNQXXa4C2BYm9A=", - "dev": true, + "version": "2.83.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", + "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", "requires": { - "aws-sign2": "0.6.0", + "aws-sign2": "0.7.0", "aws4": "1.6.0", "caseless": "0.12.0", "combined-stream": "1.0.5", "extend": "3.0.1", "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", + "form-data": "2.3.1", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", "is-typedarray": "1.0.0", "isstream": "0.1.2", "json-stringify-safe": "5.0.1", "mime-types": "2.1.17", "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.3.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", "stringstream": "0.0.5", "tough-cookie": "2.3.3", - "tunnel-agent": "0.4.3", - "uuid": "3.1.0" + "tunnel-agent": "0.6.0", + "uuid": "3.2.1" }, "dependencies": { - "qs": { - "version": "6.3.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz", - "integrity": "sha1-51vV9uJoEioqDgvaYwslUMFmUCw=", - "dev": true - }, - "tunnel-agent": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", - "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", - "dev": true - }, "uuid": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", - "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", - "dev": true + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", + "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==" } } }, @@ -7417,7 +7220,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/require-coercible-to-string-x/-/require-coercible-to-string-x-1.0.0.tgz", "integrity": "sha512-Rpfd4sMdflPAKecdKhfAtQHlZzzle4UMUgxJ01hXtTcNWMV8w9GeZnKhEyrT73kgrflBOP1zg41amUPZGcNspA==", - "dev": true, "requires": { "require-object-coercible-x": "1.4.1", "to-string-x": "1.4.2" @@ -7439,7 +7241,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/require-object-coercible-x/-/require-object-coercible-x-1.4.1.tgz", "integrity": "sha512-0YHa2afepsLfQvwQ1P2XvDZnGOUia5sC07ZijIRU2dnsRxnuilXWF6B2CFaKGDA9eZl39lJHrXCDsnfgroRd6Q==", - "dev": true, "requires": { "is-nil-x": "1.4.1" } @@ -7453,8 +7254,7 @@ "reselect": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/reselect/-/reselect-3.0.1.tgz", - "integrity": "sha1-79qpjqdFEyTQkrKyFjpqHXqaIUc=", - "dev": true + "integrity": "sha1-79qpjqdFEyTQkrKyFjpqHXqaIUc=" }, "resolve-cwd": { "version": "2.0.0", @@ -7502,8 +7302,7 @@ "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha1-iTMSr2myEj3vcfV4iQAWce6yyFM=", - "dev": true + "integrity": "sha1-iTMSr2myEj3vcfV4iQAWce6yyFM=" }, "schema-utils": { "version": "0.3.0", @@ -7532,14 +7331,12 @@ "semver": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", - "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==", - "dev": true + "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==" }, "send": { "version": "0.16.1", "resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz", "integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==", - "dev": true, "requires": { "debug": "2.6.9", "depd": "1.1.1", @@ -7560,7 +7357,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "requires": { "ms": "2.0.0" } @@ -7568,8 +7364,7 @@ "mime": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", - "dev": true + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" } } }, @@ -7603,7 +7398,6 @@ "version": "1.13.1", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz", "integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==", - "dev": true, "requires": { "encodeurl": "1.0.1", "escape-html": "1.0.3", @@ -7614,8 +7408,7 @@ "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 + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "set-immediate-shim": { "version": "1.0.1", @@ -7631,8 +7424,7 @@ "setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" }, "sha.js": { "version": "2.4.9", @@ -7662,14 +7454,12 @@ "shortid": { "version": "2.2.8", "resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.8.tgz", - "integrity": "sha1-AzsRfWoul1gE9vCWnb59PQs1UTE=", - "dev": true + "integrity": "sha1-AzsRfWoul1gE9vCWnb59PQs1UTE=" }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, "simple-assign": { "version": "0.1.0", @@ -7680,7 +7470,6 @@ "version": "1.4.3", "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-1.4.3.tgz", "integrity": "sha1-6XVe2kB+ltpAxeUVjJ6jezO+y+s=", - "dev": true, "requires": { "once": "1.4.0", "unzip-response": "1.0.2", @@ -7694,12 +7483,11 @@ "dev": true }, "sntp": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", - "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", - "dev": true, + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", + "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", "requires": { - "hoek": "2.16.3" + "hoek": "4.2.0" } }, "sockjs": { @@ -7746,8 +7534,7 @@ "source-map": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", - "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", - "dev": true + "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=" }, "source-map-support": { "version": "0.4.15", @@ -7761,8 +7548,7 @@ "spark-md5": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spark-md5/-/spark-md5-3.0.0.tgz", - "integrity": "sha1-NyIifFTi+vJLHcbZM8wUTm9xv+8=", - "dev": true + "integrity": "sha1-NyIifFTi+vJLHcbZM8wUTm9xv+8=" }, "spdx-correct": { "version": "1.0.2", @@ -7824,7 +7610,6 @@ "version": "1.13.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", - "dev": true, "requires": { "asn1": "0.2.3", "assert-plus": "1.0.0", @@ -7834,21 +7619,12 @@ "getpass": "0.1.7", "jsbn": "0.1.1", "tweetnacl": "0.14.5" - }, - "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 - } } }, "statuses": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", - "dev": true + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" }, "stream-browserify": { "version": "2.0.1", @@ -7873,14 +7649,10 @@ "xtend": "4.0.1" } }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", - "dev": true, - "requires": { - "safe-buffer": "5.1.1" - } + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" }, "string-width": { "version": "2.1.1", @@ -7915,11 +7687,18 @@ } } }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=", + "requires": { + "safe-buffer": "5.1.1" + } + }, "stringstream": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", - "dev": true + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" }, "strip-ansi": { "version": "3.0.1", @@ -7953,8 +7732,7 @@ "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 + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" }, "supports-color": { "version": "2.0.0", @@ -7976,7 +7754,6 @@ "version": "1.16.0", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.0.tgz", "integrity": "sha512-I9rb6v7mjWLtOfCau9eH5L7sLJyU2BnxtEZRQ5Mt+eRKmf1F0ohXmT/Jc3fr52kDvjJ/HV5MH3soQfPL5bQ0Yg==", - "dev": true, "requires": { "chownr": "1.0.1", "mkdirp": "0.5.1", @@ -7988,10 +7765,9 @@ "version": "1.5.5", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.5.tgz", "integrity": "sha512-mQdgLPc/Vjfr3VWqWbfxW8yQNiJCbAZ+Gf6GDu1Cy0bdb33ofyiNGBtAY96jHFhDuivCwgW1H9DgTON+INiXgg==", - "dev": true, "requires": { "bl": "1.2.1", - "end-of-stream": "1.4.0", + "end-of-stream": "1.4.1", "readable-stream": "2.3.3", "xtend": "4.0.1" } @@ -8027,15 +7803,10 @@ "resolved": "https://registry.npmjs.org/three/-/three-0.88.0.tgz", "integrity": "sha1-QlbC/Djk+yOg0j66K2zOTfjkZtU=" }, - "three-js-csg": { - "version": "github:Doodle3D/three-js-csg#a36f23da6e9be2405a9094de5709cb0ae8f58045", - "dev": true - }, "through2": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", - "dev": true, "requires": { "readable-stream": "2.3.3", "xtend": "4.0.1" @@ -8066,7 +7837,6 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.2.tgz", "integrity": "sha1-YcxHp2wavTGV8UUn+XjViulMUgQ=", - "dev": true, "requires": { "es5-ext": "0.10.35", "next-tick": "1.0.0" @@ -8075,8 +7845,7 @@ "next-tick": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", - "dev": true + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" } } }, @@ -8089,8 +7858,7 @@ "to-boolean-x": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/to-boolean-x/-/to-boolean-x-1.0.1.tgz", - "integrity": "sha512-PstxY3K6hVEHnY3FITs8XBoJbt0RI1e4MLIhAL9hWa3BtVLCrb86vU5z6lEKh7uZZjiPiLqIKMmfMro1nNgtXQ==", - "dev": true + "integrity": "sha512-PstxY3K6hVEHnY3FITs8XBoJbt0RI1e4MLIhAL9hWa3BtVLCrb86vU5z6lEKh7uZZjiPiLqIKMmfMro1nNgtXQ==" }, "to-fast-properties": { "version": "1.0.3", @@ -8101,7 +7869,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/to-integer-x/-/to-integer-x-3.0.0.tgz", "integrity": "sha512-794L2Lpwjtynm7RxahJi2YdbRY75gTxUW27TMuN26UgwPkmJb/+HPhkFEFbz+E4vNoiP0dxq5tq5fkXoXLaK/w==", - "dev": true, "requires": { "is-finite-x": "3.0.2", "is-nan-x": "1.0.1", @@ -8113,7 +7880,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-number-x/-/to-number-x-2.0.0.tgz", "integrity": "sha512-lGOnCoccUoSzjZ/9Uen8TC4+VFaQcFGhTroWTv2tYWxXgyJV1zqAZ8hEIMkez/Eo790fBMOjidTnQ/OJSCvAoQ==", - "dev": true, "requires": { "cached-constructors-x": "1.0.0", "nan-x": "1.0.0", @@ -8126,7 +7892,6 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/to-object-x/-/to-object-x-1.5.0.tgz", "integrity": "sha512-AKn5GQcdWky+s20vjWkt+Wa6y3dxQH3yQyMBhOfBOPldUwqwhgvlqcIg5H092ntNc+TX8/Cxzs1kMHH19pyCnA==", - "dev": true, "requires": { "cached-constructors-x": "1.0.0", "require-object-coercible-x": "1.4.1" @@ -8136,7 +7901,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/to-primitive-x/-/to-primitive-x-1.1.0.tgz", "integrity": "sha512-gyMY0gi3wjK3e4MUBKqv9Zl8QGcWguIkaUr2VJmoBEsOpDcpDZSEyljR773eVG4maS48uX7muLkoQoh/BA82OQ==", - "dev": true, "requires": { "has-symbol-support-x": "1.4.1", "is-date-object": "1.0.1", @@ -8152,7 +7916,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/to-property-key-x/-/to-property-key-x-2.0.2.tgz", "integrity": "sha512-YISLpZFYIazNm0P8hLsKEEUEZ3m8U3+eDysJZqTu3+B9tQp+2TrMpaEGT8Agh4fZ5LSoums60/glNEzk5ozqrg==", - "dev": true, "requires": { "has-symbol-support-x": "1.4.1", "to-primitive-x": "1.1.0", @@ -8163,7 +7926,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/to-string-symbols-supported-x/-/to-string-symbols-supported-x-1.0.0.tgz", "integrity": "sha512-HbVH673pybrUmhzESGHUm17BBJvqb7BU8HciOvuEYm9ipuDyjmddhvkVqpVW6sM/C5/zhJo17n7O7I/24loJIQ==", - "dev": true, "requires": { "cached-constructors-x": "1.0.0", "has-symbol-support-x": "1.4.1", @@ -8174,7 +7936,6 @@ "version": "1.4.2", "resolved": "https://registry.npmjs.org/to-string-tag-x/-/to-string-tag-x-1.4.2.tgz", "integrity": "sha512-ytO9eLigxsQQLGuab0C1iSSTzKdJNVSlBg0Spg4J/rGAVrQJ5y774mo0SSzgGeTT4RJGGyJNfObXaTMzX0XDOQ==", - "dev": true, "requires": { "lodash.isnull": "3.0.0", "validate.io-undefined": "1.0.3" @@ -8184,7 +7945,6 @@ "version": "1.4.2", "resolved": "https://registry.npmjs.org/to-string-x/-/to-string-x-1.4.2.tgz", "integrity": "sha512-/WP5arlwtCpAAexCCHiQBW0eXwse84osWyP1Qtaz71nsYSuUpOkT6tBm8nQ4IIUfSh5hji0hDupUCD2xbbOL6A==", - "dev": true, "requires": { "is-symbol": "1.0.1" } @@ -8199,7 +7959,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", - "dev": true, "requires": { "punycode": "1.4.1" } @@ -8208,7 +7967,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/trim-left-x/-/trim-left-x-3.0.0.tgz", "integrity": "sha512-+m6cqkppI+CxQBTwWEZliOHpOBnCArGyMnS1WCLb6IRgukhTkiQu/TNEN5Lj2eM9jk8ewJsc7WxFZfmwNpRXWQ==", - "dev": true, "requires": { "cached-constructors-x": "1.0.0", "require-coercible-to-string-x": "1.0.0", @@ -8231,7 +7989,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/trim-right-x/-/trim-right-x-3.0.0.tgz", "integrity": "sha512-iIqEsWEbWVodqdixJHi4FoayJkUxhoL4AvSNGp4FF4FfQKRPGizt8++/RnyC9od75y7P/S6EfONoVqP+NddiKA==", - "dev": true, "requires": { "cached-constructors-x": "1.0.0", "require-coercible-to-string-x": "1.0.0", @@ -8242,7 +7999,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/trim-x/-/trim-x-3.0.0.tgz", "integrity": "sha512-w8s38RAUScQ6t3XqMkS75iz5ZkIYLQpVnv2lp3IuTS36JdlVzC54oe6okOf4Wz3UH4rr3XAb2xR3kR5Xei82fw==", - "dev": true, "requires": { "trim-left-x": "3.0.0", "trim-right-x": "3.0.0" @@ -8258,7 +8014,6 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, "requires": { "safe-buffer": "5.1.1" } @@ -8267,14 +8022,12 @@ "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-is": { "version": "1.6.15", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", - "dev": true, "requires": { "media-typer": "0.3.0", "mime-types": "2.1.17" @@ -8346,17 +8099,20 @@ } } }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "dev": true + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, "unzip-response": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-1.0.2.tgz", - "integrity": "sha1-uYTwh3/AqJwsdzzB73tbIytbBv4=", - "dev": true + "integrity": "sha1-uYTwh3/AqJwsdzzB73tbIytbBv4=" }, "upper-case": { "version": "1.1.3", @@ -8410,6 +8166,11 @@ } } }, + "url-search-params-polyfill": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/url-search-params-polyfill/-/url-search-params-polyfill-2.0.2.tgz", + "integrity": "sha512-zFN1r66KeSpxM2qrbHPf4u6nbIIGLOCNdO3JXdV5mEqeoBPev7VwuCv5goL69TQmfAQdVyTHI8lmzCIRPEW4Bg==" + }, "user-home": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", @@ -8436,8 +8197,7 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "utila": { "version": "0.4.0", @@ -8448,8 +8208,7 @@ "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "dev": true + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { "version": "2.0.3", @@ -8469,8 +8228,12 @@ "valid-url": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/valid-url/-/valid-url-1.0.9.tgz", - "integrity": "sha1-HBRHm0DxOXp1eC8RXkCGRHQzogA=", - "dev": true + "integrity": "sha1-HBRHm0DxOXp1eC8RXkCGRHQzogA=" + }, + "validate-ip": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/validate-ip/-/validate-ip-1.0.1.tgz", + "integrity": "sha1-615PY+HRq8buRuGK4gaXv1vtBto=" }, "validate-npm-package-license": { "version": "3.0.1", @@ -8485,32 +8248,21 @@ "validate.io-undefined": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/validate.io-undefined/-/validate.io-undefined-1.0.3.tgz", - "integrity": "sha1-fif8uzFbhB54JDQxiXZxkp4gt/Q=", - "dev": true + "integrity": "sha1-fif8uzFbhB54JDQxiXZxkp4gt/Q=" }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "dev": true + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, "requires": { "assert-plus": "1.0.0", "core-util-is": "1.0.2", "extsprintf": "1.3.0" - }, - "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 - } } }, "vm-browserify": { @@ -8525,8 +8277,7 @@ "vuvuzela": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/vuvuzela/-/vuvuzela-1.0.3.tgz", - "integrity": "sha1-O+FF5YJxxzylUnndhR8SpoIRSws=", - "dev": true + "integrity": "sha1-O+FF5YJxxzylUnndhR8SpoIRSws=" }, "warning": { "version": "3.0.0", @@ -8597,6 +8348,24 @@ } } }, + "webpack-bundle-analyzer": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.9.2.tgz", + "integrity": "sha1-Y+2G63HMTNqG9o5oWoRTC6ASZEk=", + "requires": { + "acorn": "5.2.1", + "chalk": "1.1.3", + "commander": "2.11.0", + "ejs": "2.5.7", + "express": "4.16.2", + "filesize": "3.5.11", + "gzip-size": "3.0.0", + "lodash": "4.17.4", + "mkdirp": "0.5.1", + "opener": "1.4.3", + "ws": "4.0.0" + } + }, "webpack-dev-middleware": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-1.12.0.tgz", @@ -8849,14 +8618,12 @@ "white-space-x": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/white-space-x/-/white-space-x-3.0.0.tgz", - "integrity": "sha512-nMPVXGMdi/jQepXKryxqzEh/vCwdOYY/u6NZy40glMHvZfEr7/+vQKnDhEq4rZ1nniOFq9GWohQYB30uW/5Olg==", - "dev": true + "integrity": "sha512-nMPVXGMdi/jQepXKryxqzEh/vCwdOYY/u6NZy40glMHvZfEr7/+vQKnDhEq4rZ1nniOFq9GWohQYB30uW/5Olg==" }, "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, "requires": { "string-width": "1.0.2" }, @@ -8865,7 +8632,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, "requires": { "code-point-at": "1.1.0", "is-fullwidth-code-point": "1.0.0", @@ -8922,14 +8688,12 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "write-stream": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/write-stream/-/write-stream-0.4.3.tgz", "integrity": "sha1-g8yMA0fQr2BXqThitOOuAd5cgcE=", - "dev": true, "requires": { "readable-stream": "0.0.4" }, @@ -8937,11 +8701,20 @@ "readable-stream": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-0.0.4.tgz", - "integrity": "sha1-8y124/uGM0SlSNeZIwBxc2ZbO40=", - "dev": true + "integrity": "sha1-8y124/uGM0SlSNeZIwBxc2ZbO40=" } } }, + "ws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-4.0.0.tgz", + "integrity": "sha512-QYslsH44bH8O7/W2815u5DpnCpXWpEK44FmaHffNwgJI4JMaSZONgPBTOfrxJ29mXKbXak+LsJ2uAkDTYq2ptQ==", + "requires": { + "async-limiter": "1.0.0", + "safe-buffer": "5.1.1", + "ultron": "1.1.1" + } + }, "xml-char-classes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/xml-char-classes/-/xml-char-classes-1.0.0.tgz", @@ -8951,8 +8724,7 @@ "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "dev": true + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" }, "y18n": { "version": "3.2.1", @@ -9036,6 +8808,15 @@ } } }, + "yauzl": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.9.1.tgz", + "integrity": "sha1-qBmB6nCleUYTOIPwKcWCGok1mn8=", + "requires": { + "buffer-crc32": "0.2.13", + "fd-slicer": "1.0.1" + } + }, "yml-loader": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/yml-loader/-/yml-loader-2.1.0.tgz", diff --git a/package.json b/package.json index 26cabdb..d20bdf4 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,10 @@ "esnext": "src/index.js", "scripts": { "start": "webpack-dev-server -w", + "dist": "NODE_ENV=production webpack -p", "prepare": "npm run build", + "upload": "npm run dist && scp -r dist/* doodle3d.com:/domains/doodle3d.com/print", + "analyze": "NODE_ENV=production ANALYZE_BUNDLE=true webpack -p", "build": "npm run build:main && npm run build:main:settings && npm run build:module && npm run build:module:settings ", "build:main": "BABEL_ENV=main babel src -s -d lib", "build:module": "BABEL_ENV=module babel src -s -d module", @@ -15,20 +18,28 @@ "build:module:settings": "cp -r src/settings module" }, "dependencies": { - "@doodle3d/clipper-js": "^1.0.7", + "@doodle3d/clipper-js": "^1.0.10", + "@doodle3d/doodle3d-api": "^1.0.5", + "@doodle3d/doodle3d-core": "github:doodle3d/doodle3d-core#0.18.0", "babel-plugin-transform-class-properties": "^6.24.1", "file-saver": "^1.3.3", "lodash": "^4.17.4", "material-ui": "^0.19.4", + "material-ui-icons": "^1.0.0-beta.17", + "material-ui-textfield-icon": "^0.2.2-1", "proptypes": "^1.1.0", + "query-string": "^5.0.1", "react": "^16.0.0", + "react-addons-update": "^15.6.2", "react-dom": "^16.0.0", "react-jss": "^7.2.0", "react-resize-detector": "^1.1.0", - "three": "^0.88.0" + "shortid": "^2.2.8", + "three": "^0.88.0", + "validate-ip": "^1.0.1", + "webpack-bundle-analyzer": "^2.9.2" }, "devDependencies": { - "@doodle3d/doodle3d-core": "github:doodle3d/doodle3d-core", "babel-cli": "6.24.1", "babel-loader": "7.0.0", "babel-plugin-transform-es2015-classes": "^6.24.1", diff --git a/src/constants.js b/src/constants.js index 3e117b5..d651288 100644 --- a/src/constants.js +++ b/src/constants.js @@ -1 +1,5 @@ export const PRECISION = 0.01; +export const VERSION = '0.0.18'; +export const LOCAL_STORAGE_KEY = 'PRINTER_SETTINGS'; +export const MIN_AREA = 1; // holes smaller as 1mm2 get removed +export const Z_OFFSET = 0.2; diff --git a/src/index.js b/src/index.js index 4cb81de..25e494a 100644 --- a/src/index.js +++ b/src/index.js @@ -4,12 +4,14 @@ import _defaultSettings from './settings/default.yml'; import printerSettings from './settings/printer.yml'; import materialSettings from './settings/material.yml'; import qualitySettings from './settings/quality.yml'; +import infillSettings from './settings/infill.yml'; const defaultSettings = { default: _defaultSettings, printer: printerSettings, material: materialSettings, - quality: qualitySettings + quality: qualitySettings, + infill: infillSettings }; export { diff --git a/src/interface/FormComponents.js b/src/interface/FormComponents.js index aff0278..1ec24bf 100644 --- a/src/interface/FormComponents.js +++ b/src/interface/FormComponents.js @@ -4,36 +4,102 @@ import _ from 'lodash'; import injectSheet from 'react-jss'; import MaterialUISelectField from 'material-ui/SelectField' import MaterialUICheckbox from 'material-ui/Checkbox'; -import MaterialUITextField from 'material-ui/TextField'; +import TextFieldIcon from 'material-ui-textfield-icon'; +import RefreshIcon from 'material-ui-icons/Refresh'; +import muiThemeable from 'material-ui/styles/muiThemeable'; -const contextTypes = { state: PropTypes.object, onChange: PropTypes.func, disabled: PropTypes.bool }; +export const contextTypes = { + settings: PropTypes.object.isRequired, + onChange: PropTypes.func.isRequired, + disabled: PropTypes.bool.isRequired, + addPrinter: PropTypes.object.isRequired, + managePrinter: PropTypes.object.isRequired, + advancedFields: PropTypes.array.isRequired, + activePrinter: PropTypes.string +}; +const propTypes = { + name: PropTypes.string.isRequired, + muiTheme: PropTypes.object.isRequired +}; -export const SelectField = (props, context) => ( +export const _SelectField = ({ name, muiTheme, ...props }, context) => ( context.onChange(props.name, value)} + value={_.get(context, name)} + onChange={(event, index, value) => context.onChange(name, value)} /> ); -SelectField.contextTypes = contextTypes; +_SelectField.contextTypes = contextTypes; +_SelectField.propTypes = propTypes; +export const SelectField = muiThemeable()(_SelectField); -export const TextField = (props, context) => ( - ( + context.onChange(name, null)} + />} + floatingLabelStyle={{ + color: context.advancedFields.includes(name) ? palette.primary1Color : palette.primary3Color + }} disabled={context.disabled} - value={_.get(context.state, props.name)} - onChange={(event, value) => context.onChange(props.name, value)} + value={_.get(context, name)} + onChange={(event, value) => context.onChange(name, value)} /> ); -TextField.contextTypes = contextTypes; +_TextField.contextTypes = contextTypes; +_TextField.propTypes = propTypes; +export const TextField = muiThemeable()(_TextField); -export const Checkbox = (props, context) => ( - ( + context.onChange(name, null)} /> + } + floatingLabelStyle={{ + color: context.advancedFields.includes(name) ? palette.primary1Color : palette.primary3Color + }} disabled={context.disabled} - checked={_.get(context.state, props.name)} - onCheck={(event, value) => context.onChange(props.name, value)} + value={_.get(context, name.toString())} + onChange={(event, value) => { + value = parseFloat(value); + context.onChange(name, value); + }} + onBlur={() => { + const value = _.get(context, name.toString()); + let newValue = value; + if (typeof min === 'number') newValue = Math.max(newValue, min); + if (typeof max === 'number') newValue = Math.min(newValue, max); + if (newValue !== value) context.onChange(name, newValue); + }} /> ); -Checkbox.contextTypes = contextTypes; +_NumberField.contextTypes = contextTypes; +_NumberField.propTypes = propTypes; +export const NumberField = muiThemeable()(_NumberField); + +const _Checkbox = ({ name, muiTheme: { palette }, ...props }, context) => ( + + context.onChange(name, value)} + /> + {context.advancedFields.includes(name) && context.onChange(name, null)} + />} + +); +_Checkbox.contextTypes = contextTypes; +_Checkbox.propTypes = propTypes; +export const Checkbox = muiThemeable()(_Checkbox); diff --git a/src/interface/MalyanControl.js b/src/interface/MalyanControl.js new file mode 100644 index 0000000..d3c8dfe --- /dev/null +++ b/src/interface/MalyanControl.js @@ -0,0 +1,61 @@ +import React from 'react'; +import PropTypes from 'proptypes'; +import muiThemeable from 'material-ui/styles/muiThemeable'; +import injectSheet from 'react-jss'; +import FlatButton from 'material-ui/FlatButton'; +import { sleep, getMalyanStatus } from './utils.js'; + +const styles = { + +}; + +class MalyanControl extends React.Component { + static propTypes = { + ip: PropTypes.string.isRequired + }; + + state = { + status: null, + mounted: true + }; + + // componentDidMount = async () => { + // const { ip } = this.props; + // while (this.state.mounted) { + // const status = await getMalyanStatus(ip).catch(() => null); + // this.setState({ status }); + // await sleep(1000); + // } + // }; + + home = () => { + const { ip } = this.props; + fetch(`http://${ip}/set?code=G28`, { method: 'GET', mode: 'no-cors' }); + }; + + stop = () => { + const { ip } = this.props; + fetch(`http://${ip}/set?cmd={P:X}`, { method: 'GET', mode: 'no-cors' }); + }; + + componentWillUnmount() { + this.setState({ mounted: false }); + } + + render() { + const { status } = this.state; + return ( +
+ {status && +

Nozzle temperature: {status.nozzleTemperature}/{status.nozzleTargetTemperature}

+

Bed temperature: {status.bedTemperature}/{status.bedTargetTemperature}

+ {status.state === 'printing' &&

Progress: {status.progress}%

} +
} + + +
+ ); + } +} + +export default muiThemeable()(injectSheet(styles)(MalyanControl)); diff --git a/src/interface/Settings.js b/src/interface/Settings.js index ec45c54..f203012 100644 --- a/src/interface/Settings.js +++ b/src/interface/Settings.js @@ -4,98 +4,420 @@ import _ from 'lodash'; import { Tabs, Tab } from 'material-ui/Tabs'; import MenuItem from 'material-ui/MenuItem'; import injectSheet from 'react-jss'; -import { SelectField, TextField, Checkbox } from './FormComponents.js'; -import { grey800, cyan500 } from 'material-ui/styles/colors'; +import { SelectField, TextField, NumberField, Checkbox } from './FormComponents.js'; +import { grey800, red500 } from 'material-ui/styles/colors'; +import Divider from 'material-ui/Divider'; +import Dialog from 'material-ui/Dialog'; +import FlatButton from 'material-ui/FlatButton'; +import RaisedButton from 'material-ui/RaisedButton'; +import { LOCAL_STORAGE_KEY } from '../constants.js'; +import shortid from 'shortid'; +import defaultSettings from '../settings/default.yml'; +import printerSettings from '../settings/printer.yml'; +import materialSettings from '../settings/material.yml'; +import qualitySettings from '../settings/quality.yml'; +import infillSettings from '../settings/infill.yml'; +import update from 'react-addons-update'; +import SettingsIcon from 'material-ui-icons/Settings'; +import ExitToAppIcon from 'material-ui-icons/ExitToApp'; +import validateIp from 'validate-ip'; +import { Doodle3DManager } from 'doodle3d-api'; + +const DOODLE_3D_MANAGER = new Doodle3DManager(); +DOODLE_3D_MANAGER.checkNonServerBoxes = false; +DOODLE_3D_MANAGER.setAutoUpdate(true, 5000); + +const CONNECT_URL = 'http://connect.doodle3d.com/'; const styles = { textFieldRow: { - display: 'flex' + display: 'flex', + alignItems: 'center' }, container: { width: '100%', flexGrow: 1, overflowY: 'auto', - '& p, h3': { + '& p': { fontWeight: 'bold', margin: '30px 0 0 0' + }, + '& h3': { + fontWeight: 'bold', + marginTop: '20px', + marginBottom: '20px', } + }, + error: { + color: red500 + }, + +}; + +const getLocalStorage = () => { + let localStorage = window.localStorage.getItem(LOCAL_STORAGE_KEY); + + if (!localStorage) { + localStorage = { printers: {}, active: null }; + updateLocalStorage(localStorage); + } else { + localStorage = JSON.parse(localStorage); } + return localStorage; +}; + +const updateLocalStorage = (localStorage) => { + window.localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(localStorage)); }; class Settings extends React.Component { - static childContextTypes = { state: PropTypes.object, onChange: PropTypes.func, disabled: PropTypes.bool }; + static propTypes = { + selectedPrinter: PropTypes.string, + classes: PropTypes.objectOf(PropTypes.string), + onChange: PropTypes.func, + disabled: PropTypes.bool.isRequired + }; static defaultProps: { disabled: false }; - static propTypes = { - classes: PropTypes.objectOf(PropTypes.string), - onChange: PropTypes.func, - printers: PropTypes.object.isRequired, - defaultPrinter: PropTypes.string, - quality: PropTypes.object.isRequired, - defaultQuality: PropTypes.string.isRequired, - material: PropTypes.object.isRequired, - defaultMaterial: PropTypes.string.isRequired, - initialSettings: PropTypes.object.isRequired, - disabled: PropTypes.bool.isRequired + static childContextTypes = { + settings: PropTypes.object.isRequired, + onChange: PropTypes.func.isRequired, + disabled: PropTypes.bool.isRequired, + addPrinter: PropTypes.object.isRequired, + managePrinter: PropTypes.object.isRequired, + activePrinter: PropTypes.string, + advancedFields: PropTypes.array.isRequired }; - constructor(props) { - super(); - this.state = { - settings: props.initialSettings, - printers: props.defaultPrinter, - quality: props.defaultQuality, - material: props.defaultMaterial - }; + + state = { + localStorage: getLocalStorage(), + wifiBoxes: [], + addPrinter: { + open: false, + name: '', + printer: '', + ip: '', + error: null + }, + managePrinter: { + open: false + } + }; + + componentDidMount() { + const { onChange, selectedPrinter } = this.props; + const { localStorage } = this.state; + + if (selectedPrinter && localStorage.active) { + const activePrinter = selectedPrinter && Object.entries(localStorage.printers) + .map(([key, value]) => ({ key, value })) + .find(({ key, value: { ip } }) => ip === selectedPrinter); + + if (activePrinter) { + const state = this.changeSettings('activePrinter', activePrinter.key); + if (onChange) onChange(this.constructSettings(state.localStorage)); + } else { + this.openAddPrinterDialog({ ip: selectedPrinter }); + } + } else if (!selectedPrinter && localStorage.active) { + if (onChange) onChange(this.constructSettings(localStorage)); + } else if (selectedPrinter && !localStorage.active) { + this.openAddPrinterDialog({ ip: selectedPrinter }); + } else if (!selectedPrinter && !localStorage.active) { + this.openAddPrinterDialog(); + } + + const eventListener = ({ boxes }) => this.setState({ wifiBoxes: boxes }); + this.setState({ wifiBoxes: DOODLE_3D_MANAGER.boxes, eventListener }); + DOODLE_3D_MANAGER.addEventListener('boxeschanged', eventListener); + } + + componentWillUnmount() { + const { eventListener } = this.state; + DOODLE_3D_MANAGER.removeEventListener('boxeschanged', eventListener); } changeSettings = (fieldName, value) => { const { onChange } = this.props; + const { localStorage } = this.state; + + let state = _.cloneDeep(this.state); - let state; switch (fieldName) { - case 'printers': - case 'quality': - case 'material': - state = { - [fieldName]: value, - settings: _.merge({}, this.state.settings, this.props[fieldName][value]) - }; + case 'managePrinter.printer': + case 'managePrinter.name': + case 'managePrinter.ip': + state = _.set(state, fieldName, value); + state = update(state, { managePrinter: { error: { $set: null } } }); + break; + + case 'addPrinter.printer': + case 'addPrinter.name': + case 'addPrinter.ip': + state = _.set(state, fieldName, value); + if (fieldName === 'addPrinter.printer') { + state = update(state, { addPrinter: { name: { $set: printerSettings[value].title } } }); + } + state = update(state, { addPrinter: { error: { $set: null } } }); + break; + + case 'activePrinter': + if (value !== 'add_printer') state = update(state, { localStorage: { active: { $set: value } } }); + break; + + case 'settings.infill': + case 'settings.quality': + case 'settings.material': + if (!localStorage.active) return this.openAddPrinterDialog(); + + state = _.set(state, `localStorage.printers[${localStorage.active}].${fieldName}`, value); + break; + + case 'settings.layerHeight': + case 'settings.dimensions.x': + case 'settings.dimensions.y': + case 'settings.dimensions.z': + case 'settings.nozzleDiameter': + case 'settings.bedTemperature': + case 'settings.heatedBed': + case 'settings.filamentThickness': + case 'settings.temperature': + case 'settings.thickness.top': + case 'settings.thickness.bottom': + case 'settings.thickness.shell': + case 'settings.retraction.enabled': + case 'settings.retraction.amount': + case 'settings.retraction.speed': + case 'settings.retraction.minDistance': + case 'settings.travel.speed': + case 'settings.combing': + case 'settings.innerShell.speed': + case 'settings.innerShell.flowRate': + case 'settings.outerShell.speed': + case 'settings.outerShell.flowRate': + case 'settings.innerInfill.density': + case 'settings.innerInfill.speed': + case 'settings.innerInfill.flowRate': + case 'settings.outerInfill.speed': + case 'settings.outerInfill.flowRate': + case 'settings.brim.size': + case 'settings.brim.speed': + case 'settings.brim.flowRate': + case 'settings.firstLayer.speed': + case 'settings.firstLayer.flowRate': + case 'settings.support.enabled': + case 'settings.support.speed': + case 'settings.support.distanceY': + case 'settings.support.density': + case 'settings.support.minArea': + case 'settings.support.margin': + case 'settings.support.speed': + case 'settings.support.flowRate': + if (!localStorage.active) return this.openAddPrinterDialog(); + + if (value === null) { + const advanced = { ...state.localStorage.printers[localStorage.active].settings.advanced }; + delete advanced[fieldName]; + state = update(state, { localStorage: { printers: { [localStorage.active]: { settings: { advanced: { $set: advanced } } } } } }); + } else { + state = _.set(state, `localStorage.printers[${localStorage.active}].settings.advanced[${JSON.stringify(fieldName)}]`, value); + } break; default: - state = _.set(_.cloneDeep(this.state), fieldName, value); break; } - if (onChange) onChange(state); - if (state) this.setState(state); - }; + this.setState(state); + if (localStorage.active) { + if (onChange) onChange(this.constructSettings(state.localStorage)); + updateLocalStorage(state.localStorage); + } + + return state; + } getChildContext() { - return { state: this.state, onChange: this.changeSettings, disabled: this.props.disabled }; + const { localStorage, addPrinter, managePrinter } = this.state; + + return { + addPrinter, + managePrinter, + activePrinter: localStorage.active, + advancedFields: localStorage.active ? Object.keys(localStorage.printers[localStorage.active].settings.advanced) : [], + settings: this.constructSettings(localStorage), + onChange: this.changeSettings, + disabled: this.props.disabled + }; + } + + constructSettings(localStorage) { + if (!localStorage.active) return defaultSettings; + + const { ip, settings: { printer, material, quality, infill, advanced } } = localStorage.printers[localStorage.active]; + let settings = { + ...defaultSettings, + printer, + material, + quality, + infill, + ip + }; + + settings = _.merge({}, settings, printerSettings[printer]); + settings = _.merge({}, settings, qualitySettings[quality]); + settings = _.merge({}, settings, infillSettings[infill]); + settings = _.merge({}, settings, materialSettings[material]); + + for (const key in advanced) { + const value = advanced[key]; + settings = _.set(_.cloneDeep(settings), key.replace('settings.', ''), value); + } + + return settings; + } + + addPrinter = () => { + const { name, printer, ip } = this.state.addPrinter; + + if (!name || !printer) { + this.setState(update(this.state, { addPrinter: { error: { $set: 'Please enter a name and printer' } } })); + return; + } + if (printer === 'doodle3d_printer' && ip !== '' && !validateIp(ip)) { + this.setState(update(this.state, { addPrinter: { error: { $set: 'Please enter a valid IP adress' } } })); + return; + } + + const id = shortid.generate(); + const localStorage = { + active: id, + printers: { + ...this.state.localStorage.printers, + [id]: { name, ip, settings: { printer, material: 'pla', infill: '20pct', quality: 'medium', advanced: {} } } + } + }; + this.setState({ localStorage }); + updateLocalStorage(localStorage); + + this.closeAddPrinterDialog(); + + const { onChange } = this.props; + if (onChange) onChange(this.constructSettings(localStorage)); + }; + + editPrinter = () => { + const { localStorage: { active, printers }, managePrinter: { printer, name, ip } } = this.state; + + if (!name) { + this.setState(update(this.state, { managePrinter: { error: { $set: 'Please enter a name' } } })); + return; + } + if (printer === 'doodle3d_printer' && !validateIp(ip)) { + this.setState(update(this.state, { managePrinter: { error: { $set: 'Please enter a valid IP adress' } } })); + return; + } + + const localStorage = update(this.state.localStorage, { + printers: { + [active]: { + name: { $set: name }, + ip: { $set: ip }, + settings: { + printer: { $set: printer } + } + } + } + }); + this.closeManagePrinterDialog(); + this.setState({ localStorage }); + updateLocalStorage(localStorage); + + const { onChange } = this.props; + if (onChange) onChange(this.constructSettings(localStorage)); + }; + + removeActivePrinter = () => { + let { localStorage: { active, printers } } = this.state; + if (!active) return; + + printers = { ...printers }; + delete printers[active]; + active = Object.keys(printers)[0] || null; + const localStorage = { active, printers }; + + this.closeManagePrinterDialog(); + this.setState({ localStorage }); + updateLocalStorage(localStorage); + + const { onChange } = this.props; + if (onChange) onChange(this.constructSettings(localStorage)); + }; + + closeAddPrinterDialog = (override) => this.setAddPrinterDialog(false, override); + openAddPrinterDialog = (override) => this.setAddPrinterDialog(true, override); + setAddPrinterDialog = (open, override = {}) => this.setState({ + addPrinter: { + ip: '', + name: '', + printer: '', + error: null, + open, + ...override + } + }); + + closeManagePrinterDialog = () => this.setManagePrinterDialog(false); + openManagePrinterDialog = () => this.setManagePrinterDialog(true); + setManagePrinterDialog = (open) => { + const { localStorage: { active, printers } } = this.state; + if (!active) return this.setState({ managePrinter: { open: false } }); + this.setState({ + managePrinter: { + open, + name: printers[active].name, + ip: printers[active].ip, + printer: printers[active].settings.printer, + error: null + } + }); } render() { - const { classes, printers, quality, material, disabled } = this.props; + const { addPrinter, managePrinter, localStorage, wifiBoxes } = this.state; + const { classes, disabled } = this.props; return (
- - {Object.entries(printers).map(([value, { title }]) => ( +
+ + {Object.entries(localStorage.printers).map(([id, { name }]) => ( + + ))} + + + + {localStorage.active && } +
+ + {Object.entries(materialSettings).map(([value, { title }]) => ( ))} - - {Object.entries(material).map(([value, { title }]) => ( - - ))} - -

Printer Setup

- +

Print Setup

+
- - {Object.entries(quality).map(([value, { title }]) => ( + + {Object.entries(qualitySettings).map(([value, { title }]) => ( + + ))} + + + {Object.entries(infillSettings).map(([value, { title }]) => ( ))} @@ -104,59 +426,119 @@ class Settings extends React.Component {

Layer

- -

Printer dimensions

-
- - - -
-

Nozzle

- -

Bed

- - -

Material

- - +

Thickness

- - - + + + +

Material

+ + +

Bed

+ + +

Brim

+ + + +

Support

+ + + + + + + +

First layer

+ + +

Inner shell

+ + +

Outer shell

+ + +

Inner infill

+ + + +

Outer infill

+ + +

Travel

+ +

Retraction

- - - -

Travel

- - -

Inner shell

- - -

Outer shell

- - -

Inner infill

- - - -

Outer infill

- - -

Brim

- - - -

First layer

- - + + + +

Printer dimensions

+
+ + + +
+

Nozzle

+
+ {printDialog(this.props, this.state, 'Add Printer', 'addPrinter', 'Add', addPrinter, localStorage.active && this.closeAddPrinterDialog, null, this.addPrinter)} + {printDialog(this.props, this.state, 'Manage Printer', 'managePrinter', 'Save', managePrinter, this.closeManagePrinterDialog, this.removeActivePrinter, this.editPrinter)}
); } } +function printDialog(props, state, title, form, submitText, data, closeDialog, removeActivePrinter, save) { + const { classes } = props; + const { wifiBoxes } = state; + + return ( + , + removeActivePrinter && , + + ]} + > + + {Object.entries(printerSettings).map(([value, { title }]) => ( + + ))} + + + {(data.printer === 'doodle3d_printer') ? + : +
+ + {wifiBoxes.map(({ localip, id, wifiboxid }) => ())} + + {data.ip && window.open(`${CONNECT_URL}/?uuid=0#control?localip=${data.ip}`, '_blank')} + style={{ fill: grey800, marginLeft: '10px', cursor: 'pointer' }} + />} +
+ } + {data.error &&

{data.error}

} +
+ ); +} + export default injectSheet(styles)(Settings); diff --git a/src/interface/WifiBoxControl.js b/src/interface/WifiBoxControl.js new file mode 100644 index 0000000..5720e35 --- /dev/null +++ b/src/interface/WifiBoxControl.js @@ -0,0 +1,59 @@ +import React from 'react'; +import PropTypes from 'proptypes'; +import muiThemeable from 'material-ui/styles/muiThemeable'; +import injectSheet from 'react-jss'; +import FlatButton from 'material-ui/FlatButton'; +import { Doodle3DBox } from 'doodle3d-api'; + +const styles = { + +}; + +class WifiBoxControl extends React.Component { + static propTypes = { + ip: PropTypes.string.isRequired + }; + + state = { + box: null, + status: null + }; + + componentDidMount = async () => { + const { ip } = this.props; + + const box = new Doodle3DBox(ip); + window.d3dbox = box; + box.addEventListener('update', ({ state }) => this.setState({ status: state })); + box.setAutoUpdate(true, 5000); + + this.setState({ box }); + + const alive = await box.checkAlive(); + }; + + stop = async () => { + const { box } = this.state; + const result = await box.printer.stop(); + console.log('result: ', result); + }; + + componentWillUnmount() { + const { box } = this.state; + if (box) box.setAutoUpdate(false); + + this.setState({ mounted: false }); + } + + render() { + const { status } = this.state; + + return ( +
+ +
+ ); + } +} + +export default muiThemeable()(injectSheet(styles)(WifiBoxControl)); diff --git a/src/interface/index.js b/src/interface/index.js index 6fc92c9..c89de2f 100644 --- a/src/interface/index.js +++ b/src/interface/index.js @@ -1,10 +1,8 @@ +import * as THREE from 'three'; import _ from 'lodash'; import React from 'react'; -import { Quaternion } from 'three/src/math/Quaternion.js'; -import { Vector3 } from 'three/src/math/Vector3.js'; -import { Mesh } from 'three/src/objects/Mesh.js'; import PropTypes from 'proptypes'; -import { placeOnGround, createScene, fetchProgress, slice, TabTemplate } from './utils.js'; +import { centerGeometry, placeOnGround, createScene, slice, TabTemplate } from './utils.js'; import injectSheet from 'react-jss'; import RaisedButton from 'material-ui/RaisedButton'; import FlatButton from 'material-ui/FlatButton'; @@ -16,11 +14,15 @@ import Menu from 'material-ui/Menu'; import MenuItem from 'material-ui/MenuItem'; import { Tabs, Tab } from 'material-ui/Tabs'; import Settings from './Settings.js'; -import defaultSettings from '../settings/default.yml'; -import printerSettings from '../settings/printer.yml'; -import materialSettings from '../settings/material.yml'; -import qualitySettings from '../settings/quality.yml'; +// import MalyanControl from './MalyanControl.js'; +// import WifiBoxControl from './WifiBoxControl.js'; import ReactResizeDetector from 'react-resize-detector'; +import JSONToSketchData from 'doodle3d-core/shape/JSONToSketchData'; +import createSceneData from 'doodle3d-core/d3/createSceneData.js'; +import { generateExportMesh } from 'doodle3d-core/utils/exportUtils.js'; +import muiThemeable from 'material-ui/styles/muiThemeable'; +import Dialog from 'material-ui/Dialog'; +import logo from '../../img/logo.png'; const MAX_FULLSCREEN_WIDTH = 720; @@ -49,15 +51,22 @@ const styles = { settingsBar: { display: 'flex', flexDirection: 'column', - maxWidth: '380px', + maxWidth: '320px', boxSizing: 'border-box', - padding: '10px', + padding: '10px 20px', backgroundColor: 'white', borderLeft: `1px solid ${grey300}` }, sliceActions: { flexShrink: 0, }, + sliceInfo: { + margin: '10px 0', + '& p': { + marginBottom: '5px', + fontSize: '11px' + } + }, sliceButtons: { justifyContent: 'flex-end', display: 'flex' @@ -66,7 +75,7 @@ const styles = { margin: '5px 0 5px 5px' }, controlButton: { - marginRight: '2px' + marginRight: '5px' }, buttonContainer: { width: '100%', @@ -76,77 +85,112 @@ const styles = { color: red500 }, title: { - position: 'absolute' + userSelect: 'none', + position: 'absolute', + left: '10px' + }, + detail: { + userSelect: 'none', + marginTop: '10px', + marginBottom: '10px' + }, + logo: { + position: 'absolute', + left: '20px', + top: '20px', + width: '150px', + height: '51px' } }; class Interface extends React.Component { static propTypes = { - mesh: PropTypes.shape({ isMesh: PropTypes.oneOf([true]) }).isRequired, + fileUrl: PropTypes.string, + selectedPrinter: PropTypes.string, + mesh: PropTypes.shape({ isMesh: PropTypes.oneOf([true]) }), classes: PropTypes.objectOf(PropTypes.string), - defaultSettings: PropTypes.object.isRequired, - printers: PropTypes.object.isRequired, - defaultPrinter: PropTypes.string, - quality: PropTypes.object.isRequired, - defaultQuality: PropTypes.string.isRequired, - material: PropTypes.object.isRequired, - defaultMaterial: PropTypes.string.isRequired, pixelRatio: PropTypes.number.isRequired, onCancel: PropTypes.func, - name: PropTypes.string.isRequired + name: PropTypes.string.isRequired, + muiTheme: PropTypes.object.isRequired, + allowDragDrop: PropTypes.bool.isRequired, + actions: PropTypes.arrayOf(PropTypes.shape({ target: PropTypes.string })) }; static defaultProps = { - defaultSettings: defaultSettings, - printers: printerSettings, - quality: qualitySettings, - defaultQuality: 'medium', - material: materialSettings, - defaultMaterial: 'pla', + actions: [{ + target: 'WIFI_PRINT', + title: 'Print over WiFi' + }, { + target: 'DOWNLOAD', + title: 'Download GCode' + }], pixelRatio: 1, - name: 'Doodle3D' + name: 'Doodle3D', + allowDragDrop: true }; constructor(props) { super(props); - const { defaultPrinter, defaultQuality, defaultMaterial, printers, quality, material, defaultSettings } = props; + + const scene = createScene(this.props); this.state = { - showFullScreen: false, + scene, + settings: null, + showFullScreen: window.innerWidth > MAX_FULLSCREEN_WIDTH, isSlicing: false, error: null, - printers: defaultPrinter, - quality: defaultQuality, - material: defaultMaterial, - popover: { - element: null, - open: false - }, - settings: _.merge( - {}, - defaultSettings, - printers[defaultPrinter], - quality[defaultQuality], - material[defaultMaterial] - ) + mesh: null, + objectDimensions: '0x0x0mm', + popover: { open: false, element: null } }; } componentDidMount() { const { canvas } = this.refs; + const { scene } = this.state; + scene.updateCanvas(canvas); - const scene = createScene(canvas, this.props, this.state); - this.setState({ ...scene }); + const { mesh, fileUrl } = this.props; + if (mesh) { + this.updateMesh(mesh, scene); + } else if (fileUrl) { + this.loadFile(fileUrl); + } + } + + loadFile = (fileUrl) => { + const { origin, pathname, password, username, port } = new URL(fileUrl); + const headers = {}; + if (password && username) headers.Authorization = `Basic ${btoa(`${username}:${password}`)}`; + + fetch(`${origin}${port}${pathname}`, { headers }) + .then(resonse => resonse.json()) + .then(json => JSONToSketchData(json)) + .then(file => createSceneData(file)) + .then(sketch => generateExportMesh(sketch, { offsetSingleWalls: false, matrix: new THREE.Matrix4() })) + .then(mesh => this.updateMesh(mesh)); + }; + + updateMesh(mesh, scene = this.state.scene) { + scene.mesh.geometry = mesh.geometry; + centerGeometry(scene.mesh); + placeOnGround(scene.mesh); + this.calculateDimensions(); + scene.render(); + + this.setState({ mesh }); } componentWillUnmount() { - const { editorControls, mesh: { material }, renderer } = this.state; + const { scene: { editorControls, mesh: { material }, renderer } } = this.state; editorControls.dispose(); material.dispose(); renderer.dispose(); } resetMesh = () => { - const { mesh, render, isSlicing } = this.state; + const { scene: { mesh, render }, isSlicing } = this.state; if (isSlicing) return; if (mesh) { mesh.position.set(0, 0, 0); @@ -154,6 +198,7 @@ class Interface extends React.Component { mesh.rotation.set(0, 0, 0); mesh.updateMatrix(); placeOnGround(mesh); + this.calculateDimensions(); render(); } }; @@ -161,46 +206,58 @@ class Interface extends React.Component { scaleUp = () => this.scaleMesh(0.9); scaleDown = () => this.scaleMesh(1.0 / 0.9); scaleMesh = (factor) => { - const { mesh, render, isSlicing } = this.state; + const { scene: { mesh, render }, isSlicing } = this.state; if (isSlicing) return; if (mesh) { mesh.scale.multiplyScalar(factor); mesh.updateMatrix(); placeOnGround(mesh); + this.calculateDimensions(); render(); } }; - rotateX = () => this.rotate(new Vector3(0, 0, 1), Math.PI / 2.0); - rotateY = () => this.rotate(new Vector3(1, 0, 0), Math.PI / 2.0); - rotateZ = () => this.rotate(new Vector3(0, 1, 0), Math.PI / 2.0); + rotateX = () => this.rotate(new THREE.Vector3(0, 0, 1), Math.PI / 2.0); + rotateY = () => this.rotate(new THREE.Vector3(1, 0, 0), Math.PI / 2.0); + rotateZ = () => this.rotate(new THREE.Vector3(0, 1, 0), Math.PI / 2.0); rotate = (axis, angle) => { - const { mesh, render, isSlicing } = this.state; + const { scene: { mesh, render }, isSlicing } = this.state; if (isSlicing) return; if (mesh) { mesh.rotateOnWorldAxis(axis, angle); placeOnGround(mesh); + this.calculateDimensions(); render(); } }; - slice = async (target) => { - const { isSlicing, settings, printers, quality, material, mesh: { matrix } } = this.state; - const { name, mesh } = this.props; + slice = async (action) => { + const { isSlicing, settings, mesh, scene: { material, mesh: { matrix } } } = this.state; + const { name } = this.props; if (isSlicing) return; + if (!settings) { + this.setState({ error: 'please select a printer first' }); + return; + } + if (action.target === 'WIFI_PRINT' && !settings.ip) { + this.setState({ error: 'please connect to a WiFi enabled printer' }); + return; + } + if (!mesh) { + this.setState({ error: 'there is no file to slice' }); + return; + } this.closePopover(); - this.setState({ isSlicing: true, progress: { action: '', percentage: 0, step: 0 }, error: null }); - const exportMesh = new Mesh(mesh.geometry, mesh.material); + const exportMesh = new THREE.Mesh(mesh.geometry, mesh.material); exportMesh.applyMatrix(matrix); try { - await slice(target, name, exportMesh, settings, printers, quality, material, progress => { - this.setState({ progress: { ...this.state.progress, ...progress } }); - }); + const updateProgres = progress => this.setState({ progress: { ...this.state.progress, ...progress } }); + await slice(action, name, exportMesh, settings, updateProgres); } catch (error) { this.setState({ error: error.message }); throw error; @@ -228,31 +285,15 @@ class Interface extends React.Component { }); }; - onChangeSettings = (settings) => { - this.setState(settings); - }; - - componentWillUpdate(nextProps, nextState) { - const { box, render, setSize } = this.state; - let changed = false; - if (box && nextState.settings.dimensions !== this.state.settings.dimensions) { - const { dimensions } = nextState.settings; - box.scale.set(dimensions.y, dimensions.z, dimensions.x); - box.updateMatrix(); - changed = true; - } - if (changed) render(); - } - componentDidUpdate() { - const { updateCanvas } = this.state; + const { scene: { updateCanvas } } = this.state; const { canvas } = this.refs; if (updateCanvas && canvas) updateCanvas(canvas); } onResize3dView = (width, height) => { window.requestAnimationFrame(() => { - const { setSize } = this.state; + const { scene: { setSize } } = this.state; const { pixelRatio } = this.props; if (setSize) setSize(width, height, pixelRatio); }); @@ -262,55 +303,105 @@ class Interface extends React.Component { this.setState({ showFullScreen: width > MAX_FULLSCREEN_WIDTH }); }; + onChangeSettings = (settings) => { + const { scene: { box, render } } = this.state; + + let changed = false; + if (!this.state.settings || this.state.settings.dimensions !== settings.dimensions) { + box.scale.set(settings.dimensions.y, settings.dimensions.z, settings.dimensions.x); + box.updateMatrix(); + changed = true; + } + if (changed) render(); + + this.setState({ settings, error: null }); + }; + + calculateDimensions = () => { + const { scene: { mesh } } = this.state; + const { x, y, z } = new THREE.Box3().setFromObject(mesh).getSize(); + this.setState({ objectDimensions: `${Math.round(y)}x${Math.round(z)}x${Math.round(x)}mm` }); + }; + + onDrop = (event) => { + event.preventDefault(); + if (!this.props.allowDragDrop) return; + + for (const file of event.dataTransfer.files) { + const extentions = file.name.split('.').pop(); + + switch (extentions.toUpperCase()) { + case 'D3SKETCH': + this.loadFile(URL.createObjectURL(file)); + break; + default: + break; + } + } + } + render() { - const { classes, defaultPrinter, defaultQuality, defaultMaterial, onCancel } = this.props; - const { isSlicing, progress, settings, printers, quality, material, showFullScreen, error } = this.state; + const { classes, onCancel, selectedPrinter, actions } = this.props; + const { isSlicing, progress, showFullScreen, error, objectDimensions, settings } = this.state; const style = { ...(showFullScreen ? {} : { maxWidth: 'inherit', width: '100%', height: '100%' }) }; const settingsPanel = (
- {error &&

{error}

} - {isSlicing &&

{progress.action}

} - {isSlicing && } +
+ {error &&

{error}

} + {isSlicing &&

{progress.action}

} + {isSlicing && } +
{onCancel && } - - - - this.slice('WIFI')} /> - this.slice('DOWNLOAD')} /> - - + {/* (settings && settings.ip) && ((settings.printer === 'doodle3d_printer') ? + : + + ) */} + {actions.length === 1 ? ( + this.slice(actions[0])} + className={`${classes.button}`} + disabled={isSlicing} + /> + ) : ( + + + + + {actions.map((action) => ( + this.slice(action)} /> + ))} + + + + )}
@@ -321,6 +412,9 @@ class Interface extends React.Component {
+
+

Dimensions: {objectDimensions}

+
@@ -333,16 +427,32 @@ class Interface extends React.Component { if (showFullScreen) { return ( -
+
{ + if (container) { + container.addEventListener('dragover', event => event.preventDefault()); + container.addEventListener('drop', this.onDrop); + } + }} + > -

Print

+ {d3Panel} {settingsPanel}
); } else { return ( -
+
{ + if (container) { + container.addEventListener('dragover', event => event.preventDefault()); + container.addEventListener('drop', this.onDrop); + } + }} + > renderer.render(scene, camera); @@ -74,64 +65,111 @@ export function createScene(canvas, props, state) { render(); }; - let editorControls; - let renderer; const updateCanvas = (canvas) => { if (!renderer || renderer.domElement !== canvas) { if (renderer) renderer.dispose(); - renderer = new WebGLRenderer({ canvas, alpha: true, antialias: true }); + renderer = new THREE.WebGLRenderer({ canvas, alpha: true, antialias: true }); renderer.setClearColor(0xffffff, 0); } if (!editorControls || editorControls.domElement !== canvas) { if (editorControls) editorControls.dispose(); editorControls = new THREE.EditorControls(camera, canvas); - editorControls.focus(mesh); editorControls.addEventListener('change', render); } render(); }; - updateCanvas(canvas); const focus = () => editorControls.focus(mesh); return { editorControls, scene, mesh, camera, renderer, render, box, setSize, updateCanvas, focus }; } -export function fetchProgress(url, { method = 'get', headers = {}, body = {} } = {}, onProgress) { +export function fetchProgress(url, data = {}, onProgress) { return new Promise((resolve, reject) => { + const request = new Request(url, data); const xhr = new XMLHttpRequest(); - xhr.open(method, url); - if (headers) { - for (const key in headers) { - const header = headers[key]; - xhr.setRequestHeader(key, header); - } + + xhr.onload = () => { + resolve(new Response(xhr.response)); + // const headers = new Headers(xhr.getAllResponseHeaders() || ''); + // const { status, statusText, response, responseText, responseURL: url = headers.get('X-Request-URL') } = xhr; + // resolve(new Response(response || responseText, { headers, status, statusText, url })); + } + xhr.onerror = () => reject(new TypeError('Network request failed')); + xhr.ontimeout = () => reject(new TypeError('Network request failed')); + + xhr.open(request.method, url, true); + + if (request.credentials === 'include') { + xhr.withCredentials = true + } else if (request.credentials === 'omit') { + xhr.withCredentials = false } - xhr.onload = event => resolve(event.target.responseText); - xhr.onerror = reject; if (xhr.upload && onProgress) xhr.upload.onprogress = onProgress; - xhr.send(body); + if (xhr.responseType) xhr.responseType = 'blob'; + + // request.headers.forEach((value, name) => xhr.setRequestHeader(name, value)); + + xhr.send(data.body); }); } +export function getMalyanStatus(ip) { + return fetch(`http://${ip}/inquiry`, { method: 'GET' }) + .then(response => response.text()) + .then(statusText => { + const [nozzleTemperature, nozzleTargetTemperature, bedTemperature, bedTargetTemperature, progress] = statusText.match(/\d+/g); + const status = { nozzleTemperature, nozzleTargetTemperature, bedTemperature, bedTargetTemperature, progress }; + + switch (statusText.charAt(statusText.length - 1)) { + case 'I': + status.state = 'idle'; + break; + case 'P': + status.state = 'printing'; + break; + default: + status.state = 'unknown'; + break; + } + return status; + }) +} + +export function sleep(time) { + return new Promise(resolve => setTimeout(resolve, time)); +} + const GCODE_SERVER_URL = 'https://gcodeserver.doodle3d.com'; -const CONNECT_URL = 'http://connect.doodle3d.com/'; - -export async function slice(target, name, mesh, settings, printers, quality, material, updateProgress) { - if (!printers) throw new Error('Please select a printer'); +export async function slice(action, name, mesh, settings, updateProgress) { let steps; let currentStep = 0; - switch (target) { + let wifiBox; + switch (action.target) { case 'DOWNLOAD': steps = 1; break; - case 'WIFI': + case 'WIFI_PRINT': + if (settings.printer === 'doodle3d_printer') { + const { state } = await getMalyanStatus(settings.ip); + if (state !== 'idle') throw { message: 'printer is busy', code: 0 }; + + } else { + wifiBox = new Doodle3DBox(settings.ip); + if (!await wifiBox.checkAlive()) throw { message: `can't connect to printer`, code: 4 } + + const { state } = await wifiBox.info.status(); + if (state !== 'idle') throw { message: 'printer is busy', code: 0 }; + } + steps = 2; + break; + case 'CUSTOM_UPLOAD': steps = 2; break; default: - steps = 1; + throw { message: 'unknown target', code: 1 }; break; } @@ -139,64 +177,99 @@ export async function slice(target, name, mesh, settings, printers, quality, mat const centerX = dimensions.x / 2; const centerY = dimensions.y / 2; - const matrix = new Matrix4().makeTranslation(centerY, 0, centerX).multiply(mesh.matrix); - const { gcode } = await sliceGeometry(settings, mesh.geometry, mesh.material, matrix, false, false, ({ progress }) => { + const matrix = new THREE.Matrix4().makeTranslation(centerY, 0, centerX) + .multiply(new THREE.Matrix4().makeRotationY(-Math.PI / 2.0)) + .multiply(mesh.matrix); + + const { gcode } = await sliceGeometry({ + ...settings, + name: `${name}.gcode`, + printer: { type: settings.printers, title: printerSettings[settings.printer].title }, + material: { type: settings.material, title: materialSettings[settings.material].title }, + quality: { type: settings.quality, title: qualitySettings[settings.quality].title } + }, mesh.geometry, mesh.material, matrix, false, false, ({ progress }) => { updateProgress({ action: progress.action, - percentage: currentStep / steps + progress.done / progress.total / steps + percentage: (currentStep + progress.done / progress.total) / steps }); + }).catch(error => { + throw { message: `error during slicing: ${error.message}`, code: 2 }; }); currentStep ++; - switch (target) { + switch (action.target) { case 'DOWNLOAD': { - const blob = new File([gcode], `${name}.gcode`, { type: 'text/plain;charset=utf-8' }); - fileSaver.saveAs(blob); + fileSaver.saveAs(gcode, `${name}.gcode`); break; } - case 'WIFI': { - // upload G-code file to AWS S3 - const { data: { reservation, id } } = await fetch(`${GCODE_SERVER_URL}/upload`, { method: 'POST' }) - .then(response => response.json()); + case 'WIFI_PRINT': { + if (settings.printer === 'doodle3d_printer') { + const body = new FormData(); + body.append('file', gcode, 'doodle.gcode'); - const body = new FormData(); - const { fields } = reservation; - for (const key in fields) { - body.append(key, fields[key]); - } + // because fetch has no way of retrieving progress we fake progress + let loaded = 0; + const interval = setInterval(() => { + loaded += 15 * 1024; + updateProgress({ + action: 'Uploading to printer', + percentage: (currentStep + loaded / file.size) / steps + }); + }, 1000); - const file = ';' + JSON.stringify({ - name: `${name}.gcode`, - ...settings, - printer: { - type: printers, - title: printerSettings[printers].title - }, - material: { - type: material, - title: materialSettings[material].title - }, - quality: { - type: quality, - title: qualitySettings[quality].title + // await fetchProgress(`http://${settings.ip}/set?code=M563 S4`, { method: 'GET' }); + await fetch(`http://${settings.ip}/upload`, { method: 'POST', body, mode: 'no-cors' }, (progress) => { + updateProgress({ + action: 'Uploading to printer', + percentage: (currentStep + progress.loaded / progress.total) / steps + }); + }); + clearInterval(interval); + await fetch(`http://${settings.ip}/set?code=M566 ${name}.gcode`, { method: 'GET', mode: 'no-cors' }); + await fetch(`http://${settings.ip}/set?code=M565`, { method: 'GET', mode: 'no-cors' }); + + currentStep ++; + } else { + // upload G-code file to AWS S3 + const { data: { reservation: { fields, url }, id } } = await fetch(`${GCODE_SERVER_URL}/upload`, { method: 'POST' }) + .then(response => response.json()); + + const body = new FormData(); + for (const key in fields) { + body.append(key, fields[key]); } - }).trim() + '\n' + gcode; - body.append('file', file); - await fetchProgress(reservation.url, { method: 'POST', body }, (progess) => { + body.append('file', gcode, 'doodle.gcode'); + + await fetchProgress(url, { method: 'POST', body }, progress => { + updateProgress({ + action: 'Uploading', + percentage: (currentStep + progress.loaded / progress.total) / steps + }); + }); + currentStep ++; + + const result = await wifiBox.printer.fetch(id); + } + break; + } + case 'CUSTOM_UPLOAD': { + const body = new FormData(); + body.append('file', gcode, 'doodle.gcode'); + + await fetchProgress(action.url, { method: 'POST', body }, progress => { updateProgress({ action: 'Uploading', - percentage: currentStep / steps + progess.loaded / progess.total / steps + percentage: (currentStep + progress.loaded / progress.total) / steps }); }); currentStep ++; - - const popup = window.open(`${CONNECT_URL}?uuid=${id}`, '_blank'); - if (!popup) throw new Error('popup was blocked by browser'); + break; } default: + throw { message: 'unknown target', code: 1 }; break; } } diff --git a/src/settings/default.yml b/src/settings/default.yml index 30f552d..8167357 100644 --- a/src/settings/default.yml +++ b/src/settings/default.yml @@ -1,4 +1,30 @@ -zOffset: 0.3 +startCode: |- + M109 S{temperature} ;set target temperature + {if heatedBed}M190 S{bedTemperature} ;set target bed temperature + G21 ;metric values + M107 ;start with the fan off + G28 X0 Y0 ;move X/Y to min endstops + G28 Z0 ;move Z to min endstops + G1 Z15 F9000 ;move the platform down 15mm + G92 E0 ;zero the extruded length + G91 ;relative positioning + G1 F200 E10 ;extrude 10mm of feed stock + G92 E0 ;zero the extruded length again + G92 E0 ;zero the extruded length again + G1 F9000 + G90 ;absolute positioning + M117 Printing Doodle... +endCode: |- + M107 ;fan off + G91 ;relative positioning + G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure + G1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more + G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way + M84 ;disable axes / steppers + G90 ;absolute positioning + M104 S0 + {if heatedBed}M140 S0 + M117 Done dimensions: x: 200 y: 200 @@ -7,7 +33,7 @@ heatedBed: false nozzleDiameter: 0.4 filamentThickness: 2.85 temperature: 210 -bedTemperature: 70 +bedTemperature: 50 layerHeight: 0.15 combing: true thickness: @@ -23,11 +49,10 @@ travel: speed: 200.0 support: enabled: false - acceptanceMargin: 1.5 + minArea: 2 distanceY: 0.4 - gridSize: 6.0 + density: 5.0 margin: 2.0 - plateSize: 4.0 flowRate: 0.8 speed: 40.0 innerShell: @@ -39,12 +64,12 @@ outerShell: innerInfill: flowRate: 1.0 speed: 80.0 - gridSize: 15.0 + density: 20.0 outerInfill: flowRate: 1.0 speed: 50.0 brim: - offset: 4.0 + size: 8.0 flowRate: 1.0 speed: 40.0 firstLayer: diff --git a/src/settings/infill.yml b/src/settings/infill.yml new file mode 100644 index 0000000..14cabb6 --- /dev/null +++ b/src/settings/infill.yml @@ -0,0 +1,21 @@ +0pct: + title: Hollow (0%) + innerInfill: + density: 0.0 +10pct: + title: Light (10%) + innerInfill: + density: 10.0 +20pct: + title: Normal (20%) + innerInfill: + density: 20.0 +50pct: + title: Dense (50%) + innerInfill: + density: 50.0 +100pct: + title: Solid (100%) + innerInfill: + density: 100.0 + diff --git a/src/settings/printer.yml b/src/settings/printer.yml index 3bc6504..efd5b61 100644 --- a/src/settings/printer.yml +++ b/src/settings/printer.yml @@ -1,3 +1,33 @@ +doodle3d_printer: + startCode: |- + M140 S{bedTemperature} + {if heatedBed}M104 S{temperature} + G28 + M109 S{temperature} + {if heatedBed}M190 S{bedTemperature} + G90 + M82 + G1 Z10.0 F6000 + G92 E0 + G1 F200 E3 + G92 E0 + endCode: |- + M104 S0 + M140 S0 + G92 E1 + G1 E-1 F300 + G28 X0 Y0 + M84 + M82 + M104 S0 + title: Doodle3D Printer + heatedBed: true + bedTemperature: 50 + filamentThickness: 1.75 + dimensions: + x: 120 + y: 120 + z: 120 _3Dison_plus: title: 3Dison plus heatedBed: false @@ -267,11 +297,50 @@ ultimaker2_plus: title: Ultimaker 2+ heatedBed: true filamentThickness: 2.85 + dimensions: + x: 223 + y: 223 + z: 205 +ultimaker2_plus_extended: + title: Ultimaker 2+ Extended + heatedBed: true + filamentThickness: 2.85 dimensions: x: 223 y: 223 z: 305 ultimaker2go: + startCode: |- + M10000 + M10000 + M10001 X8 Y28 SDoodle3D heat up... + M109 S{temperature} ;set target temperature + {if heatedBed}M190 S{bedTemperature} ;set target bed temperature + G21 ;metric values + G90 ;absolute positioning + M107 ;start with the fan off + G28 ; home to endstops + G1 Z15 F9000 ;move the platform down 15mm + G92 E0 ;zero the extruded length + G1 F200 E10 ;extrude 10mm of feed stock + G92 E0 ;zero the extruded length again + G1 F9000 + M10000 + M10000 + M10001 X8 Y28 SDoodle3D printing... + endCode: |- + M10000 + M10000 + M10001 X20 Y28 SDoodle3D done! + M107 ;fan off + G91 ;relative positioning + G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure + G1 Z+5.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more + G28 ;home the printer + M84 ;disable axes / steppers + G90 ;absolute positioning + M104 S0 + {if heatedBed}M140 S0 title: Ultimaker 2 Go heatedBed: false filamentThickness: 2.85 diff --git a/src/settings/quality.yml b/src/settings/quality.yml index 967a7b0..96134d9 100644 --- a/src/settings/quality.yml +++ b/src/settings/quality.yml @@ -15,7 +15,7 @@ low: speed: 70.0 innerInfill: speed: 80.0 - gridSize: 25.0 + density: 10.0 medium: title: "Medium" layerHeight: .15 @@ -33,7 +33,7 @@ medium: speed: 40.0 innerInfill: speed: 80.0 - gridSize: 25.0 + density: 10.0 high: title: "High" thickness: @@ -51,4 +51,4 @@ high: speed: 30.0 innerInfill: speed: 70.0 - gridSize: 10.0 + density: 20.0 diff --git a/src/sliceActions/addBrim.js b/src/sliceActions/addBrim.js index 122f140..201d0fc 100644 --- a/src/sliceActions/addBrim.js +++ b/src/sliceActions/addBrim.js @@ -1,24 +1,36 @@ import Shape from 'clipper-js'; import { PRECISION } from '../constants.js'; -const offsetOptions = { +const OFFSET_OPTIONS = { jointType: 'jtRound', miterLimit: 2.0, - roundPrecision: 0.25 + roundPrecision: 0.25, + endType: 'etClosedPolygon' }; export default function addBrim(slices, settings) { let { - brim: { offset: brimOffset } + brim: { size: brimSize }, + nozzleDiameter } = settings; - brimOffset /= PRECISION; + + nozzleDiameter /= PRECISION; + brimSize /= PRECISION; + const nozzleRadius = nozzleDiameter / 2; const [firstLayer] = slices; - firstLayer.brim = firstLayer.parts.reduce((brim, { shape }) => ( - brim.join(shape.offset(brimOffset, { - ...offsetOptions, + const brim = firstLayer.parts.reduce((brim, { shape }) => ( + brim.join(shape.offset(nozzleRadius, { + ...OFFSET_OPTIONS, endType: shape.closed ? 'etClosedPolygon' : 'etOpenRound' })) ), new Shape([], true)).simplify('pftNonZero'); + + firstLayer.brim = new Shape([], true); + + for (let offset = 0; offset < brimSize; offset += nozzleDiameter) { + const brimPart = brim.offset(offset, OFFSET_OPTIONS); + firstLayer.brim = firstLayer.brim.join(brimPart); + } } diff --git a/src/sliceActions/applyPrecision.js b/src/sliceActions/applyPrecision.js index 0f23b23..6f20854 100644 --- a/src/sliceActions/applyPrecision.js +++ b/src/sliceActions/applyPrecision.js @@ -1,4 +1,4 @@ -import { devide } from './helpers/VectorUtils.js'; +import { divide } from './helpers/vector2.js'; import { PRECISION } from '../constants.js' export default function applyPrecision(layers) { @@ -16,7 +16,7 @@ function scaleUpShape(shape) { const path = shape[i]; for (let i = 0; i < path.length; i ++) { - path[i] = devide(path[i], PRECISION); + path[i] = divide(path[i], PRECISION); } } } diff --git a/src/sliceActions/calculateLayersIntersections.js b/src/sliceActions/calculateLayersIntersections.js index c077bd9..1d91f51 100644 --- a/src/sliceActions/calculateLayersIntersections.js +++ b/src/sliceActions/calculateLayersIntersections.js @@ -1,26 +1,25 @@ +import { Z_OFFSET } from '../constants.js'; + export default function calculateLayersIntersections(lines, settings) { const { dimensions: { z: dimensionsZ }, - layerHeight, - zOffset + layerHeight } = settings; - const numLayers = Math.floor((dimensionsZ - zOffset) / layerHeight); + const numLayers = Math.floor((dimensionsZ - Z_OFFSET) / layerHeight); - const layers = Array.from(Array(numLayers)).map(() => ({ - points: {}, - faceIndexes: [] - })); + const layerPoints = Array.from(Array(numLayers)).map(() => ({})); + const layerFaceIndexes = Array.from(Array(numLayers)).map(() => []); for (let lineIndex = 0; lineIndex < lines.length; lineIndex ++) { const { line, faces } = lines[lineIndex]; - const min = Math.ceil((Math.min(line.start.y, line.end.y) - zOffset) / layerHeight); - const max = Math.floor((Math.max(line.start.y, line.end.y) - zOffset) / layerHeight); + const min = Math.ceil((Math.min(line.start.y, line.end.y) - Z_OFFSET) / layerHeight); + const max = Math.floor((Math.max(line.start.y, line.end.y) - Z_OFFSET) / layerHeight); for (let layerIndex = min; layerIndex <= max; layerIndex ++) { if (layerIndex >= 0 && layerIndex < numLayers) { - const y = layerIndex * layerHeight + zOffset; + const y = layerIndex * layerHeight + Z_OFFSET; let x, z; if (line.start.y === line.end.y) { @@ -33,20 +32,14 @@ export default function calculateLayersIntersections(lines, settings) { z = line.end.z * alpha + line.start.z * alpha1; } - layers[layerIndex].points[lineIndex] = { x: z, y: x }; - layers[layerIndex].faceIndexes.push(...faces); + layerPoints[layerIndex][lineIndex] = { x: z, y: x }; + for (const faceIndex of faces) { + const layerFaceIndex = layerFaceIndexes[layerIndex]; + if (!layerFaceIndex.includes(faceIndex)) layerFaceIndex.push(faceIndex); + } } } } - for (let i = 0; i < layers.length; i ++) { - const layer = layers[i]; - - layer.faceIndexes = layer.faceIndexes.reduce((result, faceIndex) => { - if (!result.includes(faceIndex)) result.push(faceIndex); - return result; - }, []); - } - - return layers; + return { layerPoints, layerFaceIndexes }; } diff --git a/src/sliceActions/createLines.js b/src/sliceActions/createLines.js index 62b7c19..9fff900 100644 --- a/src/sliceActions/createLines.js +++ b/src/sliceActions/createLines.js @@ -1,42 +1,70 @@ -import { Line3 } from 'three/src/math/Line3.js'; -import { normalize } from './helpers/VectorUtils.js'; +import * as vector2 from './helpers/vector2.js'; +import * as vector3 from './helpers/vector3.js'; -function addLine(geometry, lineLookup, lines, a, b, faceIndex) { +export default function createLines(geometry, settings) { + const faces = []; + const lines = []; + const lineLookup = {}; + + for (let i = 0; i < geometry.objectIndexes.length; i ++) { + const objectIndex = geometry.objectIndexes[i]; + const { x: a, y: b, z: c } = getVertex(geometry.faces, i); + const normal = calculateNormal(geometry.vertices, a, b, c); + + // skip faces that point up or down + if (normal.y > .999 || normal.y < -.999) { + faces.push(null); + continue; + } + + const indexA = addLine(geometry.vertices, lineLookup, lines, a, b, i); + const indexB = addLine(geometry.vertices, lineLookup, lines, b, c, i); + const indexC = addLine(geometry.vertices, lineLookup, lines, c, a, i); + + const flatNormal = vector2.normalize({ x: normal.z, y: normal.x }); + const lineIndexes = [indexA, indexB, indexC]; + + faces.push({ lineIndexes, flatNormal, objectIndex }); + } + + return { lines, faces }; +} + +function addLine(vertices, lineLookup, lines, a, b, faceIndex) { let index; if (typeof lineLookup[`${b}_${a}`] !== 'undefined') { index = lineLookup[`${b}_${a}`]; } else { + const start = getVertex(vertices, a); + const end = getVertex(vertices, b); + const line = { start, end }; + const faces = []; + index = lines.length; lineLookup[`${a}_${b}`] = index; - - const line = new Line3(geometry.vertices[a], geometry.vertices[b]); - lines.push({ line, faces: [] }); + lines.push({ line, faces }); } - - const { faces } = lines[index]; - faces.push(faceIndex); - + lines[index].faces.push(faceIndex); return index; } -export default function createLines(geometry, settings) { - const lines = []; - const lineLookup = {}; +function calculateNormal(vertices, a, b, c) { + a = getVertex(vertices, a); + b = getVertex(vertices, b); + c = getVertex(vertices, c); - const faces = geometry.faces.map((face, i) => { - const { normal, materialIndex: objectIndex, a, b, c } = geometry.faces[i]; + const cb = vector3.subtract(c, b); + const ab = vector3.subtract(a, b); + const normal = vector3.normalize(vector3.cross(cb, ab)); - // skip faces that point up or down - if (normal.y > .999 || normal.y < -.999) return; - - const indexA = addLine(geometry, lineLookup, lines, a, b, i); - const indexB = addLine(geometry, lineLookup, lines, b, c, i); - const indexC = addLine(geometry, lineLookup, lines, c, a, i); - - const flatNormal = normalize({ x: normal.z, y: normal.x }); - const lineIndexes = [indexA, indexB, indexC]; - return { lineIndexes, flatNormal, objectIndex }; - }); - - return { lines, faces }; + return normal; +} + +function getVertex(vertices, i) { + const i3 = i * 3; + return { + x: vertices[i3], + y: vertices[i3 + 1], + z: vertices[i3 + 2] + }; } diff --git a/src/sliceActions/generateInfills.js b/src/sliceActions/generateInfills.js index 3ddfa56..fd04edc 100644 --- a/src/sliceActions/generateInfills.js +++ b/src/sliceActions/generateInfills.js @@ -5,7 +5,7 @@ import Shape from 'clipper-js'; export default function generateInfills(slices, settings) { let { layerHeight, - innerInfill: { gridSize: infillGridSize }, + innerInfill: { density }, thickness: { top: topThickness, bottom: bottomThickness @@ -13,13 +13,16 @@ export default function generateInfills(slices, settings) { nozzleDiameter } = settings; - infillGridSize /= PRECISION; + density /= 100; nozzleDiameter /= PRECISION; - const bottomSkinCount = Math.ceil(bottomThickness/layerHeight); - const topSkinCount = Math.ceil(topThickness/layerHeight); + const bidirectionalInfill = density < 0.8; + const infillGridSize = nozzleDiameter * (bidirectionalInfill ? 2 : 1) / density; + + const bottomSkinCount = Math.ceil(bottomThickness / layerHeight); + const topSkinCount = Math.ceil(topThickness / layerHeight); const nozzleRadius = nozzleDiameter / 2; - const outerFillTemplateSize = Math.sqrt(2 * Math.pow(nozzleDiameter, 2)); + const outerFillTemplateSize = nozzleDiameter; for (let layer = 0; layer < slices.length; layer ++) { const slice = slices[layer]; @@ -32,6 +35,7 @@ export default function generateInfills(slices, settings) { } for (let i = 0; i < slice.parts.length; i ++) { + const even = (layer % 2 === 0); const part = slice.parts[i]; if (!part.closed) continue; @@ -52,14 +56,13 @@ export default function generateInfills(slices, settings) { if (innerFillArea && innerFillArea.paths.length > 0) { const bounds = innerFillArea.shapeBounds(); - const innerFillTemplate = getFillTemplate(bounds, infillGridSize, true, true); + const innerFillTemplate = getFillTemplate(bounds, infillGridSize, bidirectionalInfill || even, bidirectionalInfill || !even); part.innerFill.join(innerFillTemplate.intersect(innerFillArea)); } if (outerFillArea.paths.length > 0) { const bounds = outerFillArea.shapeBounds(); - const even = (layer % 2 === 0); const outerFillTemplate = getFillTemplate(bounds, outerFillTemplateSize, even, !even); part.outerFill.join(outerFillTemplate.intersect(outerFillArea)); diff --git a/src/sliceActions/generateInnerLines.js b/src/sliceActions/generateInnerLines.js index 04e981f..2d7e751 100644 --- a/src/sliceActions/generateInnerLines.js +++ b/src/sliceActions/generateInnerLines.js @@ -1,6 +1,6 @@ import { PRECISION } from '../constants.js' -const offsetOptions = { +const OFFSET_OPTIONS = { jointType: 'jtSquare', endType: 'etClosedPolygon', miterLimit: 2.0, @@ -29,7 +29,7 @@ export default function generateInnerLines(slices, settings) { if (!part.closed) continue; - const outerLine = part.shape.offset(-nozzleRadius, offsetOptions); + const outerLine = part.shape.offset(-nozzleRadius, OFFSET_OPTIONS); if (outerLine.paths.length === 0) continue; @@ -39,7 +39,7 @@ export default function generateInnerLines(slices, settings) { for (let inset = 1; inset < numShells; inset += 1) { const offset = inset * nozzleDiameter; - const shell = outerLine.offset(-offset, offsetOptions); + const shell = outerLine.offset(-offset, OFFSET_OPTIONS); if (shell.paths.length === 0) { break; diff --git a/src/sliceActions/generateSupport.js b/src/sliceActions/generateSupport.js index 8e9e0c3..f04ffa7 100644 --- a/src/sliceActions/generateSupport.js +++ b/src/sliceActions/generateSupport.js @@ -2,75 +2,40 @@ import getFillTemplate from './getFillTemplate.js'; import Shape from 'clipper-js'; import { PRECISION } from '../constants.js'; +const PRECISION_SQUARED = Math.pow(PRECISION, 2); + export default function generateSupport(slices, settings) { if (!settings.support.enabled) return; let { layerHeight, - support: { - gridSize: supportGridSize, - margin: supportMargin, - plateSize: plateSize, - distanceY: supportDistanceY - }, + support: { density, margin, minArea, distanceY }, nozzleDiameter } = settings; - supportGridSize /= PRECISION; - supportMargin /= PRECISION; - plateSize /= PRECISION; + density /= 100; + margin /= PRECISION; nozzleDiameter /= PRECISION; - var supportDistanceLayers = Math.max(Math.ceil(supportDistanceY / layerHeight), 1); - var supportAreas = new Shape([], true); + const infillGridSize = nozzleDiameter * 2 / density; + const supportDistanceLayers = Math.max(Math.ceil(distanceY / layerHeight), 1); - for (var layer = slices.length - 1 - supportDistanceLayers; layer >= 0; layer --) { - var currentSlice = slices[layer]; + let supportArea = new Shape([], true); - if (supportAreas.length > 0) { + for (let layer = slices.length - 1 - supportDistanceLayers; layer >= 0; layer --) { + const currentLayer = slices[layer + supportDistanceLayers - 1]; + const upSkin = slices[layer + supportDistanceLayers]; + const downSkin = slices[layer - supportDistanceLayers]; - if (layer >= supportDistanceLayers) { - var sliceSkin = slices[layer - supportDistanceLayers].outline; - sliceSkin = sliceSkin; + const neededSupportArea = upSkin.outline.difference(currentLayer.outline.offset(margin)); - var supportAreasSlimmed = supportAreas.difference(sliceSkin.offset(supportMargin)); - if (supportAreasSlimmed.area() < 100.0) { - supportAreas = supportAreas.difference(sliceSkin); - } - else { - supportAreas = supportAreasSlimmed; - } - } + if (neededSupportArea.totalArea() * PRECISION_SQUARED > minArea) supportArea = supportArea.union(neededSupportArea); + if (downSkin) supportArea = supportArea.difference(downSkin.outline.offset(margin)); - var supportTemplate = getFillTemplate(supportAreas.bounds(), supportGridSize, true, true); - var supportFill = supportTemplate.intersect(supportAreas); - if (supportFill.length === 0) { - currentSlice.support = supportAreas.clone(); - } - else { - currentSlice.support = supportFill; - } - } + const bounds = supportArea.shapeBounds(); + const innerFillTemplate = getFillTemplate(bounds, infillGridSize, true, true); - var supportSkin = slices[layer + supportDistanceLayers - 1].outline; - - var slice = slices[layer + supportDistanceLayers]; - for (var i = 0; i < slice.parts.length; i ++) { - var slicePart = slice.parts[i]; - - if (slicePart.intersect.closed) { - var outerLine = slicePart.outerLine; - } - else { - var outerLine = slicePart.intersect.offset(supportMargin); - } - - var overlap = supportSkin.offset(supportMargin).intersect(outerLine); - var overhang = outerLine.difference(overlap); - - if (overlap.length === 0 || overhang.length > 0) { - supportAreas = supportAreas.join(overhang); - } - } + slices[layer].support = supportArea.clone().join(supportArea.intersect(innerFillTemplate)); + slices[layer].supportOutline = supportArea; } } diff --git a/src/sliceActions/getFillTemplate.js b/src/sliceActions/getFillTemplate.js index 98ee8be..6b3db95 100644 --- a/src/sliceActions/getFillTemplate.js +++ b/src/sliceActions/getFillTemplate.js @@ -1,8 +1,10 @@ import Shape from 'clipper-js'; -export default function getFillTemplate(bounds, size, even, uneven) { +export default function getFillTemplate(bounds, gridSize, even, uneven) { const paths = []; + const size = Math.sqrt(2 * Math.pow(gridSize, 2)); + const left = Math.floor(bounds.left / size) * size; const right = Math.ceil(bounds.right / size) * size; const top = Math.floor(bounds.top / size) * size; diff --git a/src/sliceActions/helpers/GCode.js b/src/sliceActions/helpers/GCode.js index 6955cbf..aa7a04f 100644 --- a/src/sliceActions/helpers/GCode.js +++ b/src/sliceActions/helpers/GCode.js @@ -1,5 +1,5 @@ -import { Vector2 } from 'three/src/math/Vector2.js'; -import { PRECISION } from '../../constants.js'; +import { scale, distanceTo } from './vector2.js'; +import { PRECISION, VERSION } from '../../constants.js'; export const MOVE = 'G'; export const M_COMMAND = 'M'; @@ -10,13 +10,15 @@ export const POSITION_X = 'X'; export const POSITION_Y = 'Y'; export const POSITION_Z = 'Z'; -export default class { - constructor(nozzleToFilamentRatio) { - this._nozzleToFilamentRatio = nozzleToFilamentRatio; - - this._gcode = []; +export default class GCode { + constructor(settings) { + this._nozzleToFilamentRatio = 1; + this._gcode = [ + `; ${JSON.stringify(settings).trim()}`, + `; Generated with Doodle3D Slicer V${VERSION}` + ]; this._currentValues = {}; - this._nozzlePosition = new Vector2(0, 0); + this._nozzlePosition = { x: 0, y: 0 }; this._extruder = 0.0; this._duration = 0.0; this._isRetracted = false; @@ -27,10 +29,16 @@ export default class { this._gcode.push(command); } + updateLayerHeight(layerHeight, nozzleDiameter, filamentThickness) { + const filamentSurfaceArea = Math.pow((filamentThickness / 2), 2) * Math.PI; + const lineSurfaceArea = nozzleDiameter * layerHeight; + this._nozzleToFilamentRatio = lineSurfaceArea / filamentSurfaceArea; + } + turnFanOn(fanSpeed) { this._isFanOn = true; - const gcode = { [M_COMMAND]: 106 } + const gcode = { [M_COMMAND]: 106 }; if (typeof fanSpeed !== 'undefined') gcode[FAN_SPEED] = fanSpeed; this._addGCode(gcode); @@ -47,41 +55,41 @@ export default class { } moveTo(x, y, z, { speed }) { - const newNozzlePosition = new Vector2(x, y).multiplyScalar(PRECISION); - const lineLength = this._nozzlePosition.distanceTo(newNozzlePosition); + const newNozzlePosition = scale({ x, y }, PRECISION); + const lineLength = distanceTo(this._nozzlePosition, newNozzlePosition); this._duration += lineLength / speed; this._addGCode({ [MOVE]: 0, - [POSITION_X]: newNozzlePosition.x.toFixed(3), - [POSITION_Y]: newNozzlePosition.y.toFixed(3), - [POSITION_Z]: z.toFixed(3), - [SPEED]: (speed * 60).toFixed(3) + [POSITION_X]: newNozzlePosition.x, + [POSITION_Y]: newNozzlePosition.y, + [POSITION_Z]: z, + [SPEED]: speed * 60 }); - this._nozzlePosition.copy(newNozzlePosition); + this._nozzlePosition = newNozzlePosition; return this; } lineTo(x, y, z, { speed, flowRate }) { - const newNozzlePosition = new Vector2(x, y).multiplyScalar(PRECISION); - const lineLength = this._nozzlePosition.distanceTo(newNozzlePosition); + const newNozzlePosition = scale({ x, y }, PRECISION); + const lineLength = distanceTo(this._nozzlePosition, newNozzlePosition); this._extruder += this._nozzleToFilamentRatio * lineLength * flowRate; this._duration += lineLength / speed; this._addGCode({ [MOVE]: 1, - [POSITION_X]: newNozzlePosition.x.toFixed(3), - [POSITION_Y]: newNozzlePosition.y.toFixed(3), - [POSITION_Z]: z.toFixed(3), - [SPEED]: (speed * 60).toFixed(3), - [EXTRUDER]: this._extruder.toFixed(3) + [POSITION_X]: newNozzlePosition.x, + [POSITION_Y]: newNozzlePosition.y, + [POSITION_Z]: z, + [SPEED]: speed * 60, + [EXTRUDER]: this._extruder }); - this._nozzlePosition.copy(newNozzlePosition); + this._nozzlePosition = newNozzlePosition; return this; } @@ -95,8 +103,8 @@ export default class { this._addGCode({ [MOVE]: 0, - [EXTRUDER]: this._extruder.toFixed(3), - [SPEED]: (speed * 60).toFixed(3) + [EXTRUDER]: this._extruder, + [SPEED]: speed * 60 }); } } @@ -113,8 +121,8 @@ export default class { this._addGCode({ [MOVE]: 0, - [EXTRUDER]: (this._extruder - amount).toFixed(3), - [SPEED]: (speed * 60).toFixed(3) + [EXTRUDER]: this._extruder - amount, + [SPEED]: speed * 60 }); } } @@ -122,6 +130,15 @@ export default class { return this; } + addGCode(gcode, { temperature, bedTemperature, heatedBed }) { + gcode = gcode + .replace(/{temperature}/gi, temperature) + .replace(/{bedTemperature}/gi, bedTemperature) + .replace(/{if heatedBed}/gi, heatedBed ? '' : ';'); + + this._addGCode(gcode); + } + getGCode() { return { gcode: this._gcode, diff --git a/src/sliceActions/helpers/Slice.js b/src/sliceActions/helpers/Slice.js index 10b22fe..2f5c085 100644 --- a/src/sliceActions/helpers/Slice.js +++ b/src/sliceActions/helpers/Slice.js @@ -1,6 +1,6 @@ import Shape from 'clipper-js'; -export default class { +export default class Slice { constructor() { this.parts = []; } diff --git a/src/sliceActions/helpers/color.js b/src/sliceActions/helpers/color.js new file mode 100644 index 0000000..c6f6f33 --- /dev/null +++ b/src/sliceActions/helpers/color.js @@ -0,0 +1,24 @@ +export function hslToRgb(h, s, l){ + let r, g, b; + + if (s === 0) { + r = g = b = lightness; + } else { + const q = l < 0.5 ? l * (1 + s) : l + s - l * s; + const p = 2 * l - q; + r = hueToRgb(p, q, h + 1 / 3); + g = hueToRgb(p, q, h); + b = hueToRgb(p, q, h - 1 / 3); + } + + return [r, g, b]; +} + +function hueToRgb(p, q, t){ + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1 / 6) return p + (q - p) * 6 * t; + if (t < 1 / 2) return q; + if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; + return p; +} diff --git a/src/sliceActions/helpers/comb.js b/src/sliceActions/helpers/comb.js index 67a0ea5..671e8fa 100644 --- a/src/sliceActions/helpers/comb.js +++ b/src/sliceActions/helpers/comb.js @@ -1,8 +1,8 @@ import Shape from 'clipper-js'; -import { subtract, add, scale, normalize, dot, length, distanceTo } from './VectorUtils.js'; +import { subtract, add, scale, normalize, dot, length, distanceTo } from './vector2.js'; import { PRECISION } from '../../constants.js'; -const TOLERANCE = 5 / PRECISION; +const TOLERANCE = 1 / PRECISION; export default function comb(outline, start, end) { if (distanceTo(start, end) < TOLERANCE) { @@ -45,9 +45,9 @@ export default function comb(outline, start, end) { if (snappedCombPaths.length === 0) { snappedCombPaths.push([start], [end]); - } else if (distanceTo(firstPath[0], start) > 1.0) { + } else if (distanceTo(firstPath[0], start) > 1.) { snappedCombPaths.unshift([start]); - } else if (distanceTo(lastPath[lastPath.length - 1], end) > 1.0) { + } else if (distanceTo(lastPath[lastPath.length - 1], end) > 1.) { snappedCombPaths.push([end]); } diff --git a/src/sliceActions/helpers/VectorUtils.js b/src/sliceActions/helpers/vector2.js similarity index 54% rename from src/sliceActions/helpers/VectorUtils.js rename to src/sliceActions/helpers/vector2.js index 83d33f0..bf10575 100644 --- a/src/sliceActions/helpers/VectorUtils.js +++ b/src/sliceActions/helpers/vector2.js @@ -6,18 +6,20 @@ export const add = (a, b) => ({ x: a.x + b.x, y: a.y + b.y }); -export const scale = (a, factor) => ({ - x: a.x * factor, - y: a.y * factor +export const scale = (v, factor) => ({ + x: v.x * factor, + y: v.y * factor }); -export const devide = (a, factor) => ({ - x: a.x / factor, - y: a.y / factor +export const divide = (v, factor) => ({ + x: v.x / factor, + y: v.y / factor }); -export const normal = (a) => ({ - x: -a.y, - y: a.x +export const normal = (v) => ({ + x: -v.y, + y: v.x }); +export const equals = (a, b) => a.x === b.x && a.y === b.y; +export const almostEquals = (a, b) => Math.abs(a.x - b.x) < 0.001 && Math.abs(a.y - b.y) < 0.001; export const dot = (a, b) => a.x * b.x + a.y * b.y; export const length = (v) => Math.sqrt(v.x * v.x + v.y * v.y); export const distanceTo = (a, b) => length(subtract(a, b)); @@ -28,5 +30,4 @@ export const normalize = (v) => { x: v.x / l, y: v.y / l }; -} -export const clone = (v) => ({ x: v.x, y: v.y }); +}; diff --git a/src/sliceActions/helpers/vector3.js b/src/sliceActions/helpers/vector3.js new file mode 100644 index 0000000..7d5493e --- /dev/null +++ b/src/sliceActions/helpers/vector3.js @@ -0,0 +1,38 @@ +export const subtract = (a, b) => ({ + x: a.x - b.x, + y: a.y - b.y, + z: a.z - b.z +}); +export const add = (a, b) => ({ + x: a.x + b.x, + y: a.y + b.y, + z: a.z + b.z +}); +export const scale = (v, factor) => ({ + x: v.x * factor, + y: v.y * factor, + z: v.z * factor +}); +export const divide = (v, factor) => ({ + x: v.x / factor, + y: v.y / factor, + z: v.z / factor +}); +export const cross = (a, b) => ({ + x: a.y * b.z - a.z * b.y, + y: a.z * b.x - a.x * b.z, + z: a.x * b.y - a.y * b.x +}); +export const equals = (a, b) => a.x === b.x && a.y === b.y && a.z === b.z; +export const almostEquals = (a, b) => Math.abs(a.x - b.x) < 0.001 && Math.abs(a.y - b.y) < 0.001 && Math.abs(a.z - b.z) < 0.001; +export const length = (v) => Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z); +export const distanceTo = (a, b) => length(subtract(a, b)); +export const normalize = (v) => { + const l = length(v); + + return { + x: v.x / l, + y: v.y / l, + z: v.z / l + }; +}; diff --git a/src/sliceActions/intersectionsToShapes.js b/src/sliceActions/intersectionsToShapes.js index 0993d1e..25ba3e2 100644 --- a/src/sliceActions/intersectionsToShapes.js +++ b/src/sliceActions/intersectionsToShapes.js @@ -1,136 +1,157 @@ -import { subtract, normal, normalize, dot, distanceTo, clone } from './helpers/VectorUtils.js'; +import { subtract, normal, normalize, dot, almostEquals } from './helpers/vector2.js'; -export default function intersectionsToShapes(intersectionLayers, faces, openObjectIndexes, settings) { +export default function intersectionsToShapes(layerPoints, layerFaceIndexes, faces, openObjectIndexes, settings) { const layers = []; - for (let layer = 0; layer < intersectionLayers.length; layer ++) { + for (let layer = 0; layer < layerPoints.length; layer ++) { const fillShapes = []; const lineShapesOpen = []; const lineShapesClosed = []; - const { points, faceIndexes } = intersectionLayers[layer]; + const points = layerPoints[layer]; + const faceIndexes = layerFaceIndexes[layer]; if (faceIndexes.length === 0) continue; const shapes = {}; + const startConnects = {}; + const endConnects = {}; + for (let i = 0; i < faceIndexes.length; i ++) { - const { lineIndexes, objectIndex, flatNormal } = faces[faceIndexes[i]]; + const faceIndex = faceIndexes[i]; + const { lineIndexes, flatNormal, objectIndex } = faces[faceIndex]; - const a = points[lineIndexes[0]]; - const b = points[lineIndexes[1]]; - const c = points[lineIndexes[2]]; + const a = lineIndexes[0]; + const b = lineIndexes[1]; + const c = lineIndexes[2]; - const lineSegment = []; - if (a && b) { - lineSegment.push(a, b); - } else if (b && c) { - lineSegment.push(b, c); - } else if (c && a) { - lineSegment.push(c, a); + let pointA; + let pointB; + if (points[a] && points[b]) { + pointA = a; + pointB = b; + } else if (points[b] && points[c]) { + pointA = b; + pointB = c; + } else if (points[c] && points[a]) { + pointA = c; + pointB = a; } else { + // should never happen continue; } - const segmentNormal = normalize(normal(subtract(lineSegment[1], lineSegment[0]))); - if (dot(segmentNormal, flatNormal) < 0) lineSegment.reverse(); + const segmentNormal = normalize(normal(subtract(points[pointA], points[pointB]))); + if (dot(segmentNormal, flatNormal) < 0) { + const temp = pointB; + pointB = pointA; + pointA = temp; + } - if (!shapes[objectIndex]) shapes[objectIndex] = { lineSegments: [] }; - const shape = shapes[objectIndex]; + if (endConnects[pointA]) { + const lineSegment = endConnects[pointA]; + delete endConnects[pointA]; + if (startConnects[pointB]) { + if (startConnects[pointB] === lineSegment) { + delete startConnects[pointB]; + lineSegment.push(pointB); + } else { + lineSegment.push(...startConnects[pointB]); + endConnects[lineSegment[lineSegment.length - 1]] = lineSegment; + } + } else { + lineSegment.push(pointB); + endConnects[pointB] = lineSegment; + } + } else if (startConnects[pointB]) { + const lineSegment = startConnects[pointB]; + delete startConnects[pointB]; + if (endConnects[pointA]) { + lineSegment.unshift(...endConnects[pointA]); + startConnects[lineSegment[0]] = lineSegment; + } else { + lineSegment.unshift(pointA); + startConnects[pointA] = lineSegment; + } + } else { + const lineSegment = [pointA, pointB]; + startConnects[pointA] = lineSegment; + endConnects[pointB] = lineSegment; - shape.lineSegments.push(lineSegment) + if (!shapes[objectIndex]) shapes[objectIndex] = []; + shapes[objectIndex].push(lineSegment); + } } for (const objectIndex in shapes) { - const shape = shapes[objectIndex]; + const shape = shapes[objectIndex] + .map(lineSegment => lineSegment.map(pointIndex => points[pointIndex])) + .filter(lineSegment => lineSegment.some(i => !almostEquals(lineSegment[0], lineSegment[1]))); const openShape = openObjectIndexes[objectIndex]; - const lines = [shape.lineSegments.pop()]; + const connectPoints = []; + for (let pathIndex = 0; pathIndex < shape.length; pathIndex ++) { + const path = shape[pathIndex]; - loop: while (shape.lineSegments.length !== 0) { - for (let i = 0; i < lines.length; i ++) { - const line = lines[i]; - - const lastPoint = line[line.length - 1]; - - let closestSegmentEnd; - let endHit = false; - const distanceEnd = new WeakMap(); - for (let i = 0; i < shape.lineSegments.length; i ++) { - const lineSegment = shape.lineSegments[i]; - if (lastPoint === lineSegment[0]) { - closestSegmentEnd = lineSegment; - endHit = true; - break; - } - const distance = distanceTo(lastPoint, lineSegment[0]); - distanceEnd.set(lineSegment, distance); - } - - if (!endHit) { - closestSegmentEnd = shape.lineSegments.sort((a, b) => { - const distanceA = distanceEnd.get(a); - const distanceB = distanceEnd.get(b); - if (distanceA === distanceB) return distanceTo(a[0], a[1]) - distanceTo(b[0], b[1]); - return distanceA - distanceB; - })[0]; - - if (distanceTo(closestSegmentEnd[0], lastPoint) < .001) endHit = true; - } - - if (endHit) { - shape.lineSegments.splice(shape.lineSegments.indexOf(closestSegmentEnd), 1); - line.splice(line.length, 0, closestSegmentEnd[1]); - continue loop; - } - - const firstPoint = line[0]; - - let closestSegmentStart; - let hitStart = false; - const distanceStart = new WeakMap(); - for (let i = 0; i < shape.lineSegments.length; i ++) { - const lineSegment = shape.lineSegments[i]; - if (firstPoint === lineSegment[1]) { - closestSegmentStart = lineSegment; - hitStart = true; - break; - } - const distance = distanceTo(firstPoint, lineSegment[1]); - distanceStart.set(lineSegment, distance); - } - - if (!hitStart) { - closestSegmentStart = shape.lineSegments.sort((a, b) => { - const distanceA = distanceStart.get(a); - const distanceB = distanceStart.get(b); - if (distanceA === distanceB) return distanceTo(a[0], a[1]) - distanceTo(b[0], b[1]); - return distanceA - distanceB; - })[0]; - - if (distanceTo(closestSegmentStart[1], firstPoint) < .001) hitStart = true; - } - - if (hitStart) { - shape.lineSegments.splice(shape.lineSegments.indexOf(closestSegmentStart), 1); - line.splice(0, 0, closestSegmentStart[0]); - continue loop; + if (almostEquals(path[0], path[path.length - 1])) { + if (openShape) { + lineShapesClosed.push(path); + } else { + fillShapes.push(path); } + continue; + } + + let shapeStartPoint = path[0]; + const connectNext = connectPoints.find(({ point }) => almostEquals(point, shapeStartPoint)); + if (connectNext) { + connectNext.next = pathIndex; + } else { + connectPoints.push({ point: shapeStartPoint, next: pathIndex, previous: -1 }); + } + + let shapeEndPoint = path[path.length - 1]; + const connectPrevious = connectPoints.find(({ point }) => almostEquals(point, shapeEndPoint)); + if (connectPrevious) { + connectPrevious.previous = pathIndex; + } else { + connectPoints.push({ point: shapeEndPoint, next: -1, previous: pathIndex }); } - lines.push(shape.lineSegments.pop()); } - if (openShape) { - for (const line of lines) { - const closed = distanceTo(line[0], line[line.length - 1]) < .001; - if (closed) { + connectPoints.sort(({ previous }) => -previous); + + while (connectPoints.length !== 0) { + let { next, previous } = connectPoints.pop(); + + const line = []; + if (previous !== -1) line.push(...shape[previous]); + + while (true) { + const pointIndex = connectPoints.findIndex(point => point.previous === next); + if (pointIndex === -1) break; + + const point = connectPoints[pointIndex]; + line.push(...shape[point.previous]); + + connectPoints.splice(pointIndex, 1); + + if (point.next === -1) break; + if (point.next === previous) break; + + next = point.next; + } + + if (openShape) { + if (almostEquals(line[0], line[line.length - 1])) { lineShapesClosed.push(line); } else { lineShapesOpen.push(line); } + } else { + fillShapes.push(line); } - } else { - fillShapes.push(...lines); } } diff --git a/src/sliceActions/optimizePaths.js b/src/sliceActions/optimizePaths.js index 661e7e0..bdafffe 100644 --- a/src/sliceActions/optimizePaths.js +++ b/src/sliceActions/optimizePaths.js @@ -1,15 +1,15 @@ -import { Vector2 } from 'three/src/math/Vector2.js'; +import { length, distanceTo } from './helpers/vector2.js'; import Shape from 'clipper-js'; export default function optimizePaths(slices, settings) { - const start = new Vector2(0, 0); + let start = { x: 0, y: 0 }; for (let layer = 0; layer < slices.length; layer ++) { const slice = slices[layer]; if (typeof slice.brim !== 'undefined' && slice.brim.paths.length > 0) { slice.brim = optimizeShape(slice.brim, start); - start.copy(slice.brim.lastPoint(true)); + start = slice.brim.lastPoint(true); } const parts = []; @@ -54,36 +54,34 @@ export default function optimizePaths(slices, settings) { if (shell.paths.length === 0) continue; part.shell[i] = optimizeShape(shell, start); - start.copy(part.shell[i].lastPoint(true)); + start = part.shell[i].lastPoint(true); } if (part.outerFill.paths.length > 0) { part.outerFill = optimizeShape(part.outerFill, start); - start.copy(part.outerFill.lastPoint(true)); + start = part.outerFill.lastPoint(true); } if (part.innerFill.paths.length > 0) { part.innerFill = optimizeShape(part.innerFill, start); - start.copy(part.innerFill.lastPoint(true)); + start = part.innerFill.lastPoint(true); } } else { part.shape = optimizeShape(part.shape, start); - start.copy(part.shape.lastPoint(true)); + start = part.shape.lastPoint(true); } } slice.parts = parts; - if (typeof slice.support !== 'undefined' && slice.support.length > 0) { + if (typeof slice.support !== 'undefined' && slice.support.paths.length > 0) { slice.support = optimizeShape(slice.support, start); - start.copy(slice.support.lastPoint(true)); + start = slice.support.lastPoint(true); } } } function optimizeShape(shape, start) { - start = start.clone(); - const inputPaths = shape.mapToLower(); const optimizedPaths = []; const donePaths = []; @@ -102,8 +100,7 @@ function optimizeShape(shape, start) { if (shape.closed) { for (let j = 0; j < path.length; j += 1) { - const point = new Vector2().copy(path[j]); - const length = point.sub(start).length(); + const length = distanceTo(path[j], start); if (minLength === false || length < minLength) { minPath = path; minLength = length; @@ -112,8 +109,7 @@ function optimizeShape(shape, start) { } } } else { - const startPoint = new Vector2().copy(path[0]); - const lengthToStart = startPoint.sub(start).length(); + const lengthToStart = distanceTo(path[0], start); if (minLength === false || lengthToStart < minLength) { minPath = path; minLength = lengthToStart; @@ -121,8 +117,7 @@ function optimizeShape(shape, start) { pathIndex = i; } - const endPoint = new Vector2().copy(path[path.length - 1]); - const lengthToEnd = endPoint.sub(start).length(); + const lengthToEnd = distanceTo(path[path.length - 1], start); if (lengthToEnd < minLength) { minPath = path; minLength = lengthToEnd; @@ -132,20 +127,15 @@ function optimizeShape(shape, start) { } } - let point; if (shape.closed) { minPath = minPath.concat(minPath.splice(0, offset)); - point = minPath[0]; + start = minPath[0]; } else { - if (reverse) { - minPath.reverse(); - } - point = minPath[minPath.length - 1]; + if (reverse) minPath.reverse(); + start = minPath[minPath.length - 1]; } donePaths.push(pathIndex); - start.copy(point); - optimizedPaths.push(minPath); } diff --git a/src/sliceActions/shapesToSlices.js b/src/sliceActions/shapesToSlices.js index a6ace31..9e439cc 100644 --- a/src/sliceActions/shapesToSlices.js +++ b/src/sliceActions/shapesToSlices.js @@ -1,7 +1,7 @@ import Shape from 'clipper-js'; import Slice from './helpers/Slice.js'; -import { PRECISION } from '../constants.js'; +import { PRECISION, MIN_AREA } from '../constants.js'; export default function shapesToSlices(shapes, settings) { const sliceLayers = []; @@ -13,6 +13,7 @@ export default function shapesToSlices(shapes, settings) { .fixOrientation() .simplify('pftNonZero') .clean(1) + .thresholdArea(MIN_AREA / Math.pow(PRECISION, 2)) .seperateShapes(); lineShapesClosed = new Shape(lineShapesClosed, true, true, true, true) @@ -27,23 +28,16 @@ export default function shapesToSlices(shapes, settings) { for (let i = 0; i < fillShapes.length; i ++) { const fillShape = fillShapes[i]; + if (fillShape.paths.length === 0) continue; + slice.add(fillShape, true); - // if (lineShapesClosed.paths.length > 0) { - // lineShapesClosed = lineShapesClosed.difference(closedShape); - // } - // if (lineShapesOpen.paths.length > 0) { - // lineShapesOpen = lineShapesOpen.difference(closedShape); - // } + if (lineShapesClosed.paths.length > 0) lineShapesClosed = lineShapesClosed.difference(fillShape); + if (lineShapesOpen.paths.length > 0) lineShapesOpen = lineShapesOpen.difference(fillShape); } - if (lineShapesClosed.paths.length > 0) { - slice.add(lineShapesClosed, false); - } - - if (lineShapesOpen.paths.length > 0) { - slice.add(lineShapesOpen, false); - } + if (lineShapesClosed.paths.length > 0) slice.add(lineShapesClosed, false); + if (lineShapesOpen.paths.length > 0) slice.add(lineShapesOpen, false); sliceLayers.push(slice); } diff --git a/src/sliceActions/slice.js b/src/sliceActions/slice.js index 57b8232..e56b678 100644 --- a/src/sliceActions/slice.js +++ b/src/sliceActions/slice.js @@ -1,9 +1,3 @@ -import { Color } from 'three/src/math/Color.js'; -import { BufferGeometry } from 'three/src/core/BufferGeometry.js'; -import { BufferAttribute } from 'three/src/core/BufferAttribute.js'; -import { LineBasicMaterial } from 'three/src/materials/LineBasicMaterial.js'; -import { VertexColors } from 'three/src/constants.js'; -import { LineSegments } from 'three/src/objects/LineSegments.js'; import calculateLayersIntersections from './calculateLayersIntersections.js'; import createLines from './createLines.js'; import generateInfills from './generateInfills.js'; @@ -16,32 +10,25 @@ import optimizePaths from './optimizePaths.js'; import shapesToSlices from './shapesToSlices.js'; import slicesToGCode from './slicesToGCode.js'; import applyPrecision from './applyPrecision.js'; +import { hslToRgb } from './helpers/color.js'; // // import removePrecision from './removePrecision.js'; export default function(settings, geometry, openObjectIndexes, constructLinePreview, onProgress) { - const totalStages = 11; - let current = -1; - const updateProgress = (action) => { - current ++; - if (typeof onProgress !== 'undefined') { - onProgress({ - progress: { - done: current, - total: totalStages, - action - } - }); - } + const total = 11; + let done = -1; + const updateProgress = action => { + done ++; + if (onProgress) onProgress({ progress: { done, total, action } }); }; updateProgress('Constructing unique lines from geometry'); const { lines, faces } = createLines(geometry, settings); updateProgress('Calculating layer intersections'); - const layers = calculateLayersIntersections(lines, settings); + const { layerPoints, layerFaceIndexes } = calculateLayersIntersections(lines, settings); updateProgress('Constructing shapes from intersections'); - const shapes = intersectionsToShapes(layers, faces, openObjectIndexes, settings); + const shapes = intersectionsToShapes(layerPoints, layerFaceIndexes, faces, openObjectIndexes, settings); applyPrecision(shapes); @@ -69,23 +56,34 @@ export default function(settings, geometry, openObjectIndexes, constructLinePrev updateProgress('Finished'); if (constructLinePreview) gcode.linePreview = createGcodeGeometry(gcode.gcode); - gcode.gcode = gcodeToString(gcode.gcode); + + gcode.gcode = new Blob([gcodeToString(gcode.gcode)], { type: 'text/plain' }); + return gcode; } +const PRECISION = 1000; +function toFixedTrimmed(value) { + return (Math.round(value * PRECISION) / PRECISION).toString(); +} + function gcodeToString(gcode) { const currentValues = {}; return gcode.reduce((string, command) => { - let first = true; - for (const action in command) { - const value = command[action]; - const currentValue = currentValues[action]; - if (first) { - string += `${action}${value}`; - first = false; - } else if (currentValue !== value) { - string += ` ${action}${value}`; - currentValues[action] = value; + if (typeof command === 'string') { + string += command; + } else { + let first = true; + for (const action in command) { + const value = toFixedTrimmed(command[action]); + const currentValue = currentValues[action]; + if (first) { + string += `${action}${value}`; + first = false; + } else if (currentValue !== value) { + string += ` ${action}${value}`; + currentValues[action] = value; + } } } string += '\n'; @@ -94,35 +92,31 @@ function gcodeToString(gcode) { } const MAX_SPEED = 100 * 60; -const COLOR = new Color(); function createGcodeGeometry(gcode) { const positions = []; const colors = []; let lastPoint = [0, 0, 0]; for (let i = 0; i < gcode.length; i ++) { - const { G, F, X, Y, Z } = gcode[i]; + const command = gcode[i]; + if (typeof command === 'string') continue; + + const { G, F, X, Y, Z } = command; if (X || Y || Z) { if (G === 1) { positions.push(lastPoint.Y, lastPoint.Z, lastPoint.X); positions.push(Y, Z, X); - const color = (G === 0) ? COLOR.setHex(0x00ff00) : COLOR.setHSL(F / MAX_SPEED, 0.5, 0.5); - colors.push(color.r, color.g, color.b); - colors.push(color.r, color.g, color.b); + const color = (G === 0) ? [0, 1, 0] : hslToRgb(F / MAX_SPEED, 0.5, 0.5); + colors.push(...color, ...color); } lastPoint = { X, Y, Z }; } } - const geometry = new BufferGeometry(); - - geometry.addAttribute('position', new BufferAttribute(new Float32Array(positions), 3)); - geometry.addAttribute('color', new BufferAttribute(new Float32Array(colors), 3)); - - const material = new LineBasicMaterial({ vertexColors: VertexColors }); - const linePreview = new LineSegments(geometry, material); - - return linePreview; + return { + positions: new Float32Array(positions), + colors: new Float32Array(colors) + }; } diff --git a/src/sliceActions/slicesToGCode.js b/src/sliceActions/slicesToGCode.js index 790385d..7a06918 100644 --- a/src/sliceActions/slicesToGCode.js +++ b/src/sliceActions/slicesToGCode.js @@ -1,6 +1,7 @@ import GCode from './helpers/GCode.js'; import comb from './helpers/comb.js'; -import { PRECISION } from '../constants.js'; +import { divide } from './helpers/vector2.js'; +import { PRECISION, Z_OFFSET } from '../constants.js'; const PROFILE_TYPES = ['support', 'innerShell', 'outerShell', 'innerInfill', 'outerInfill', 'brim']; @@ -12,15 +13,13 @@ export default function slicesToGCode(slices, settings) { travelSpeed, retraction, travel, - combing, - zOffset + combing } = settings; - const filamentSurfaceArea = Math.pow((filamentThickness / 2), 2) * Math.PI; - const lineSurfaceArea = nozzleDiameter * layerHeight; - const nozzleToFilamentRatio = lineSurfaceArea / filamentSurfaceArea; + const gcode = new GCode(settings); + gcode.updateLayerHeight(Z_OFFSET, nozzleDiameter, filamentThickness) - const gcode = new GCode(nozzleToFilamentRatio); + if (settings.startCode) gcode.addGCode(settings.startCode, settings); const defaultProfile = { travelProfile: travel, @@ -30,9 +29,10 @@ export default function slicesToGCode(slices, settings) { let isFirstLayer = true; for (let layer = 0; layer < slices.length; layer ++) { const slice = slices[layer]; - const z = layer * layerHeight + zOffset; + const z = layer * layerHeight + Z_OFFSET; if (layer === 1) { + gcode.updateLayerHeight(layerHeight, nozzleDiameter, filamentThickness); gcode.turnFanOn(); isFirstLayer = false; } @@ -61,11 +61,11 @@ export default function slicesToGCode(slices, settings) { const unRetract = isOuterShell; const profile = isOuterShell ? profiles.outerShell : profiles.innerShell; - pathToGCode(outline, combing && true, gcode, shell, false, unRetract, z, profile); + pathToGCode(outline, combing, gcode, shell, false, unRetract, z, profile); } - pathToGCode(outline, combing && true, gcode, part.outerFill, false, false, z, profiles.outerInfill); - pathToGCode(outline, combing && true, gcode, part.innerFill, true, false, z, profiles.innerInfill); + pathToGCode(outline, combing, gcode, part.outerFill, false, false, z, profiles.outerInfill); + pathToGCode(outline, combing, gcode, part.innerFill, true, false, z, profiles.innerInfill); } else { const retract = !(slice.parts.length === 1 && typeof slice.support === 'undefined'); pathToGCode(null, false, gcode, part.shape, retract, retract, z, profiles.outerShell); @@ -73,10 +73,12 @@ export default function slicesToGCode(slices, settings) { } if (typeof slice.support !== 'undefined') { - pathToGCode(null, false, gcode, slice.support, true, true, z, profiles.support); + pathToGCode(slice.supportOutline, combing, gcode, slice.support, true, true, z, profiles.support); } } + if (settings.endCode) gcode.addGCode(settings.endCode, settings); + return gcode.getGCode(); } @@ -93,7 +95,7 @@ function pathToGCode(outline, combing, gcode, shape, retract, unRetract, z, { li if (i === 0) { if (combing) { - const combPath = comb(outline, gcode._nozzlePosition.divideScalar(PRECISION), point); + const combPath = comb(outline, divide(gcode._nozzlePosition, PRECISION), point); for (let i = 0; i < combPath.length; i ++) { const combPoint = combPath[i]; gcode.moveTo(combPoint.x, combPoint.y, z, travelProfile); diff --git a/src/slicer.js b/src/slicer.js index ead168b..0f77d18 100644 --- a/src/slicer.js +++ b/src/slicer.js @@ -1,11 +1,6 @@ -import { VertexColors } from 'three/src/constants.js'; -import { BufferAttribute } from 'three/src/core/BufferAttribute.js'; -import { LineBasicMaterial } from 'three/src/materials/LineBasicMaterial.js'; -import { LineSegments } from 'three/src/objects/LineSegments.js'; +import * as THREE from 'three'; import slice from './sliceActions/slice.js'; import SlicerWorker from './slicer.worker.js'; -import { FrontSide, DoubleSide } from 'three/src/constants.js'; -import { BufferGeometry } from 'three/src/core/BufferGeometry.js' export function sliceMesh(settings, mesh, sync = false, constructLinePreview = false, onProgress) { if (!mesh || !mesh.isMesh) { @@ -21,26 +16,43 @@ export function sliceGeometry(settings, geometry, materials, matrix, sync = fals if (!geometry) { throw new Error('Missing required geometry argument'); } else if (geometry.isBufferGeometry) { - geometry = new Geometry().fromBufferGeometry(geometry); + geometry = new THREE.Geometry().fromBufferGeometry(geometry); } else if (geometry.isGeometry) { geometry = geometry.clone(); } else { throw new Error('Geometry is not an instance of BufferGeometry or Geometry'); } - if (geometry.faces.length === 0) { - throw new Error('Geometry does not contain any data'); - } + if (matrix && matrix.isMatrix4) geometry.applyMatrix(matrix); - if (matrix && matrix.isMatrix4) { - geometry.applyMatrix(matrix); - } + const vertices = geometry.vertices.reduce((array, { x, y, z }, i) => { + const i3 = i * 3; + array[i3] = x; + array[i3 + 1] = y; + array[i3 + 2] = z; + return array; + }, new Float32Array(geometry.vertices.length * 3)); + const faces = geometry.faces.reduce((array, { a, b, c }, i) => { + const i3 = i * 3; + array[i3] = a; + array[i3 + 1] = b; + array[i3 + 2] = c; + return array; + }, new Uint32Array(geometry.faces.length * 3)); + const objectIndexes = geometry.faces.reduce((array, { materialIndex }, i) => { + array[i] = materialIndex; + return array; + }, new Uint8Array(geometry.faces.length)); + + if (faces.length === 0) throw new Error('Geometry does not contain any data'); + + geometry = { vertices, faces, objectIndexes }; const openObjectIndexes = materials instanceof Array ? materials.map(({ side }) => { switch (side) { - case FrontSide: + case THREE.FrontSide: return false; - case DoubleSide: + case THREE.DoubleSide: return true; default: return false; @@ -55,7 +67,9 @@ export function sliceGeometry(settings, geometry, materials, matrix, sync = fals } function sliceSync(settings, geometry, openObjectIndexes, constructLinePreview, onProgress) { - return slice(settings, geometry, openObjectIndexes, constructLinePreview, onProgress); + const gcode = slice(settings, geometry, openObjectIndexes, constructLinePreview, onProgress); + if (gcode.linePreview) gcode.linePreview = constructLineGeometry(gcode.linePreview); + return gcode; } function sliceAsync(settings, geometry, openObjectIndexes, constructLinePreview, onProgress) { @@ -63,10 +77,10 @@ function sliceAsync(settings, geometry, openObjectIndexes, constructLinePreview, // create the slicer worker const slicerWorker = new SlicerWorker(); - slicerWorker.onerror = error => { + slicerWorker.addEventListener('error', event => { slicerWorker.terminate(); - reject(error); - }; + reject(event); + }); // listen to messages send from worker slicerWorker.addEventListener('message', (event) => { @@ -75,36 +89,36 @@ function sliceAsync(settings, geometry, openObjectIndexes, constructLinePreview, case 'SLICE': { slicerWorker.terminate(); - if (data.gcode.linePreview) { - const geometry = new BufferGeometry(); + const { gcode } = data; + if (gcode.linePreview) gcode.linePreview = constructLineGeometry(gcode.linePreview); - const { position, color } = data.gcode.linePreview; - geometry.addAttribute('position', new BufferAttribute(new Float32Array(position), 3)); - geometry.addAttribute('color', new BufferAttribute(new Float32Array(color), 3)); - - const material = new LineBasicMaterial({ vertexColors: VertexColors }); - const linePreview = new LineSegments(geometry, material); - - data.gcode.linePreview = linePreview; - } - - resolve(data.gcode); + resolve(gcode); break; } case 'PROGRESS': { - if (typeof onProgress !== 'undefined') { - onProgress(data); - } + if (typeof onProgress !== 'undefined') onProgress(data); break; } } }); - // send geometry and settings to worker to start the slicing progress - geometry = geometry.toJSON(); + const { vertices, faces, objectIndexes } = geometry; + const buffers = [vertices.buffer, faces.buffer, objectIndexes.buffer]; + slicerWorker.postMessage({ message: 'SLICE', data: { settings, geometry, openObjectIndexes, constructLinePreview } - }); + }, buffers); }); } + +function constructLineGeometry(linePreview) { + const geometry = new THREE.BufferGeometry(); + + geometry.addAttribute('position', new THREE.BufferAttribute(new Float32Array(linePreview.positions), 3)); + geometry.addAttribute('color', new THREE.BufferAttribute(new Float32Array(linePreview.colors), 3)); + + const material = new THREE.LineBasicMaterial({ vertexColors: THREE.VertexColors }); + const mesh = new THREE.LineSegments(geometry, material); + return mesh; +} diff --git a/src/slicer.worker.js b/src/slicer.worker.js index 0168b7b..a2fdcbc 100644 --- a/src/slicer.worker.js +++ b/src/slicer.worker.js @@ -1,7 +1,5 @@ import 'core-js'; // polyfills import slice from './sliceActions/slice.js'; -import { Matrix4 } from 'three/src/math/Matrix4.js'; -import { JSONLoader } from 'three/src/loaders/JSONLoader.js'; const onProgress = progress => { self.postMessage({ @@ -10,23 +8,18 @@ const onProgress = progress => { }); } -const loader = new JSONLoader(); - -self.addEventListener('message', async (event) => { +self.addEventListener('message', (event) => { const { message, data } = event.data; switch (message) { case 'SLICE': { - const { settings, geometry: JSONGeometry, constructLinePreview, openObjectIndexes } = data; - const { geometry } = loader.parse(JSONGeometry.data); + const { settings, geometry, constructLinePreview, openObjectIndexes } = data; const gcode = slice(settings, geometry, openObjectIndexes, constructLinePreview, onProgress); const buffers = []; if (gcode.linePreview) { - const position = gcode.linePreview.geometry.getAttribute('position').array; - const color = gcode.linePreview.geometry.getAttribute('color').array; - buffers.push(position.buffer, color.buffer); - gcode.linePreview = { position, color }; + buffers.push(gcode.linePreview.positions.buffer); + buffers.push(gcode.linePreview.colors.buffer); } self.postMessage({ diff --git a/webpack.config.js b/webpack.config.js index 8e59163..157a8d2 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,8 +1,9 @@ const path = require('path'); -// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; +const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; const HTMLWebpackPlugin = require('html-webpack-plugin'); -const devMode = true; +const devMode = process.env.NODE_ENV !== 'production'; +const analyzeBundle = process.env.ANALYZE_BUNDLE; const babelLoader = { loader: 'babel-loader', @@ -34,6 +35,7 @@ module.exports = { 'clipper-lib': '@doodle3d/clipper-lib', 'clipper-js': '@doodle3d/clipper-js', 'doodle3d-core': `@doodle3d/doodle3d-core/${devMode ? 'module' : 'lib'}`, + 'doodle3d-api': `@doodle3d/doodle3d-api/${devMode ? 'module' : 'lib'}`, 'cal': '@doodle3d/cal' } }, @@ -51,7 +53,13 @@ module.exports = { use: 'yml-loader' }, { test: /\.worker\.js$/, - use: ['worker-loader', babelLoader] + use: [{ + loader: 'worker-loader', + options: { + inline: false, + name: '[name].js' + } + }, babelLoader], }, { test: /\.(png|jpg|gif)$/, use: ['url-loader?name=images/[name].[ext]'] @@ -61,15 +69,16 @@ module.exports = { } ] }, - plugins: [ + plugins: analyzeBundle ? [new BundleAnalyzerPlugin()] : [ new HTMLWebpackPlugin({ - title: 'Doodle3D Slicer - Simple example', + favicon: 'favicon.ico', + title: 'Doodle3D Slicer', template: require('html-webpack-template'), inject: false, appMountId: 'app' - }), + }) ], - devtool: "source-map", + devtool: devMode ? 'source-map' : false, devServer: { contentBase: 'dist' }