From db097184abebcd8357c8c29669a269817f35b56d Mon Sep 17 00:00:00 2001 From: wyattis Date: Wed, 25 Sep 2019 17:52:10 -0400 Subject: [PATCH 001/234] Rearranged files to separate the new Vue/Typescript client from the old AngularJS application --- frontend/app/breadboard.js | 47 -- frontend/app/client/client-graph.js | 425 -------------- frontend/app/util/http.js | 6 - frontend/client/TODO.md | 15 + frontend/client/components/Choice.vue | 15 + frontend/client/components/Graph.vue | 15 + frontend/client/components/PlayerChoices.vue | 15 + frontend/client/components/PlayerText.vue | 15 + frontend/client/components/PlayerTimers.vue | 15 + frontend/client/components/Timer.vue | 15 + frontend/client/main.ts | 31 + frontend/client/plugins/vuetify.ts | 9 + frontend/client/types.d.ts | 3 + frontend/client/vue-shim.d.ts | 4 + frontend/core/TypedResponse.ts | 3 + frontend/core/breadboard.ts | 88 +++ frontend/core/http.ts | 8 + .../amt-admin/amt-admin.app.js | 0 .../amt-admin/amt-admin.controller.js | 0 .../amt-admin/amt-admin.directive.js | 0 .../amt-admin/amt-admin.service.js | 0 .../amt-admin/amt-admin.style.css | 0 .../amt-admin/amt-admin.template.html | 0 .../amt-admin/create-hit/create-hit.app.js | 0 .../create-hit/create-hit.controller.js | 0 .../create-hit/create-hit.directive.js | 0 .../create-hit/create-hit.service.js | 0 .../amt-admin/create-hit/create-hit.style.css | 0 .../create-hit/create-hit.template.html | 0 .../select-qualifications.app.js | 0 .../select-qualifications.controller.js | 0 .../select-qualifications.directive.js | 0 .../select-qualifications.service.js | 0 .../select-qualifications.style.css | 0 .../select-qualifications.template.html | 0 .../manage-qualifications.app.js | 0 .../manage-qualifications.controller.js | 0 .../manage-qualifications.directive.js | 0 .../manage-qualifications.service.js | 0 .../manage-qualifications.style.css | 0 .../manage-qualifications.template.html | 0 frontend/{app => design}/client.js | 2 - .../client/choices.controller.js | 0 .../client/client-directives.js | 0 .../{app => design}/client/client-filters.js | 0 .../client/client.controller.js | 0 frontend/{app => design}/client/client.sass | 0 .../content/content-name.controller.js | 0 .../content/content-name.directive.js | 0 .../content/content-name.template.html | 0 .../content/content-status.controller.js | 0 .../content/content-status.directive.js | 0 .../content/content-status.template.html | 0 .../{app => design}/content/content.app.js | 0 .../content/content.controller.js | 0 .../content/content.directive.js | 0 .../content/content.service.js | 0 .../{app => design}/content/content.style.css | 0 .../content/content.template.html | 0 .../create-first-user.app.js | 0 .../create-first-user.controller.js | 0 .../create-first-user.directive.js | 0 .../create-first-user.service.js | 0 .../create-first-user.template.html | 0 .../create-new-experiment.app.js | 0 .../create-new-experiment.controller.js | 0 .../create-new-experiment.directive.js | 0 .../create-new-experiment.service.js | 0 .../create-new-experiment.template.html | 0 .../customize/customize.app.js | 0 .../customize/customize.controller.js | 0 .../customize/customize.directive.js | 0 .../customize/customize.service.js | 0 .../customize/customize.style.css | 0 .../customize/customize.template.html | 0 frontend/{app => design}/design.js | 2 - frontend/{app => design}/design/app.js | 0 frontend/{app => design}/design/breadboard.js | 0 .../{app => design}/design/controllers.js | 0 frontend/{app => design}/design/design.sass | 0 frontend/{app => design}/design/directives.js | 0 frontend/{app => design}/design/filters.js | 0 frontend/{app => design}/design/graph.js | 0 frontend/{app => design}/design/routes.js | 0 frontend/{app => design}/design/services.js | 0 .../instance-parameters.app.js | 0 .../instance-parameters.directive.js | 0 .../instance-parameters.template.html | 0 .../directives/tab-status/tab-status.app.js | 0 .../tab-status/tab-status.directive.js | 0 .../tab-status/tab-status.template.html | 0 .../experiment-import.app.js | 0 .../experiment-import.controller.js | 0 .../experiment-import.directive.js | 0 .../experiment-import.template.html | 0 .../{app => design}/login/login.controller.js | 0 .../{app => design}/login/login.directive.js | 0 .../{app => design}/login/login.template.html | 0 .../middleware/Authorization.middleware.js | 0 .../providers/ui-jq-config.value.js | 0 .../services/alert/alert.service.js | 0 .../services/alert/confirm.sass | 0 .../services/alert/confirm.template.html | 0 .../services/breadboard.factory.js | 12 +- .../services/client-graph.service.js | 11 +- .../services/client.factory.js | 10 +- .../services/config.service.js | 0 .../{app => design}/services/constants.js | 0 .../{app => design}/services/csv.service.js | 0 .../services/download.service.js | 0 .../services/language.service.js | 0 .../services/script-injector.service.js | 15 +- .../services/services.module.js | 0 .../services/websocket.factory.js | 0 .../steps/step-name.controller.js | 0 .../steps/step-name.directive.js | 0 .../steps/step-name.template.html | 0 .../{app => design}/steps/step.controller.js | 0 .../{app => design}/steps/step.directive.js | 0 .../{app => design}/steps/step.template.html | 0 frontend/{app => design}/steps/steps.app.js | 0 .../{app => design}/steps/steps.controller.js | 0 .../{app => design}/steps/steps.directive.js | 0 .../{app => design}/steps/steps.service.js | 0 .../{app => design}/steps/steps.style.css | 0 .../{app => design}/steps/steps.template.html | 0 .../templates/create-first-user.html | 0 frontend/{app => design}/templates/home.html | 0 frontend/{app => design}/templates/login.html | 0 .../{app => design}/testing/testing.app.js | 0 .../testing/testing.controller.js | 0 .../testing/testing.directive.js | 0 .../testing/testing.service.js | 0 .../{app => design}/testing/testing.style.css | 0 .../testing/testing.template.html | 0 .../{app => design}/timer/timer.controller.js | 0 .../{app => design}/timer/timer.directive.js | 0 .../{app => design}/timer/timer.template.html | 0 frontend/{app => design}/util/gremlins.min.js | 0 frontend/{app => design}/util/keycodes.js | 0 frontend/{app => design}/util/util.js | 0 frontend/package-lock.json | 541 ++++++++++++++++++ frontend/package.json | 11 +- frontend/tsconfig.json | 31 + frontend/tslint.json | 3 + frontend/webpack/webpack.base.js | 136 ++--- frontend/webpack/webpack.client.js | 10 +- frontend/webpack/webpack.core.js | 10 + frontend/webpack/webpack.design.js | 8 +- frontend/webpack/webpack.dev.js | 24 +- frontend/webpack/webpack.prod.js | 7 +- frontend/webpack/webpack.server.js | 41 +- 152 files changed, 978 insertions(+), 625 deletions(-) delete mode 100644 frontend/app/breadboard.js delete mode 100644 frontend/app/client/client-graph.js delete mode 100644 frontend/app/util/http.js create mode 100644 frontend/client/TODO.md create mode 100644 frontend/client/components/Choice.vue create mode 100644 frontend/client/components/Graph.vue create mode 100644 frontend/client/components/PlayerChoices.vue create mode 100644 frontend/client/components/PlayerText.vue create mode 100644 frontend/client/components/PlayerTimers.vue create mode 100644 frontend/client/components/Timer.vue create mode 100644 frontend/client/main.ts create mode 100644 frontend/client/plugins/vuetify.ts create mode 100644 frontend/client/types.d.ts create mode 100644 frontend/client/vue-shim.d.ts create mode 100644 frontend/core/TypedResponse.ts create mode 100644 frontend/core/breadboard.ts create mode 100644 frontend/core/http.ts rename frontend/{app => design}/amt-admin/amt-admin.app.js (100%) rename frontend/{app => design}/amt-admin/amt-admin.controller.js (100%) rename frontend/{app => design}/amt-admin/amt-admin.directive.js (100%) rename frontend/{app => design}/amt-admin/amt-admin.service.js (100%) rename frontend/{app => design}/amt-admin/amt-admin.style.css (100%) rename frontend/{app => design}/amt-admin/amt-admin.template.html (100%) rename frontend/{app => design}/amt-admin/create-hit/create-hit.app.js (100%) rename frontend/{app => design}/amt-admin/create-hit/create-hit.controller.js (100%) rename frontend/{app => design}/amt-admin/create-hit/create-hit.directive.js (100%) rename frontend/{app => design}/amt-admin/create-hit/create-hit.service.js (100%) rename frontend/{app => design}/amt-admin/create-hit/create-hit.style.css (100%) rename frontend/{app => design}/amt-admin/create-hit/create-hit.template.html (100%) rename frontend/{app => design}/amt-admin/create-hit/select-qualifications/select-qualifications.app.js (100%) rename frontend/{app => design}/amt-admin/create-hit/select-qualifications/select-qualifications.controller.js (100%) rename frontend/{app => design}/amt-admin/create-hit/select-qualifications/select-qualifications.directive.js (100%) rename frontend/{app => design}/amt-admin/create-hit/select-qualifications/select-qualifications.service.js (100%) rename frontend/{app => design}/amt-admin/create-hit/select-qualifications/select-qualifications.style.css (100%) rename frontend/{app => design}/amt-admin/create-hit/select-qualifications/select-qualifications.template.html (100%) rename frontend/{app => design}/amt-admin/manage-qualifications/manage-qualifications.app.js (100%) rename frontend/{app => design}/amt-admin/manage-qualifications/manage-qualifications.controller.js (100%) rename frontend/{app => design}/amt-admin/manage-qualifications/manage-qualifications.directive.js (100%) rename frontend/{app => design}/amt-admin/manage-qualifications/manage-qualifications.service.js (100%) rename frontend/{app => design}/amt-admin/manage-qualifications/manage-qualifications.style.css (100%) rename frontend/{app => design}/amt-admin/manage-qualifications/manage-qualifications.template.html (100%) rename frontend/{app => design}/client.js (97%) rename frontend/{app => design}/client/choices.controller.js (100%) rename frontend/{app => design}/client/client-directives.js (100%) rename frontend/{app => design}/client/client-filters.js (100%) rename frontend/{app => design}/client/client.controller.js (100%) rename frontend/{app => design}/client/client.sass (100%) rename frontend/{app => design}/content/content-name.controller.js (100%) rename frontend/{app => design}/content/content-name.directive.js (100%) rename frontend/{app => design}/content/content-name.template.html (100%) rename frontend/{app => design}/content/content-status.controller.js (100%) rename frontend/{app => design}/content/content-status.directive.js (100%) rename frontend/{app => design}/content/content-status.template.html (100%) rename frontend/{app => design}/content/content.app.js (100%) rename frontend/{app => design}/content/content.controller.js (100%) rename frontend/{app => design}/content/content.directive.js (100%) rename frontend/{app => design}/content/content.service.js (100%) rename frontend/{app => design}/content/content.style.css (100%) rename frontend/{app => design}/content/content.template.html (100%) rename frontend/{app => design}/create-first-user/create-first-user.app.js (100%) rename frontend/{app => design}/create-first-user/create-first-user.controller.js (100%) rename frontend/{app => design}/create-first-user/create-first-user.directive.js (100%) rename frontend/{app => design}/create-first-user/create-first-user.service.js (100%) rename frontend/{app => design}/create-first-user/create-first-user.template.html (100%) rename frontend/{app => design}/create-new-experiment/create-new-experiment.app.js (100%) rename frontend/{app => design}/create-new-experiment/create-new-experiment.controller.js (100%) rename frontend/{app => design}/create-new-experiment/create-new-experiment.directive.js (100%) rename frontend/{app => design}/create-new-experiment/create-new-experiment.service.js (100%) rename frontend/{app => design}/create-new-experiment/create-new-experiment.template.html (100%) rename frontend/{app => design}/customize/customize.app.js (100%) rename frontend/{app => design}/customize/customize.controller.js (100%) rename frontend/{app => design}/customize/customize.directive.js (100%) rename frontend/{app => design}/customize/customize.service.js (100%) rename frontend/{app => design}/customize/customize.style.css (100%) rename frontend/{app => design}/customize/customize.template.html (100%) rename frontend/{app => design}/design.js (91%) rename frontend/{app => design}/design/app.js (100%) rename frontend/{app => design}/design/breadboard.js (100%) rename frontend/{app => design}/design/controllers.js (100%) rename frontend/{app => design}/design/design.sass (100%) rename frontend/{app => design}/design/directives.js (100%) rename frontend/{app => design}/design/filters.js (100%) rename frontend/{app => design}/design/graph.js (100%) rename frontend/{app => design}/design/routes.js (100%) rename frontend/{app => design}/design/services.js (100%) rename frontend/{app => design}/directives/instance-parameters/instance-parameters.app.js (100%) rename frontend/{app => design}/directives/instance-parameters/instance-parameters.directive.js (100%) rename frontend/{app => design}/directives/instance-parameters/instance-parameters.template.html (100%) rename frontend/{app => design}/directives/tab-status/tab-status.app.js (100%) rename frontend/{app => design}/directives/tab-status/tab-status.directive.js (100%) rename frontend/{app => design}/directives/tab-status/tab-status.template.html (100%) rename frontend/{app => design}/experiment-import/experiment-import.app.js (100%) rename frontend/{app => design}/experiment-import/experiment-import.controller.js (100%) rename frontend/{app => design}/experiment-import/experiment-import.directive.js (100%) rename frontend/{app => design}/experiment-import/experiment-import.template.html (100%) rename frontend/{app => design}/login/login.controller.js (100%) rename frontend/{app => design}/login/login.directive.js (100%) rename frontend/{app => design}/login/login.template.html (100%) rename frontend/{app => design}/middleware/Authorization.middleware.js (100%) rename frontend/{app => design}/providers/ui-jq-config.value.js (100%) rename frontend/{app => design}/services/alert/alert.service.js (100%) rename frontend/{app => design}/services/alert/confirm.sass (100%) rename frontend/{app => design}/services/alert/confirm.template.html (100%) rename frontend/{app => design}/services/breadboard.factory.js (93%) rename frontend/{app => design}/services/client-graph.service.js (72%) rename frontend/{app => design}/services/client.factory.js (82%) rename frontend/{app => design}/services/config.service.js (100%) rename frontend/{app => design}/services/constants.js (100%) rename frontend/{app => design}/services/csv.service.js (100%) rename frontend/{app => design}/services/download.service.js (100%) rename frontend/{app => design}/services/language.service.js (100%) rename frontend/{app => design}/services/script-injector.service.js (78%) rename frontend/{app => design}/services/services.module.js (100%) rename frontend/{app => design}/services/websocket.factory.js (100%) rename frontend/{app => design}/steps/step-name.controller.js (100%) rename frontend/{app => design}/steps/step-name.directive.js (100%) rename frontend/{app => design}/steps/step-name.template.html (100%) rename frontend/{app => design}/steps/step.controller.js (100%) rename frontend/{app => design}/steps/step.directive.js (100%) rename frontend/{app => design}/steps/step.template.html (100%) rename frontend/{app => design}/steps/steps.app.js (100%) rename frontend/{app => design}/steps/steps.controller.js (100%) rename frontend/{app => design}/steps/steps.directive.js (100%) rename frontend/{app => design}/steps/steps.service.js (100%) rename frontend/{app => design}/steps/steps.style.css (100%) rename frontend/{app => design}/steps/steps.template.html (100%) rename frontend/{app => design}/templates/create-first-user.html (100%) rename frontend/{app => design}/templates/home.html (100%) rename frontend/{app => design}/templates/login.html (100%) rename frontend/{app => design}/testing/testing.app.js (100%) rename frontend/{app => design}/testing/testing.controller.js (100%) rename frontend/{app => design}/testing/testing.directive.js (100%) rename frontend/{app => design}/testing/testing.service.js (100%) rename frontend/{app => design}/testing/testing.style.css (100%) rename frontend/{app => design}/testing/testing.template.html (100%) rename frontend/{app => design}/timer/timer.controller.js (100%) rename frontend/{app => design}/timer/timer.directive.js (100%) rename frontend/{app => design}/timer/timer.template.html (100%) rename frontend/{app => design}/util/gremlins.min.js (100%) rename frontend/{app => design}/util/keycodes.js (100%) rename frontend/{app => design}/util/util.js (100%) create mode 100644 frontend/tsconfig.json create mode 100644 frontend/tslint.json create mode 100644 frontend/webpack/webpack.core.js diff --git a/frontend/app/breadboard.js b/frontend/app/breadboard.js deleted file mode 100644 index 8bf4a63..0000000 --- a/frontend/app/breadboard.js +++ /dev/null @@ -1,47 +0,0 @@ -import { http } from './util/http' -import { Mutex } from 'async-mutex' - -export class Breadboard { - - constructor () { - this.socket = null - this.state = null - this.socketMutex = new Mutex() - this.stateMutex = new Mutex() - } - - async loadConfig () { - const release = await this.stateMutex.acquire() - if (this.state) { - release() - return this.state - } - try { - const res = await http.get('state') - this.state = res.json() - } finally { - release() - } - return this.state - } - - /** - * Returns the websocket used to talk to the server. - * @returns {Promise} - */ - async connect () { - const release = await this.socketMutex.acquire() - if (this.socket) { - release() - return this.socket - } - try { - const config = await this.loadConfig() - this.socket = new WebSocket(config.connectSocket) - } finally { - release() - } - return this.socket - } - -} diff --git a/frontend/app/client/client-graph.js b/frontend/app/client/client-graph.js deleted file mode 100644 index 9276ff5..0000000 --- a/frontend/app/client/client-graph.js +++ /dev/null @@ -1,425 +0,0 @@ -export default function Graph(w, h, clientId) { - - var width = (w == undefined) ? 600 : w; - var height = (h == undefined) ? 600 : h; - var egoNodeR = 50; - var alterNodeR = 30; - var arrowPadding = 7; - var graphPadding = 10; - var linkDistance = (Math.min(width, height) / 2) - alterNodeR - (2 * graphPadding); - - - var ignoreProps = ["$$hashKey", "text", "choices", "x", "y", "px", "py"]; - - // set up initial svg object - var div = d3.select("#graph"); - var vis = div.append("svg:svg") - .attr("width", width) - .attr("height", height); - - // set up arrow markers for graph links - // Thanks to rkirsling for the example here: http://bl.ocks.org/rkirsling/5001347 - vis.append('svg:defs').append('svg:marker') - .attr('id', 'end') - .attr('viewBox', '0 -5 10 10') //'0 -5 10 10' - .attr('refX', 6) - .attr('markerWidth', 4) - .attr('markerHeight', 4) - .attr('orient', 'auto') - .append('svg:path') - .attr('d', 'M0,-5L10,0L0,5') - .attr('fill', '#333'); - - vis.append('svg:defs').append('svg:marker') - .attr('id', 'start') - .attr('viewBox', '0 -5 10 10') //'0 -5 10 10' - .attr('refX', 4) - .attr('markerWidth', 4) - .attr('markerHeight', 4) - .attr('orient', 'auto') - .append('svg:path') - .attr('d', 'M10,-5L0,0L10,5') - .attr('fill', '#333'); - - vis.append('svg:defs').append('svg:marker') - .attr('id', 'end-green') - .attr('viewBox', '0 -5 10 10')//'0 -5 10 10' - .attr('refX', 6) - .attr('markerWidth', 4) - .attr('markerHeight', 4) - .attr('orient', 'auto') - .append('svg:path') - .attr('d', 'M0,-5L10,0L0,5') - .attr('fill', 'green'); - - vis.append('svg:defs').append('svg:marker') - .attr('id', 'end-red') - .attr('viewBox', '0 -5 10 10')//'0 -5 10 10' - .attr('refX', 6) - .attr('markerWidth', 4) - .attr('markerHeight', 4) - .attr('orient', 'auto') - .append('svg:path') - .attr('d', 'M0,-5L10,0L0,5') - .attr('fill', 'red'); - - vis.append('svg:defs').append('svg:marker') - .attr('id', 'start-green') - .attr('viewBox', '0 -5 10 10')//'0 -5 10 10' - .attr('refX', 4) - .attr('markerWidth', 4) - .attr('markerHeight', 4) - .attr('orient', 'auto') - .append('svg:path') - .attr('d', 'M10,-5L0,0L10,5') - .attr('fill', 'green'); - - vis.append('svg:defs').append('svg:marker') - .attr('id', 'start-red') - .attr('viewBox', '0 -5 10 10')//'0 -5 10 10' - .attr('refX', 4) - .attr('markerWidth', 4) - .attr('markerHeight', 4) - .attr('orient', 'auto') - .append('svg:path') - .attr('d', 'M10,-5L0,0L10,5') - .attr('fill', 'red'); - - var force = d3.layout.force() - .gravity(.05) - .friction(0.8) - .charge(-10000) //-500 - .linkStrength(10) //2 - .linkDistance(linkDistance * 0.9) - .size([width, height]); - - var nodes = force.nodes(), - links = force.links(); - - force.on("tick", function () { - vis.selectAll("line.link") - .attr("x1", function (d) { - var deltaX = d.target.x - d.source.x, - deltaY = d.target.y - d.source.y, - dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY), - normX = deltaX / dist, - sourcePadding = (d.source.id == clientId) ? egoNodeR : alterNodeR; - if (d.arrow && d.arrow.length > 0) { - sourcePadding += arrowPadding; - } - return d.source.x + (sourcePadding * normX); - }) - .attr("y1", function (d) { - var deltaX = d.target.x - d.source.x, - deltaY = d.target.y - d.source.y, - dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY), - normY = deltaY / dist, - sourcePadding = (d.source.id == clientId) ? egoNodeR : alterNodeR; - if (d.arrow && d.arrow.length > 0) { - sourcePadding += arrowPadding; - } - return d.source.y + (sourcePadding * normY); - }) - .attr("x2", function (d) { - var deltaX = d.target.x - d.source.x, - deltaY = d.target.y - d.source.y, - dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY), - normX = deltaX / dist, - targetPadding = (d.target.id == clientId) ? egoNodeR : alterNodeR; - if (d.arrow && d.arrow.length > 0) { - targetPadding += arrowPadding; - } - return targetX = d.target.x - (targetPadding * normX); - }) - .attr("y2", function (d) { - var deltaX = d.target.x - d.source.x, - deltaY = d.target.y - d.source.y, - dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY), - normY = deltaY / dist, - targetPadding = (d.target.id == clientId) ? egoNodeR : alterNodeR; - if (d.arrow && d.arrow.length > 0) { - targetPadding += arrowPadding; - } - return targetY = d.target.y - (targetPadding * normY); - }); - - vis.selectAll("g.node") - .attr("transform", function (d) { - return "translate(" + d.x + "," + d.y + ")" - }); - }); - - var removeNode = function (nid) { - var nodeIndex = findNode(nid); - if (nodeIndex > -1) { - nodes.splice(i, 1); - } - } - - var findNode = function (nid) { - for (var i = 0; i < nodes.length; i++) { - if (nodes[i].id == nid) { - return nodes[i]; - } - } - return null; - } - - var addLink = function (link, sourceId, targetId) { - link.source = findNode(sourceId); - link.target = findNode(targetId); - links.push(link); - } - - var updateLink = function (oldLink, newLink, sourceId, targetId) { - _.extend(oldLink, newLink); - oldLink.source = findNode(sourceId); - oldLink.target = findNode(targetId); - } - - this.updateGraph = function (newGraph) { - - if (newGraph == undefined) - return; - - if (newGraph.nodes == undefined || newGraph.nodes.length == 0) { - // Remove all nodes - nodes.length = 0; - } else { - // If there is anything in the old array that isn't in the new, it needs to be removed - for (var i = nodes.length - 1; i >= 0; i--) { - if (_.find(newGraph.nodes, function (n) { - return n.id === nodes[i].id; - }) === undefined) { - nodes.splice(i, 1); - } - } - - // Finally, anything in the new array that isn't in the old needs to be added - for (var i = 0; i < newGraph.nodes.length; i++) { - var oldNode = _.find(nodes, function (n) { - return n.id === newGraph.nodes[i].id; - }); - if (oldNode === null || oldNode === undefined) { - nodes.push(newGraph.nodes[i]); - } else { - // Update the old node - _.extend(oldNode, newGraph.nodes[i]); - } - } - } - - if (newGraph.links == undefined || newGraph.links.length == 0) { - // Remove all links - links.length = 0; - } else { - // If there is anything in the old array that isn't in the new, it needs to be removed - for (var i = links.length - 1; i >= 0; i--) { - // source or target could have been removed at this point - var sourceId = (links[i].source == undefined) ? null : links[i].source.id; - var targetId = (links[i].target == undefined) ? null : links[i].target.id; - - try { - if (_.find(newGraph.links, function (l) { - return ((newGraph.nodes[l.source].id === sourceId) && (newGraph.nodes[l.target].id === targetId)); - }) === undefined) { - links.splice(i, 1); - } - } catch (e) { - //TODO: Why is there an exception being thrown here? - } - } - - // Finally, anything in the new array that isn't in the old needs to be added - for (var i = 0; i < newGraph.links.length; i++) { - var sourceIdx, targetIdx, source, target, sourceId, targetId = undefined; - var link = newGraph.links[i]; - if (link != undefined) { - sourceIdx = link.source; - targetIdx = link.target; - } - - if (sourceIdx != undefined && targetIdx != undefined) { - source = newGraph.nodes[sourceIdx]; - target = newGraph.nodes[targetIdx]; - } - - if (source != undefined && target != undefined) { - sourceId = source.id; - targetId = target.id; - } - - if (sourceId != undefined && targetId != undefined) { - var oldLink = _.find(links, function (l) { - return ((l.target.id === targetId) && (l.source.id === sourceId)); - }); - if (oldLink === null || oldLink === undefined) { - addLink(link, sourceId, targetId); - } else { - // Update the old link - updateLink(oldLink, link, sourceId, targetId); - } - } - } - } - - update(); - }; - - var animateScore = function (amount, start, end, endNodeId) { - //console.log("animateScore(" + amount + ", " + start + ", " + end + ", " + endNodeId + ")"); - - var animText = vis.append("svg:text") - .attr("class", "anim") - .style("text-anchor", "middle") - .style("fill", "#1EFF1E") - .style("stroke", "#000") - .style("font-family", "Lucida Sans") - .style("font-weight", "bold") - .style("font-size", 18) - .text(((amount < 0) ? "" : "+") + amount) - .attr("x", start.x) - .attr("y", start.y) - .transition() - .duration(1500) - .attr("x", end.x) - .attr("y", end.y) - .remove(); - - } - - var update = function () { - var link = vis.selectAll("line.link") - .data(links, function (d) { - return d.id; - }); - - link.enter().insert("svg:line", "g.node") - .attr("class", "link client"); - - link.exit().remove(); - - var g = vis.selectAll("g.node") - .data(nodes, function (d) { - return d.id; - }); - - var gEnter = g.enter().append("svg:g") - .attr("class", "node client"); - //.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); - - gEnter.append("svg:text") - .attr("class", "node client") - .style("text-anchor", "middle") - .style("font-size", function (d) { - return (d.id == clientId) ? "18pt" : "14pt" - }) - .text(function (d) { - return (d.score == undefined) ? "" : d.score; - }); - - gEnter.insert("svg:circle", "text.node") - .attr("class", "node client") - .attr("r", function (d) { - return (d.id == clientId) ? egoNodeR : alterNodeR; - }) - .each(function (d) { - if (d.id == clientId) { - d.fixed = true; - d.x = width / 2; - d.y = height / 2; - } - }); - - g.exit().remove(); - - - var scoreText = vis.selectAll("text.node"); - - scoreText.text(function (d) { - return (d.score == undefined) ? "" : d.score; - }); - - force - .nodes(nodes) - .links(links) - .start(); - - var node = g.selectAll("circle.node"); - - d3.selectAll("circle.node").each(function (d, i) { - for (var propertyName in d) { - if (_.indexOf(ignoreProps, propertyName) == -1 && isNaN(propertyName)) { - d3.select(this).attr(propertyName, d[propertyName]); - } - } - }); - - d3.selectAll("line.link").each(function (d, i) { - d3.select(this).attr("marker-start", null); - d3.select(this).attr("marker-end", null); - - for (var propertyName in d) { - if (propertyName == "arrow") { - var arrowParams = d.arrow.split(","); - if (arrowParams.length < 1) { - return; - } - - if (d.source.id == arrowParams[0] || arrowParams[0] == "both") { - if (arrowParams.length > 1 && arrowParams[1] != "grey") { - d3.select(this).attr("marker-start", "url(#start-" + arrowParams[1] + ")") - } else { - d3.select(this).attr("marker-start", "url(#start)") - } - } else { - d3.select(this).attr("marker-start", null); - } - - if (d.target.id == arrowParams[0] || arrowParams[0] == "both") { - if (arrowParams.length > 1 && arrowParams[1] != "grey") { - d3.select(this).attr("marker-end", "url(#end-" + arrowParams[1] + ")") - } else { - d3.select(this).attr("marker-end", "url(#end)") - } - } else { - d3.select(this).attr("marker-end", null); - } - - } else if (_.indexOf(ignoreProps, propertyName) == -1) { - d3.select(this).attr(propertyName, d[propertyName]); - } - } - }); - - - var setupAnim = function () { - link.each(function (d) { - var animate = d3.select(this).attr("animate"); - if (animate != undefined) { - var params = animate.split(","); - if (params.length > 3) { - var round = params[0]; - var amount = params[1]; - var startNodeId = params[2]; - var endNodeId = params[3]; - - var startNode = findNode(startNodeId); - var endNode = findNode(endNodeId); - - var start = {"x": startNode.x, "y": startNode.y}; - var end = {"x": endNode.x, "y": endNode.y}; - - if ((d.animated != animate) && start != undefined && end != undefined && endNodeId != undefined) { - d.animated = animate; - animateScore(amount, start, end, endNodeId); - } - } - } - }); - }; - - var t = setTimeout(setupAnim, 1000); - - }; -} diff --git a/frontend/app/util/http.js b/frontend/app/util/http.js deleted file mode 100644 index 4814bcb..0000000 --- a/frontend/app/util/http.js +++ /dev/null @@ -1,6 +0,0 @@ -export const http = { - async get (url, params) { - params = Object.assign({ method: 'GET' }, params) - return fetch(url, params) - } -} diff --git a/frontend/client/TODO.md b/frontend/client/TODO.md new file mode 100644 index 0000000..9a5d78a --- /dev/null +++ b/frontend/client/TODO.md @@ -0,0 +1,15 @@ +# TODO +- [ ] Locales +- [ ] Gremlins +- [ ] Graph +- [ ] Choices + - [ ] Custom choices +- [ ] Player text +- [ ] Custom styles +- [ ] Timer + + +# Flow +- Breadboard object loads +- Client JS and templates load +- Client JS creates the Vue instance (or whatever) diff --git a/frontend/client/components/Choice.vue b/frontend/client/components/Choice.vue new file mode 100644 index 0000000..004a9fd --- /dev/null +++ b/frontend/client/components/Choice.vue @@ -0,0 +1,15 @@ + + + + + diff --git a/frontend/client/components/Graph.vue b/frontend/client/components/Graph.vue new file mode 100644 index 0000000..e483b4a --- /dev/null +++ b/frontend/client/components/Graph.vue @@ -0,0 +1,15 @@ + + + + + diff --git a/frontend/client/components/PlayerChoices.vue b/frontend/client/components/PlayerChoices.vue new file mode 100644 index 0000000..a4932fd --- /dev/null +++ b/frontend/client/components/PlayerChoices.vue @@ -0,0 +1,15 @@ + + + + + diff --git a/frontend/client/components/PlayerText.vue b/frontend/client/components/PlayerText.vue new file mode 100644 index 0000000..9a9ff15 --- /dev/null +++ b/frontend/client/components/PlayerText.vue @@ -0,0 +1,15 @@ + + + + + diff --git a/frontend/client/components/PlayerTimers.vue b/frontend/client/components/PlayerTimers.vue new file mode 100644 index 0000000..89713e3 --- /dev/null +++ b/frontend/client/components/PlayerTimers.vue @@ -0,0 +1,15 @@ + + + + + diff --git a/frontend/client/components/Timer.vue b/frontend/client/components/Timer.vue new file mode 100644 index 0000000..157ba06 --- /dev/null +++ b/frontend/client/components/Timer.vue @@ -0,0 +1,15 @@ + + + + + diff --git a/frontend/client/main.ts b/frontend/client/main.ts new file mode 100644 index 0000000..f62e586 --- /dev/null +++ b/frontend/client/main.ts @@ -0,0 +1,31 @@ +import Vue from 'vue' +import vuetify from '@/plugins/vuetify' +import { Breadboard } from './types' + +async function main () { + let config + try { + config = await Breadboard.loadConfig() + } catch (err) { + console.error('Breadboard: Unable to load Breadboard') + throw err + } + + try { + await Breadboard.addScriptFromString(config.clientGraph) + } catch (err) { + console.error('Breadboard: Unable to run client-graph.js') + throw err + } + + // TODO: Move this to client graph instead + Breadboard.loadConfig().then(config => { + new Vue({ + vuetify, + // template: config.clientHtml + template: `` + }).$mount('#app') + }) +} + +main() diff --git a/frontend/client/plugins/vuetify.ts b/frontend/client/plugins/vuetify.ts new file mode 100644 index 0000000..d3848b1 --- /dev/null +++ b/frontend/client/plugins/vuetify.ts @@ -0,0 +1,9 @@ +import Vue from 'vue' +import Vuetify from 'vuetify' +import 'vuetify/dist/vuetify.min.css' + +Vue.use(Vuetify) + +const opts = {} + +export default new Vuetify(opts) diff --git a/frontend/client/types.d.ts b/frontend/client/types.d.ts new file mode 100644 index 0000000..7575c74 --- /dev/null +++ b/frontend/client/types.d.ts @@ -0,0 +1,3 @@ +import { BreadboardClass } from '../core/breadboard' + +declare const Breadboard: BreadboardClass diff --git a/frontend/client/vue-shim.d.ts b/frontend/client/vue-shim.d.ts new file mode 100644 index 0000000..0660bd6 --- /dev/null +++ b/frontend/client/vue-shim.d.ts @@ -0,0 +1,4 @@ +declare module "*.vue" { + import Vue from "vue"; + export default Vue; +} diff --git a/frontend/core/TypedResponse.ts b/frontend/core/TypedResponse.ts new file mode 100644 index 0000000..63e8b5f --- /dev/null +++ b/frontend/core/TypedResponse.ts @@ -0,0 +1,3 @@ +export interface TypedResponse extends Response { + json (): Promise +} diff --git a/frontend/core/breadboard.ts b/frontend/core/breadboard.ts new file mode 100644 index 0000000..6931725 --- /dev/null +++ b/frontend/core/breadboard.ts @@ -0,0 +1,88 @@ +import 'core-js' +import 'regenerator-runtime' +import { http } from './http' +import { Mutex } from 'async-mutex' + +type BreadboardState = { + [key: string]: string | number, + connectSocket: string, + clientGraph: string, + clientHtml: string +} + +export class BreadboardClass { + + private socket!: WebSocket + private state: BreadboardState + private socketMutex = new Mutex() + private stateMutex = new Mutex() + + /** + * Load the client config. + * @returns {Promise} + */ + async loadConfig (): Promise { + const release = await this.stateMutex.acquire() + if (this.state) { + release() + return this.state + } + try { + const res = await http.get('state') + this.state = await res.json() + } finally { + release() + } + return this.state + } + + /** + * Returns the websocket that's connected to the server. + * @returns {Promise} + */ + async connect (): Promise { + const release = await this.socketMutex.acquire() + if (this.socket) { + release() + return this.socket + } + try { + const config = await this.loadConfig() + this.socket = new WebSocket(config.connectSocket) + } finally { + release() + } + return this.socket + } + + /** + * Load a script from a url. + * @param src + * @returns {Promise} + */ + addScriptFromURL (src: string): Promise { + return new Promise((resolve, reject) => { + const script = document.createElement('script') + script.src = src + script.onload = () => resolve() + script.onerror = reject + document.body.appendChild(script) + }) + } + + addScriptFromString (contents: string): Promise { + return new Promise((resolve, reject) => { + try { + var geval = eval + geval(contents) + setTimeout(resolve) + } catch (err) { + reject(err) + } + }) + } + +} + +// @ts-ignore export globally +window.Breadboard = new BreadboardClass() diff --git a/frontend/core/http.ts b/frontend/core/http.ts new file mode 100644 index 0000000..101270d --- /dev/null +++ b/frontend/core/http.ts @@ -0,0 +1,8 @@ +import { TypedResponse } from './TypedResponse' + +export class http { + static get (url: string, params = {}): Promise> { + params = Object.assign({ method: 'GET' }, params) + return fetch(url, params) + } +} diff --git a/frontend/app/amt-admin/amt-admin.app.js b/frontend/design/amt-admin/amt-admin.app.js similarity index 100% rename from frontend/app/amt-admin/amt-admin.app.js rename to frontend/design/amt-admin/amt-admin.app.js diff --git a/frontend/app/amt-admin/amt-admin.controller.js b/frontend/design/amt-admin/amt-admin.controller.js similarity index 100% rename from frontend/app/amt-admin/amt-admin.controller.js rename to frontend/design/amt-admin/amt-admin.controller.js diff --git a/frontend/app/amt-admin/amt-admin.directive.js b/frontend/design/amt-admin/amt-admin.directive.js similarity index 100% rename from frontend/app/amt-admin/amt-admin.directive.js rename to frontend/design/amt-admin/amt-admin.directive.js diff --git a/frontend/app/amt-admin/amt-admin.service.js b/frontend/design/amt-admin/amt-admin.service.js similarity index 100% rename from frontend/app/amt-admin/amt-admin.service.js rename to frontend/design/amt-admin/amt-admin.service.js diff --git a/frontend/app/amt-admin/amt-admin.style.css b/frontend/design/amt-admin/amt-admin.style.css similarity index 100% rename from frontend/app/amt-admin/amt-admin.style.css rename to frontend/design/amt-admin/amt-admin.style.css diff --git a/frontend/app/amt-admin/amt-admin.template.html b/frontend/design/amt-admin/amt-admin.template.html similarity index 100% rename from frontend/app/amt-admin/amt-admin.template.html rename to frontend/design/amt-admin/amt-admin.template.html diff --git a/frontend/app/amt-admin/create-hit/create-hit.app.js b/frontend/design/amt-admin/create-hit/create-hit.app.js similarity index 100% rename from frontend/app/amt-admin/create-hit/create-hit.app.js rename to frontend/design/amt-admin/create-hit/create-hit.app.js diff --git a/frontend/app/amt-admin/create-hit/create-hit.controller.js b/frontend/design/amt-admin/create-hit/create-hit.controller.js similarity index 100% rename from frontend/app/amt-admin/create-hit/create-hit.controller.js rename to frontend/design/amt-admin/create-hit/create-hit.controller.js diff --git a/frontend/app/amt-admin/create-hit/create-hit.directive.js b/frontend/design/amt-admin/create-hit/create-hit.directive.js similarity index 100% rename from frontend/app/amt-admin/create-hit/create-hit.directive.js rename to frontend/design/amt-admin/create-hit/create-hit.directive.js diff --git a/frontend/app/amt-admin/create-hit/create-hit.service.js b/frontend/design/amt-admin/create-hit/create-hit.service.js similarity index 100% rename from frontend/app/amt-admin/create-hit/create-hit.service.js rename to frontend/design/amt-admin/create-hit/create-hit.service.js diff --git a/frontend/app/amt-admin/create-hit/create-hit.style.css b/frontend/design/amt-admin/create-hit/create-hit.style.css similarity index 100% rename from frontend/app/amt-admin/create-hit/create-hit.style.css rename to frontend/design/amt-admin/create-hit/create-hit.style.css diff --git a/frontend/app/amt-admin/create-hit/create-hit.template.html b/frontend/design/amt-admin/create-hit/create-hit.template.html similarity index 100% rename from frontend/app/amt-admin/create-hit/create-hit.template.html rename to frontend/design/amt-admin/create-hit/create-hit.template.html diff --git a/frontend/app/amt-admin/create-hit/select-qualifications/select-qualifications.app.js b/frontend/design/amt-admin/create-hit/select-qualifications/select-qualifications.app.js similarity index 100% rename from frontend/app/amt-admin/create-hit/select-qualifications/select-qualifications.app.js rename to frontend/design/amt-admin/create-hit/select-qualifications/select-qualifications.app.js diff --git a/frontend/app/amt-admin/create-hit/select-qualifications/select-qualifications.controller.js b/frontend/design/amt-admin/create-hit/select-qualifications/select-qualifications.controller.js similarity index 100% rename from frontend/app/amt-admin/create-hit/select-qualifications/select-qualifications.controller.js rename to frontend/design/amt-admin/create-hit/select-qualifications/select-qualifications.controller.js diff --git a/frontend/app/amt-admin/create-hit/select-qualifications/select-qualifications.directive.js b/frontend/design/amt-admin/create-hit/select-qualifications/select-qualifications.directive.js similarity index 100% rename from frontend/app/amt-admin/create-hit/select-qualifications/select-qualifications.directive.js rename to frontend/design/amt-admin/create-hit/select-qualifications/select-qualifications.directive.js diff --git a/frontend/app/amt-admin/create-hit/select-qualifications/select-qualifications.service.js b/frontend/design/amt-admin/create-hit/select-qualifications/select-qualifications.service.js similarity index 100% rename from frontend/app/amt-admin/create-hit/select-qualifications/select-qualifications.service.js rename to frontend/design/amt-admin/create-hit/select-qualifications/select-qualifications.service.js diff --git a/frontend/app/amt-admin/create-hit/select-qualifications/select-qualifications.style.css b/frontend/design/amt-admin/create-hit/select-qualifications/select-qualifications.style.css similarity index 100% rename from frontend/app/amt-admin/create-hit/select-qualifications/select-qualifications.style.css rename to frontend/design/amt-admin/create-hit/select-qualifications/select-qualifications.style.css diff --git a/frontend/app/amt-admin/create-hit/select-qualifications/select-qualifications.template.html b/frontend/design/amt-admin/create-hit/select-qualifications/select-qualifications.template.html similarity index 100% rename from frontend/app/amt-admin/create-hit/select-qualifications/select-qualifications.template.html rename to frontend/design/amt-admin/create-hit/select-qualifications/select-qualifications.template.html diff --git a/frontend/app/amt-admin/manage-qualifications/manage-qualifications.app.js b/frontend/design/amt-admin/manage-qualifications/manage-qualifications.app.js similarity index 100% rename from frontend/app/amt-admin/manage-qualifications/manage-qualifications.app.js rename to frontend/design/amt-admin/manage-qualifications/manage-qualifications.app.js diff --git a/frontend/app/amt-admin/manage-qualifications/manage-qualifications.controller.js b/frontend/design/amt-admin/manage-qualifications/manage-qualifications.controller.js similarity index 100% rename from frontend/app/amt-admin/manage-qualifications/manage-qualifications.controller.js rename to frontend/design/amt-admin/manage-qualifications/manage-qualifications.controller.js diff --git a/frontend/app/amt-admin/manage-qualifications/manage-qualifications.directive.js b/frontend/design/amt-admin/manage-qualifications/manage-qualifications.directive.js similarity index 100% rename from frontend/app/amt-admin/manage-qualifications/manage-qualifications.directive.js rename to frontend/design/amt-admin/manage-qualifications/manage-qualifications.directive.js diff --git a/frontend/app/amt-admin/manage-qualifications/manage-qualifications.service.js b/frontend/design/amt-admin/manage-qualifications/manage-qualifications.service.js similarity index 100% rename from frontend/app/amt-admin/manage-qualifications/manage-qualifications.service.js rename to frontend/design/amt-admin/manage-qualifications/manage-qualifications.service.js diff --git a/frontend/app/amt-admin/manage-qualifications/manage-qualifications.style.css b/frontend/design/amt-admin/manage-qualifications/manage-qualifications.style.css similarity index 100% rename from frontend/app/amt-admin/manage-qualifications/manage-qualifications.style.css rename to frontend/design/amt-admin/manage-qualifications/manage-qualifications.style.css diff --git a/frontend/app/amt-admin/manage-qualifications/manage-qualifications.template.html b/frontend/design/amt-admin/manage-qualifications/manage-qualifications.template.html similarity index 100% rename from frontend/app/amt-admin/manage-qualifications/manage-qualifications.template.html rename to frontend/design/amt-admin/manage-qualifications/manage-qualifications.template.html diff --git a/frontend/app/client.js b/frontend/design/client.js similarity index 97% rename from frontend/app/client.js rename to frontend/design/client.js index 4b9b90a..8b28f79 100644 --- a/frontend/app/client.js +++ b/frontend/design/client.js @@ -1,7 +1,5 @@ import 'core-js' import 'regenerator-runtime' -import { Breadboard } from './breadboard' -window.Breadboard = new Breadboard() import angular from 'angular'; import 'jquery'; import 'jquery-ui'; diff --git a/frontend/app/client/choices.controller.js b/frontend/design/client/choices.controller.js similarity index 100% rename from frontend/app/client/choices.controller.js rename to frontend/design/client/choices.controller.js diff --git a/frontend/app/client/client-directives.js b/frontend/design/client/client-directives.js similarity index 100% rename from frontend/app/client/client-directives.js rename to frontend/design/client/client-directives.js diff --git a/frontend/app/client/client-filters.js b/frontend/design/client/client-filters.js similarity index 100% rename from frontend/app/client/client-filters.js rename to frontend/design/client/client-filters.js diff --git a/frontend/app/client/client.controller.js b/frontend/design/client/client.controller.js similarity index 100% rename from frontend/app/client/client.controller.js rename to frontend/design/client/client.controller.js diff --git a/frontend/app/client/client.sass b/frontend/design/client/client.sass similarity index 100% rename from frontend/app/client/client.sass rename to frontend/design/client/client.sass diff --git a/frontend/app/content/content-name.controller.js b/frontend/design/content/content-name.controller.js similarity index 100% rename from frontend/app/content/content-name.controller.js rename to frontend/design/content/content-name.controller.js diff --git a/frontend/app/content/content-name.directive.js b/frontend/design/content/content-name.directive.js similarity index 100% rename from frontend/app/content/content-name.directive.js rename to frontend/design/content/content-name.directive.js diff --git a/frontend/app/content/content-name.template.html b/frontend/design/content/content-name.template.html similarity index 100% rename from frontend/app/content/content-name.template.html rename to frontend/design/content/content-name.template.html diff --git a/frontend/app/content/content-status.controller.js b/frontend/design/content/content-status.controller.js similarity index 100% rename from frontend/app/content/content-status.controller.js rename to frontend/design/content/content-status.controller.js diff --git a/frontend/app/content/content-status.directive.js b/frontend/design/content/content-status.directive.js similarity index 100% rename from frontend/app/content/content-status.directive.js rename to frontend/design/content/content-status.directive.js diff --git a/frontend/app/content/content-status.template.html b/frontend/design/content/content-status.template.html similarity index 100% rename from frontend/app/content/content-status.template.html rename to frontend/design/content/content-status.template.html diff --git a/frontend/app/content/content.app.js b/frontend/design/content/content.app.js similarity index 100% rename from frontend/app/content/content.app.js rename to frontend/design/content/content.app.js diff --git a/frontend/app/content/content.controller.js b/frontend/design/content/content.controller.js similarity index 100% rename from frontend/app/content/content.controller.js rename to frontend/design/content/content.controller.js diff --git a/frontend/app/content/content.directive.js b/frontend/design/content/content.directive.js similarity index 100% rename from frontend/app/content/content.directive.js rename to frontend/design/content/content.directive.js diff --git a/frontend/app/content/content.service.js b/frontend/design/content/content.service.js similarity index 100% rename from frontend/app/content/content.service.js rename to frontend/design/content/content.service.js diff --git a/frontend/app/content/content.style.css b/frontend/design/content/content.style.css similarity index 100% rename from frontend/app/content/content.style.css rename to frontend/design/content/content.style.css diff --git a/frontend/app/content/content.template.html b/frontend/design/content/content.template.html similarity index 100% rename from frontend/app/content/content.template.html rename to frontend/design/content/content.template.html diff --git a/frontend/app/create-first-user/create-first-user.app.js b/frontend/design/create-first-user/create-first-user.app.js similarity index 100% rename from frontend/app/create-first-user/create-first-user.app.js rename to frontend/design/create-first-user/create-first-user.app.js diff --git a/frontend/app/create-first-user/create-first-user.controller.js b/frontend/design/create-first-user/create-first-user.controller.js similarity index 100% rename from frontend/app/create-first-user/create-first-user.controller.js rename to frontend/design/create-first-user/create-first-user.controller.js diff --git a/frontend/app/create-first-user/create-first-user.directive.js b/frontend/design/create-first-user/create-first-user.directive.js similarity index 100% rename from frontend/app/create-first-user/create-first-user.directive.js rename to frontend/design/create-first-user/create-first-user.directive.js diff --git a/frontend/app/create-first-user/create-first-user.service.js b/frontend/design/create-first-user/create-first-user.service.js similarity index 100% rename from frontend/app/create-first-user/create-first-user.service.js rename to frontend/design/create-first-user/create-first-user.service.js diff --git a/frontend/app/create-first-user/create-first-user.template.html b/frontend/design/create-first-user/create-first-user.template.html similarity index 100% rename from frontend/app/create-first-user/create-first-user.template.html rename to frontend/design/create-first-user/create-first-user.template.html diff --git a/frontend/app/create-new-experiment/create-new-experiment.app.js b/frontend/design/create-new-experiment/create-new-experiment.app.js similarity index 100% rename from frontend/app/create-new-experiment/create-new-experiment.app.js rename to frontend/design/create-new-experiment/create-new-experiment.app.js diff --git a/frontend/app/create-new-experiment/create-new-experiment.controller.js b/frontend/design/create-new-experiment/create-new-experiment.controller.js similarity index 100% rename from frontend/app/create-new-experiment/create-new-experiment.controller.js rename to frontend/design/create-new-experiment/create-new-experiment.controller.js diff --git a/frontend/app/create-new-experiment/create-new-experiment.directive.js b/frontend/design/create-new-experiment/create-new-experiment.directive.js similarity index 100% rename from frontend/app/create-new-experiment/create-new-experiment.directive.js rename to frontend/design/create-new-experiment/create-new-experiment.directive.js diff --git a/frontend/app/create-new-experiment/create-new-experiment.service.js b/frontend/design/create-new-experiment/create-new-experiment.service.js similarity index 100% rename from frontend/app/create-new-experiment/create-new-experiment.service.js rename to frontend/design/create-new-experiment/create-new-experiment.service.js diff --git a/frontend/app/create-new-experiment/create-new-experiment.template.html b/frontend/design/create-new-experiment/create-new-experiment.template.html similarity index 100% rename from frontend/app/create-new-experiment/create-new-experiment.template.html rename to frontend/design/create-new-experiment/create-new-experiment.template.html diff --git a/frontend/app/customize/customize.app.js b/frontend/design/customize/customize.app.js similarity index 100% rename from frontend/app/customize/customize.app.js rename to frontend/design/customize/customize.app.js diff --git a/frontend/app/customize/customize.controller.js b/frontend/design/customize/customize.controller.js similarity index 100% rename from frontend/app/customize/customize.controller.js rename to frontend/design/customize/customize.controller.js diff --git a/frontend/app/customize/customize.directive.js b/frontend/design/customize/customize.directive.js similarity index 100% rename from frontend/app/customize/customize.directive.js rename to frontend/design/customize/customize.directive.js diff --git a/frontend/app/customize/customize.service.js b/frontend/design/customize/customize.service.js similarity index 100% rename from frontend/app/customize/customize.service.js rename to frontend/design/customize/customize.service.js diff --git a/frontend/app/customize/customize.style.css b/frontend/design/customize/customize.style.css similarity index 100% rename from frontend/app/customize/customize.style.css rename to frontend/design/customize/customize.style.css diff --git a/frontend/app/customize/customize.template.html b/frontend/design/customize/customize.template.html similarity index 100% rename from frontend/app/customize/customize.template.html rename to frontend/design/customize/customize.template.html diff --git a/frontend/app/design.js b/frontend/design/design.js similarity index 91% rename from frontend/app/design.js rename to frontend/design/design.js index 1e64326..a068819 100644 --- a/frontend/app/design.js +++ b/frontend/design/design.js @@ -1,7 +1,5 @@ import 'core-js' import 'regenerator-runtime' -import { Breadboard } from './breadboard' -window.Breadboard = new Breadboard() import 'jquery'; import angular from 'angular'; import '../lib/jquery-ui/jquery-ui'; diff --git a/frontend/app/design/app.js b/frontend/design/design/app.js similarity index 100% rename from frontend/app/design/app.js rename to frontend/design/design/app.js diff --git a/frontend/app/design/breadboard.js b/frontend/design/design/breadboard.js similarity index 100% rename from frontend/app/design/breadboard.js rename to frontend/design/design/breadboard.js diff --git a/frontend/app/design/controllers.js b/frontend/design/design/controllers.js similarity index 100% rename from frontend/app/design/controllers.js rename to frontend/design/design/controllers.js diff --git a/frontend/app/design/design.sass b/frontend/design/design/design.sass similarity index 100% rename from frontend/app/design/design.sass rename to frontend/design/design/design.sass diff --git a/frontend/app/design/directives.js b/frontend/design/design/directives.js similarity index 100% rename from frontend/app/design/directives.js rename to frontend/design/design/directives.js diff --git a/frontend/app/design/filters.js b/frontend/design/design/filters.js similarity index 100% rename from frontend/app/design/filters.js rename to frontend/design/design/filters.js diff --git a/frontend/app/design/graph.js b/frontend/design/design/graph.js similarity index 100% rename from frontend/app/design/graph.js rename to frontend/design/design/graph.js diff --git a/frontend/app/design/routes.js b/frontend/design/design/routes.js similarity index 100% rename from frontend/app/design/routes.js rename to frontend/design/design/routes.js diff --git a/frontend/app/design/services.js b/frontend/design/design/services.js similarity index 100% rename from frontend/app/design/services.js rename to frontend/design/design/services.js diff --git a/frontend/app/directives/instance-parameters/instance-parameters.app.js b/frontend/design/directives/instance-parameters/instance-parameters.app.js similarity index 100% rename from frontend/app/directives/instance-parameters/instance-parameters.app.js rename to frontend/design/directives/instance-parameters/instance-parameters.app.js diff --git a/frontend/app/directives/instance-parameters/instance-parameters.directive.js b/frontend/design/directives/instance-parameters/instance-parameters.directive.js similarity index 100% rename from frontend/app/directives/instance-parameters/instance-parameters.directive.js rename to frontend/design/directives/instance-parameters/instance-parameters.directive.js diff --git a/frontend/app/directives/instance-parameters/instance-parameters.template.html b/frontend/design/directives/instance-parameters/instance-parameters.template.html similarity index 100% rename from frontend/app/directives/instance-parameters/instance-parameters.template.html rename to frontend/design/directives/instance-parameters/instance-parameters.template.html diff --git a/frontend/app/directives/tab-status/tab-status.app.js b/frontend/design/directives/tab-status/tab-status.app.js similarity index 100% rename from frontend/app/directives/tab-status/tab-status.app.js rename to frontend/design/directives/tab-status/tab-status.app.js diff --git a/frontend/app/directives/tab-status/tab-status.directive.js b/frontend/design/directives/tab-status/tab-status.directive.js similarity index 100% rename from frontend/app/directives/tab-status/tab-status.directive.js rename to frontend/design/directives/tab-status/tab-status.directive.js diff --git a/frontend/app/directives/tab-status/tab-status.template.html b/frontend/design/directives/tab-status/tab-status.template.html similarity index 100% rename from frontend/app/directives/tab-status/tab-status.template.html rename to frontend/design/directives/tab-status/tab-status.template.html diff --git a/frontend/app/experiment-import/experiment-import.app.js b/frontend/design/experiment-import/experiment-import.app.js similarity index 100% rename from frontend/app/experiment-import/experiment-import.app.js rename to frontend/design/experiment-import/experiment-import.app.js diff --git a/frontend/app/experiment-import/experiment-import.controller.js b/frontend/design/experiment-import/experiment-import.controller.js similarity index 100% rename from frontend/app/experiment-import/experiment-import.controller.js rename to frontend/design/experiment-import/experiment-import.controller.js diff --git a/frontend/app/experiment-import/experiment-import.directive.js b/frontend/design/experiment-import/experiment-import.directive.js similarity index 100% rename from frontend/app/experiment-import/experiment-import.directive.js rename to frontend/design/experiment-import/experiment-import.directive.js diff --git a/frontend/app/experiment-import/experiment-import.template.html b/frontend/design/experiment-import/experiment-import.template.html similarity index 100% rename from frontend/app/experiment-import/experiment-import.template.html rename to frontend/design/experiment-import/experiment-import.template.html diff --git a/frontend/app/login/login.controller.js b/frontend/design/login/login.controller.js similarity index 100% rename from frontend/app/login/login.controller.js rename to frontend/design/login/login.controller.js diff --git a/frontend/app/login/login.directive.js b/frontend/design/login/login.directive.js similarity index 100% rename from frontend/app/login/login.directive.js rename to frontend/design/login/login.directive.js diff --git a/frontend/app/login/login.template.html b/frontend/design/login/login.template.html similarity index 100% rename from frontend/app/login/login.template.html rename to frontend/design/login/login.template.html diff --git a/frontend/app/middleware/Authorization.middleware.js b/frontend/design/middleware/Authorization.middleware.js similarity index 100% rename from frontend/app/middleware/Authorization.middleware.js rename to frontend/design/middleware/Authorization.middleware.js diff --git a/frontend/app/providers/ui-jq-config.value.js b/frontend/design/providers/ui-jq-config.value.js similarity index 100% rename from frontend/app/providers/ui-jq-config.value.js rename to frontend/design/providers/ui-jq-config.value.js diff --git a/frontend/app/services/alert/alert.service.js b/frontend/design/services/alert/alert.service.js similarity index 100% rename from frontend/app/services/alert/alert.service.js rename to frontend/design/services/alert/alert.service.js diff --git a/frontend/app/services/alert/confirm.sass b/frontend/design/services/alert/confirm.sass similarity index 100% rename from frontend/app/services/alert/confirm.sass rename to frontend/design/services/alert/confirm.sass diff --git a/frontend/app/services/alert/confirm.template.html b/frontend/design/services/alert/confirm.template.html similarity index 100% rename from frontend/app/services/alert/confirm.template.html rename to frontend/design/services/alert/confirm.template.html diff --git a/frontend/app/services/breadboard.factory.js b/frontend/design/services/breadboard.factory.js similarity index 93% rename from frontend/app/services/breadboard.factory.js rename to frontend/design/services/breadboard.factory.js index ff1cbb0..708ca95 100644 --- a/frontend/app/services/breadboard.factory.js +++ b/frontend/design/services/breadboard.factory.js @@ -65,8 +65,8 @@ export default function BreadboardFactory($websocketFactory, $rootScope, $cookie async onmessage (callback) { const config = await window.Breadboard.loadConfig() websocket = await window.Breadboard.connect() - websocket.onmessage = function(message){ - let data = JSON.parse(message.data); + websocket.addEventListener('message', function (e) { + let data = JSON.parse(e.data); if (data.hasOwnProperty("queuedMessages")) { for (var i = 0; i < data.queuedMessages.length; i++) { processMessage(data.queuedMessages[i], callback); @@ -74,10 +74,10 @@ export default function BreadboardFactory($websocketFactory, $rootScope, $cookie } else { processMessage(data, callback); } - }; - websocket.onopen = function (evt) { - websocket.send(JSON.stringify({ action: 'LogIn', uid: config.uid })); - }; + }) + websocket.addEventListener('open', function () { + websocket.send(JSON.stringify({ action: 'LogIn', uid: config.uid })) + }) }, send: function (message) { configService.get('uid').then(function(uid) { diff --git a/frontend/app/services/client-graph.service.js b/frontend/design/services/client-graph.service.js similarity index 72% rename from frontend/app/services/client-graph.service.js rename to frontend/design/services/client-graph.service.js index cec38b6..57d318b 100644 --- a/frontend/app/services/client-graph.service.js +++ b/frontend/design/services/client-graph.service.js @@ -8,13 +8,12 @@ export default function ClientGraphService($q, scriptInjector, configService){ this.load = function(){ return configService.get('clientGraph') .then(contents => { - //console.log("Evaluating in global scope", contents); - return scriptInjector.injectScript(contents); + return scriptInjector.injectScript(contents) }) .then(() => { - return window.Graph; + return window.Graph }, err => { - return DefaultGraph; - }); + return DefaultGraph + }) } -} \ No newline at end of file +} diff --git a/frontend/app/services/client.factory.js b/frontend/design/services/client.factory.js similarity index 82% rename from frontend/app/services/client.factory.js rename to frontend/design/services/client.factory.js index bf912ad..c5514bd 100644 --- a/frontend/app/services/client.factory.js +++ b/frontend/design/services/client.factory.js @@ -12,12 +12,12 @@ export default function ClientFactory($websocketFactory, $rootScope, $http, $q, return { async onmessage (callback) { const websocket = await window.Breadboard.connect() - websocket.onmessage = function() { - let args = arguments; + websocket.addEventListener('message', function () { + let args = arguments $rootScope.$apply(function () { - callback.apply(websocket, args); - }); - }; + callback.apply(websocket, args) + }) + }) }, async send (message) { const websocket = await window.Breadboard.connect() diff --git a/frontend/app/services/config.service.js b/frontend/design/services/config.service.js similarity index 100% rename from frontend/app/services/config.service.js rename to frontend/design/services/config.service.js diff --git a/frontend/app/services/constants.js b/frontend/design/services/constants.js similarity index 100% rename from frontend/app/services/constants.js rename to frontend/design/services/constants.js diff --git a/frontend/app/services/csv.service.js b/frontend/design/services/csv.service.js similarity index 100% rename from frontend/app/services/csv.service.js rename to frontend/design/services/csv.service.js diff --git a/frontend/app/services/download.service.js b/frontend/design/services/download.service.js similarity index 100% rename from frontend/app/services/download.service.js rename to frontend/design/services/download.service.js diff --git a/frontend/app/services/language.service.js b/frontend/design/services/language.service.js similarity index 100% rename from frontend/app/services/language.service.js rename to frontend/design/services/language.service.js diff --git a/frontend/app/services/script-injector.service.js b/frontend/design/services/script-injector.service.js similarity index 78% rename from frontend/app/services/script-injector.service.js rename to frontend/design/services/script-injector.service.js index 748d5a0..0079cb1 100644 --- a/frontend/app/services/script-injector.service.js +++ b/frontend/design/services/script-injector.service.js @@ -29,15 +29,14 @@ export default function ScriptInjectorService($q, $timeout){ return deferred.promise; }; - this.injectScript = function(contents){ + this.injectScript = function (contents) { - let geval = eval; // Hacky thing to evaluate script in global scope - let timeoutPromise = $timeout(function(){ - geval(contents); - }); - - return $q.when(timeoutPromise); + let geval = eval // Hacky thing to evaluate script in global scope + let timeoutPromise = $timeout(function () { + geval(contents) + }) + return $q.when(timeoutPromise) }; -} \ No newline at end of file +} diff --git a/frontend/app/services/services.module.js b/frontend/design/services/services.module.js similarity index 100% rename from frontend/app/services/services.module.js rename to frontend/design/services/services.module.js diff --git a/frontend/app/services/websocket.factory.js b/frontend/design/services/websocket.factory.js similarity index 100% rename from frontend/app/services/websocket.factory.js rename to frontend/design/services/websocket.factory.js diff --git a/frontend/app/steps/step-name.controller.js b/frontend/design/steps/step-name.controller.js similarity index 100% rename from frontend/app/steps/step-name.controller.js rename to frontend/design/steps/step-name.controller.js diff --git a/frontend/app/steps/step-name.directive.js b/frontend/design/steps/step-name.directive.js similarity index 100% rename from frontend/app/steps/step-name.directive.js rename to frontend/design/steps/step-name.directive.js diff --git a/frontend/app/steps/step-name.template.html b/frontend/design/steps/step-name.template.html similarity index 100% rename from frontend/app/steps/step-name.template.html rename to frontend/design/steps/step-name.template.html diff --git a/frontend/app/steps/step.controller.js b/frontend/design/steps/step.controller.js similarity index 100% rename from frontend/app/steps/step.controller.js rename to frontend/design/steps/step.controller.js diff --git a/frontend/app/steps/step.directive.js b/frontend/design/steps/step.directive.js similarity index 100% rename from frontend/app/steps/step.directive.js rename to frontend/design/steps/step.directive.js diff --git a/frontend/app/steps/step.template.html b/frontend/design/steps/step.template.html similarity index 100% rename from frontend/app/steps/step.template.html rename to frontend/design/steps/step.template.html diff --git a/frontend/app/steps/steps.app.js b/frontend/design/steps/steps.app.js similarity index 100% rename from frontend/app/steps/steps.app.js rename to frontend/design/steps/steps.app.js diff --git a/frontend/app/steps/steps.controller.js b/frontend/design/steps/steps.controller.js similarity index 100% rename from frontend/app/steps/steps.controller.js rename to frontend/design/steps/steps.controller.js diff --git a/frontend/app/steps/steps.directive.js b/frontend/design/steps/steps.directive.js similarity index 100% rename from frontend/app/steps/steps.directive.js rename to frontend/design/steps/steps.directive.js diff --git a/frontend/app/steps/steps.service.js b/frontend/design/steps/steps.service.js similarity index 100% rename from frontend/app/steps/steps.service.js rename to frontend/design/steps/steps.service.js diff --git a/frontend/app/steps/steps.style.css b/frontend/design/steps/steps.style.css similarity index 100% rename from frontend/app/steps/steps.style.css rename to frontend/design/steps/steps.style.css diff --git a/frontend/app/steps/steps.template.html b/frontend/design/steps/steps.template.html similarity index 100% rename from frontend/app/steps/steps.template.html rename to frontend/design/steps/steps.template.html diff --git a/frontend/app/templates/create-first-user.html b/frontend/design/templates/create-first-user.html similarity index 100% rename from frontend/app/templates/create-first-user.html rename to frontend/design/templates/create-first-user.html diff --git a/frontend/app/templates/home.html b/frontend/design/templates/home.html similarity index 100% rename from frontend/app/templates/home.html rename to frontend/design/templates/home.html diff --git a/frontend/app/templates/login.html b/frontend/design/templates/login.html similarity index 100% rename from frontend/app/templates/login.html rename to frontend/design/templates/login.html diff --git a/frontend/app/testing/testing.app.js b/frontend/design/testing/testing.app.js similarity index 100% rename from frontend/app/testing/testing.app.js rename to frontend/design/testing/testing.app.js diff --git a/frontend/app/testing/testing.controller.js b/frontend/design/testing/testing.controller.js similarity index 100% rename from frontend/app/testing/testing.controller.js rename to frontend/design/testing/testing.controller.js diff --git a/frontend/app/testing/testing.directive.js b/frontend/design/testing/testing.directive.js similarity index 100% rename from frontend/app/testing/testing.directive.js rename to frontend/design/testing/testing.directive.js diff --git a/frontend/app/testing/testing.service.js b/frontend/design/testing/testing.service.js similarity index 100% rename from frontend/app/testing/testing.service.js rename to frontend/design/testing/testing.service.js diff --git a/frontend/app/testing/testing.style.css b/frontend/design/testing/testing.style.css similarity index 100% rename from frontend/app/testing/testing.style.css rename to frontend/design/testing/testing.style.css diff --git a/frontend/app/testing/testing.template.html b/frontend/design/testing/testing.template.html similarity index 100% rename from frontend/app/testing/testing.template.html rename to frontend/design/testing/testing.template.html diff --git a/frontend/app/timer/timer.controller.js b/frontend/design/timer/timer.controller.js similarity index 100% rename from frontend/app/timer/timer.controller.js rename to frontend/design/timer/timer.controller.js diff --git a/frontend/app/timer/timer.directive.js b/frontend/design/timer/timer.directive.js similarity index 100% rename from frontend/app/timer/timer.directive.js rename to frontend/design/timer/timer.directive.js diff --git a/frontend/app/timer/timer.template.html b/frontend/design/timer/timer.template.html similarity index 100% rename from frontend/app/timer/timer.template.html rename to frontend/design/timer/timer.template.html diff --git a/frontend/app/util/gremlins.min.js b/frontend/design/util/gremlins.min.js similarity index 100% rename from frontend/app/util/gremlins.min.js rename to frontend/design/util/gremlins.min.js diff --git a/frontend/app/util/keycodes.js b/frontend/design/util/keycodes.js similarity index 100% rename from frontend/app/util/keycodes.js rename to frontend/design/util/keycodes.js diff --git a/frontend/app/util/util.js b/frontend/design/util/util.js similarity index 100% rename from frontend/app/util/util.js rename to frontend/design/util/util.js diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 3f386f3..dafdefb 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1168,6 +1168,48 @@ "resolved": "https://registry.npmjs.org/@uirouter/core/-/core-5.0.11.tgz", "integrity": "sha512-x8js8f0nJivRMlxVyFcP5VmHyI091qUYCSEP69+m3uTCsIlCvLWmQiT4/FY7YBe9go6tYBBzPV+dWseg5XMD8Q==" }, + "@vue/component-compiler-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.0.0.tgz", + "integrity": "sha512-am+04/0UX7ektcmvhYmrf84BDVAD8afFOf4asZjN84q8xzxFclbk5x0MtxuKGfp+zjN5WWPJn3fjFAWtDdIGSw==", + "dev": true, + "requires": { + "consolidate": "^0.15.1", + "hash-sum": "^1.0.2", + "lru-cache": "^4.1.2", + "merge-source-map": "^1.1.0", + "postcss": "^7.0.14", + "postcss-selector-parser": "^5.0.0", + "prettier": "1.16.3", + "source-map": "~0.6.1", + "vue-template-es2015-compiler": "^1.9.0" + }, + "dependencies": { + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", + "dev": true + }, + "postcss-selector-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", + "dev": true, + "requires": { + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "@webassemblyjs/ast": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", @@ -2531,6 +2573,15 @@ "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true }, + "consolidate": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", + "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", + "dev": true, + "requires": { + "bluebird": "^3.1.1" + } + }, "constants-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", @@ -3155,6 +3206,12 @@ "regexp.prototype.flags": "^1.2.0" } }, + "deepmerge": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.0.0.tgz", + "integrity": "sha512-YZ1rOP5+kHor4hMAH+HRQnBQHg+wvS1un1hAOuIcxcBy0hzcUf6Jg2a1w65kpoOUnurOfZbERwjI1TfZxNjcww==", + "dev": true + }, "default-gateway": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", @@ -3284,6 +3341,18 @@ "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", "dev": true }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "dev": true + }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "dev": true + }, "detect-node": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", @@ -3381,6 +3450,12 @@ "minimalistic-crypto-utils": "^1.0.0" } }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, "emojis-list": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", @@ -3608,6 +3683,15 @@ } } }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, "express": { "version": "4.17.1", "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", @@ -3785,6 +3869,15 @@ "websocket-driver": ">=0.5.1" } }, + "fibers": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/fibers/-/fibers-4.0.1.tgz", + "integrity": "sha512-H79EJn7DMWXk48ygmC82bMP8KNcFBZF1CPfwBpYF6cO85hGWoIrlu7eyX9ayxfjP9Nsl0JXxdI6fpYU4DWVw2w==", + "dev": true, + "requires": { + "detect-libc": "^1.0.3" + } + }, "figgy-pudding": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", @@ -3929,6 +4022,18 @@ "pinkie-promise": "^2.0.0" } }, + "findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + } + }, "flush-write-stream": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", @@ -4717,6 +4822,47 @@ } } }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "requires": { + "global-prefix": "^3.0.0" + }, + "dependencies": { + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + }, "globby": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", @@ -4865,6 +5011,12 @@ "safe-buffer": "^5.0.1" } }, + "hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=", + "dev": true + }, "hash.js": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", @@ -4900,6 +5052,15 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, "hosted-git-info": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", @@ -5130,6 +5291,12 @@ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, "internal-ip": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", @@ -5140,6 +5307,12 @@ "ipaddr.js": "^1.9.0" } }, + "interpret": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", + "dev": true + }, "invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -5772,6 +5945,23 @@ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", "dev": true }, + "merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -6578,6 +6768,12 @@ "error-ex": "^1.2.0" } }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -6865,6 +7061,12 @@ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true }, + "prettier": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.16.3.tgz", + "integrity": "sha512-kn/GU6SMRYPxUakNXhpP0EedT/KmaPzr0H5lIsDogrykbaxOpOfAFfk5XA7DZrJyMAv1wlMV3CPcZruGXVVUZw==", + "dev": true + }, "private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", @@ -7372,6 +7574,29 @@ "resolve-from": "^3.0.0" } }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "dependencies": { + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + } + } + }, "resolve-from": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", @@ -7471,6 +7696,15 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "sass": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.22.12.tgz", + "integrity": "sha512-u5Rxn+dKTPCW5/11kMNxtmqKsxCjcpnqj9CaJoru1NqeJ0DOa9rOM00e0HqmseTAatGkKoLY+jaNecMYevu1gg==", + "dev": true, + "requires": { + "chokidar": ">=2.0.0 <4.0.0" + } + }, "sass-graph": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz", @@ -9035,6 +9269,12 @@ "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", "dev": true }, + "v8-compile-cache": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz", + "integrity": "sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w==", + "dev": true + }, "validate-npm-package-license": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", @@ -9071,6 +9311,53 @@ "indexof": "0.0.1" } }, + "vue": { + "version": "2.6.10", + "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.10.tgz", + "integrity": "sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==", + "dev": true + }, + "vue-hot-reload-api": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz", + "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==", + "dev": true + }, + "vue-loader": { + "version": "15.7.1", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.7.1.tgz", + "integrity": "sha512-fwIKtA23Pl/rqfYP5TSGK7gkEuLhoTvRYW+TU7ER3q9GpNLt/PjG5NLv3XHRDiTg7OPM1JcckBgds+VnAc+HbA==", + "dev": true, + "requires": { + "@vue/component-compiler-utils": "^3.0.0", + "hash-sum": "^1.0.2", + "loader-utils": "^1.1.0", + "vue-hot-reload-api": "^2.3.0", + "vue-style-loader": "^4.1.0" + } + }, + "vue-style-loader": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.2.tgz", + "integrity": "sha512-0ip8ge6Gzz/Bk0iHovU9XAUQaFt/G2B61bnWa2tCcqqdgfHs1lF9xXorFbE55Gmy92okFT+8bfmySuUOu13vxQ==", + "dev": true, + "requires": { + "hash-sum": "^1.0.2", + "loader-utils": "^1.0.2" + } + }, + "vue-template-es2015-compiler": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz", + "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", + "dev": true + }, + "vuetify": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/vuetify/-/vuetify-2.0.19.tgz", + "integrity": "sha512-zBskf77Z+RH8+Qs1q0NIDv/1enVkOoVH2dcdjcs+ZUNOhnlG0IkDedmqE2+PNm0JvJdgpOaV8wq+Pl69TGD2Hg==", + "dev": true + }, "watchpack": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", @@ -9160,6 +9447,260 @@ } } }, + "webpack-cli": { + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.9.tgz", + "integrity": "sha512-xwnSxWl8nZtBl/AFJCOn9pG7s5CYUYdZxmmukv+fAHLcBIHM36dImfpQg3WfShZXeArkWlf6QRw24Klcsv8a5A==", + "dev": true, + "requires": { + "chalk": "2.4.2", + "cross-spawn": "6.0.5", + "enhanced-resolve": "4.1.0", + "findup-sync": "3.0.0", + "global-modules": "2.0.0", + "import-local": "2.0.0", + "interpret": "1.2.0", + "loader-utils": "1.2.3", + "supports-color": "6.1.0", + "v8-compile-cache": "2.0.3", + "yargs": "13.2.4" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yargs": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz", + "integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "os-locale": "^3.1.0", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.0" + } + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, "webpack-dev-middleware": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index fc4e689..e9c2fa6 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -34,21 +34,28 @@ "underscore": "1.8.3" }, "devDependencies": { - "ajv": "^6.10.0", "@babel/core": "^7.6.0", + "@babel/polyfill": "^7.6.0", "@babel/preset-env": "^7.6.0", + "ajv": "^6.10.0", "babel-loader": "^8.0.6", - "@babel/polyfill": "^7.6.0", "css-loader": "^2.1.1", + "deepmerge": "^4.0.0", + "fibers": "^4.0.1", "file-loader": "^4.0.0", "html-loader": "^0.5.1", "ngtemplate-loader": "^2.0.1", "node-gyp": "^4.0.0", "node-sass": "^4.12.0", "popper.js": "^1.15.0", + "sass": "^1.22.12", "sass-loader": "^6.0.6", "style-loader": "^0.19.1", + "vue": "^2.6.10", + "vue-loader": "^15.7.1", + "vuetify": "^2.0.19", "webpack": "^4.0.0", + "webpack-cli": "^3.3.9", "webpack-dev-server": "^3.8.1", "webpack-livereload-plugin": "^2.2.0" }, diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json new file mode 100644 index 0000000..55c5692 --- /dev/null +++ b/frontend/tsconfig.json @@ -0,0 +1,31 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "esnext", + "jsx": "preserve", + "importHelpers": true, + "moduleResolution": "node", + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "sourceMap": true, + "baseUrl": ".", + "types": [ + "webpack-env", + "mocha", + "chai", + "vuetify" + ], + "lib": [ + "esnext", + "dom", + "dom.iterable" + ] + }, + "include": [ + "src/**/*", + "src/**/*" + ], + "exclude": [ + "node_modules" + ] +} diff --git a/frontend/tslint.json b/frontend/tslint.json new file mode 100644 index 0000000..8887798 --- /dev/null +++ b/frontend/tslint.json @@ -0,0 +1,3 @@ +{ + "extends": "tslint-config-standard" +} diff --git a/frontend/webpack/webpack.base.js b/frontend/webpack/webpack.base.js index be54d4a..2114a37 100644 --- a/frontend/webpack/webpack.base.js +++ b/frontend/webpack/webpack.base.js @@ -1,70 +1,76 @@ -"use strict"; -const webpack = require('webpack'); -const path = require('path'); -console.log(__dirname); -const buildPath = path.resolve(__dirname, '../../public/bundles/'); -const nodeModulesPath = path.resolve(__dirname, 'node_modules'); -const LiveReloadPlugin = require('webpack-livereload-plugin'); +'use strict' +const webpack = require('webpack') +const path = require('path') +console.log(__dirname) +const buildPath = path.resolve(__dirname, '../../public/bundles/') /** * Base configuration object for Webpack */ module.exports = { - output: { - path: buildPath, - publicPath: '/bundles/' - }, - module: { - rules: [ - { - test: /\.css$/, - use: ['style-loader','css-loader?url=false'], - // exclude: /node_modules/, - }, - { - test: /\.js$/, - use: { - loader: 'babel-loader', - options: { - presets: ['@babel/preset-env'] - } - }, - exclude: /node_modules/, - }, - { - test: /\.(sass|scss)$/, - use: ['style-loader', 'css-loader?url=false', 'sass-loader'], - exclude: /node_modules/, - }, - { - test: /\.html$/, - use: ['ngtemplate-loader?relativeTo=frontend&prefix=files', 'html-loader'], - exclude: /node_modules/, - }, - { - test: /\.(jpg|png)$/, - use: 'url-loader?limit=100000', - exclude: /node_modules/, - }, - { - test: /\.svg$/, - use: 'url-loader?limit=10000&mimetype=image/svg+xml', - exclude: /node_modules/, - }, - { - test: /\.(eot|svg|ttf|woff|woff2)$/, - use: 'file-loader?name=public/fonts/[name].[ext]' - } - ] - }, - resolve: { - extensions: ['.js','.json','.css','.html', '.jsx'] - }, - plugins: [ - new webpack.ContextReplacementPlugin( - /angular(\\|\/)core(\\|\/)@angular/, - path.resolve(__dirname, './app') - ), - new LiveReloadPlugin() - ] -}; + output: { + path: buildPath, + publicPath: '/bundles/' + }, + module: { + rules: [{ + test: /\.css$/, + use: ['style-loader','css-loader?url=false'], + // exclude: /node_modules/, + }, { + test: /\.js$/, + use: { + loader: 'babel-loader', + options: { + presets: ['@babel/preset-env'] + } + }, + exclude: /node_modules/, + }, { + test: /\.tsx?$/, + loader: 'ts-loader', + exclude: /node_modules/, + options: { + appendTsSuffixTo: [/\.vue$/] + } + }, { + test: /\.vue$/, + use: 'vue-loader' + }, { + test: /\.(sass|scss)$/, + use: ['vue-style-loader', 'css-loader?url=false', { + loader: 'sass-loader', + options: { + implementation: require('sass'), + fiber: require('fibers'), + indentedSyntax: true + } + }], + exclude: /node_modules/, + }, { + test: /\.html$/, + use: ['ngtemplate-loader?relativeTo=frontend&prefix=files', 'html-loader'], + exclude: /node_modules/, + }, { + test: /\.(jpg|png)$/, + use: 'url-loader?limit=100000', + exclude: /node_modules/, + }, { + test: /\.svg$/, + use: 'url-loader?limit=10000&mimetype=image/svg+xml', + exclude: /node_modules/, + }, { + test: /\.(eot|svg|ttf|woff|woff2)$/, + use: 'file-loader?name=public/fonts/[name].[ext]' + }] + }, + resolve: { + extensions: ['.js','.json','.css','.html', '.jsx', '.ts', '.tsx', '.vue'] + }, + plugins: [ + new webpack.ContextReplacementPlugin( + /angular(\\|\/)core(\\|\/)@angular/, + path.resolve(__dirname, './design') + ) + ] +} diff --git a/frontend/webpack/webpack.client.js b/frontend/webpack/webpack.client.js index b8e78d7..6a5b7b8 100644 --- a/frontend/webpack/webpack.client.js +++ b/frontend/webpack/webpack.client.js @@ -1,11 +1,11 @@ -let config = require('./webpack.base.js'); -config = Object.assign({}, config); -module.exports = Object.assign({}, config, { - entry: ['./app/client.js'], +const merge = require('webpack-merge') +const config = require('./webpack.base.js'); +module.exports = merge(Object.create(config), { + entry: ['./design/client.js'], output: { path: config.output.path, publicPath: config.output.publicPath, filename: 'client.js', sourceMapFilename: 'client.map' } -}); +}) diff --git a/frontend/webpack/webpack.core.js b/frontend/webpack/webpack.core.js new file mode 100644 index 0000000..6651498 --- /dev/null +++ b/frontend/webpack/webpack.core.js @@ -0,0 +1,10 @@ +let config = require('./webpack.base.js') +config = Object.assign({}, config) +module.exports = Object.assign({}, config, { + entry: ['./core/breadboard.ts'], + output: { + path: config.output.path, + publicPath: config.output.publicPath, + filename: 'breadboard.js' + } +}) diff --git a/frontend/webpack/webpack.design.js b/frontend/webpack/webpack.design.js index 4c70ba3..2f29487 100644 --- a/frontend/webpack/webpack.design.js +++ b/frontend/webpack/webpack.design.js @@ -1,7 +1,7 @@ -var config = require('./webpack.base.js'); -config = Object.assign({}, config); -module.exports = Object.assign({}, config, { - entry: ['./app/design.js'], +const merge = require('webpack-merge') +const config = require('./webpack.base.js') +module.exports = merge(Object.create(config), { + entry: ['./design/design.js'], output: { path: config.output.path, publicPath: config.output.publicPath, diff --git a/frontend/webpack/webpack.dev.js b/frontend/webpack/webpack.dev.js index 3749811..9c39e07 100644 --- a/frontend/webpack/webpack.dev.js +++ b/frontend/webpack/webpack.dev.js @@ -1,22 +1,14 @@ -/* global __dirname */ -const path = require('path'); -const webpack = require('webpack'); +const webpack = require('webpack') -const config = Object.create(require('./webpack.base.js')); +const config = require('./webpack.base.js') config.mode = 'development' config.devtool = 'source-map' config.plugins = [ - // new webpack.ContextReplacementPlugin( - // /angular(\\|\/)core(\\|\/)@angular/, - // path.resolve(__dirname, './app') - // ), - new webpack.HotModuleReplacementPlugin() -]; + // new webpack.HotModuleReplacementPlugin() +] -const clientConfig = Object.assign({}, config, require('./webpack.client.js')); -const designConfig = Object.assign({}, config, require('./webpack.design.js')); -module.exports = [clientConfig, designConfig].map(c => { - // c.entry = ['webpack/hot/dev-server', 'webpack-dev-server/client?http://localhost:8080'].concat(c.entry); - return c; -}); +const clientConfig = require('./webpack.client') +const designConfig = require('./webpack.design') +const coreConfig = require('./webpack.core') +module.exports = [clientConfig, designConfig, coreConfig] diff --git a/frontend/webpack/webpack.prod.js b/frontend/webpack/webpack.prod.js index 3e08337..aa199cc 100644 --- a/frontend/webpack/webpack.prod.js +++ b/frontend/webpack/webpack.prod.js @@ -1,6 +1,7 @@ -const designConfig = require('./webpack.design.js'); -const clientConfig = require('./webpack.client.js'); +const designConfig = require('./webpack.design') +const clientConfig = require('./webpack.client') +const coreConfig = require('./webpack.core') // TODO: add minification and prod stuff for client here -module.exports = [clientConfig, designConfig]; \ No newline at end of file +module.exports = [coreConfig, clientConfig, designConfig]; diff --git a/frontend/webpack/webpack.server.js b/frontend/webpack/webpack.server.js index 5f2c37d..fd9ab73 100644 --- a/frontend/webpack/webpack.server.js +++ b/frontend/webpack/webpack.server.js @@ -1,45 +1,40 @@ -"use strict"; -/** - * Webpack server for development. - */ -let webpack = require('webpack'); -let webpackDevServer = require('webpack-dev-server'); -let webpackConfig = require('./webpack.dev.js'); - -//noinspection JSUnresolvedVariable -let webpackPath = __dirname; +'use strict' +const webpack = require('webpack') +const webpackDevServer = require('webpack-dev-server') +const webpackConfig = require('./webpack.dev.js') // Notify about the path where the server is running -console.log('[Webpack] Server running at location: ' + webpackPath); +console.log('[Webpack] Server running at location: ' + __dirname) // First we fire up Webpack an pass in the configuration file -let bundleStart = null; -let compiler = webpack(webpackConfig); +const compiler = webpack(webpackConfig) // We give notice in the terminal when it starts bundling and // set the time it started compiler.compilers.forEach(comp => { + let bundleStart comp.plugin('compile', function() { - console.log('[Webpack] Bundling...'); - bundleStart = Date.now(); - }); + console.log('[Webpack] Bundling...') + bundleStart = Date.now() + }) comp.plugin('done', function() { - console.log('[Webpack] Bundled in ' + (Date.now() - bundleStart) + 'ms!'); - }); + console.log('[Webpack] Bundled in ' + (Date.now() - bundleStart) + 'ms!') + }) }) // We also give notice when it is done compiling, including the // time it took. Nice to have -let server = new webpackDevServer(compiler, { +const server = new webpackDevServer(compiler, { // We need to tell Webpack to serve our bundled application // from the build path. publicPath: '/bundles/', // Configure hot replacement - hot: true, + hot: false, + liveReload: false, // The rest is terminal configurations quiet: false, @@ -47,10 +42,10 @@ let server = new webpackDevServer(compiler, { stats: { colors: true } -}); +}) // We fire up the development server and give notice in the terminal // that we are starting the initial bundle server.listen(8765, 'localhost', function () { - console.log('[Webpack] Bundling project, please wait...'); -}); + console.log('[Webpack] Bundling project, please wait...') +}) From 1ab414e8fef26d93c45a9e667b25e9ee70ad6e8a Mon Sep 17 00:00:00 2001 From: Mark McKnight Date: Thu, 26 Sep 2019 16:55:13 -0400 Subject: [PATCH 002/234] Started work on supporting file-based editing of Steps. --- .gitignore | 1 + app/controllers/ExperimentController.java | 10 ++-- app/controllers/StepsController.java | 4 +- app/models/Breadboard.java | 16 +++--- app/models/Experiment.java | 63 +++++++++++++++++++++-- app/models/ScriptBoard.java | 4 +- frontend/package-lock.json | 14 ++++- frontend/package.json | 2 + 8 files changed, 92 insertions(+), 22 deletions(-) diff --git a/.gitignore b/.gitignore index 898fc53..323ec1b 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ docs logo logs db +dev project/project project/target conf/generated.keystore diff --git a/app/controllers/ExperimentController.java b/app/controllers/ExperimentController.java index d145299..4a87b04 100644 --- a/app/controllers/ExperimentController.java +++ b/app/controllers/ExperimentController.java @@ -232,7 +232,7 @@ public static Result exportExperiment(Long experimentId){ zos.closeEntry(); // Steps - for (Step step : experiment.steps) { + for (Step step : experiment.getSteps()) { e = new ZipEntry("Steps/" + step.name.concat(".groovy")); zos.putNextEntry(e); zos.write(step.source.getBytes()); @@ -536,7 +536,7 @@ private static void importSteps(Experiment experiment, File stepsDirectory) thro String source = FileUtils.readFileToString(stepFile); step.name = stepName; step.source = source; - experiment.steps.add(step); + experiment.addStep(step); Logger.debug("Adding step: " + stepName); } else { Logger.debug("Skipping " + stepFile.getName() + " with unsupported file extension"); @@ -551,9 +551,9 @@ private static Experiment newExperiment(User user, Boolean isNewExperiment){ Step onJoin = Experiment.generateOnJoinStep(); Step onLeave = Experiment.generateOnLeaveStep(); Step init = Experiment.generateInitStep(); - experiment.steps.add(onJoin); - experiment.steps.add(onLeave); - experiment.steps.add(init); + experiment.addStep(onJoin); + experiment.addStep(onLeave); + experiment.addStep(init); } experiment.clientHtml = Experiment.defaultClientHTML(); experiment.clientGraph = Experiment.defaultClientGraph(); diff --git a/app/controllers/StepsController.java b/app/controllers/StepsController.java index 7d3f400..f6b0f9c 100644 --- a/app/controllers/StepsController.java +++ b/app/controllers/StepsController.java @@ -22,7 +22,7 @@ public static Result getSteps(Long experimentId) { ObjectNode returnJson = Json.newObject(); ArrayNode jsonSteps = returnJson.putArray("steps"); - for (Step s : experiment.steps) { + for (Step s : experiment.getSteps()) { jsonSteps.add(s.toJson()); } @@ -86,7 +86,7 @@ public static Result updateStep(Long stepId) { step.setSource(source); step.setName(name); if (isNewStep) { - experiment.steps.add(step); + experiment.addStep(step); experiment.save(); } else { step.update(); diff --git a/app/models/Breadboard.java b/app/models/Breadboard.java index 569ac0a..250a125 100644 --- a/app/models/Breadboard.java +++ b/app/models/Breadboard.java @@ -312,7 +312,7 @@ public UntypedActor create() { if (copyFrom != null) { experiment = new Experiment(copyFrom); boolean foundOnJoin = false, foundOnLeave = false; - for (Step step : experiment.steps) { + for (Step step : experiment.getSteps()) { if (Experiment.ON_JOIN_STEP_NAME.equals(step.name)) { foundOnJoin = true; } else if (Experiment.ON_LEAVE_STEP_NAME.equals(step.name)) { @@ -321,11 +321,11 @@ public UntypedActor create() { } if (!foundOnJoin) { Step onJoin = Experiment.generateOnJoinStep(); - experiment.steps.add(onJoin); + experiment.addStep(onJoin); } if (!foundOnLeave) { Step onLeave = Experiment.generateOnLeaveStep(); - experiment.steps.add(onLeave); + experiment.addStep(onLeave); } } } @@ -334,9 +334,9 @@ public UntypedActor create() { Step onJoin = Experiment.generateOnJoinStep(); Step onLeave = Experiment.generateOnLeaveStep(); Step init = Experiment.generateInitStep(); - experiment.steps.add(onJoin); - experiment.steps.add(onLeave); - experiment.steps.add(init); + experiment.addStep(onJoin); + experiment.addStep(onLeave); + experiment.addStep(init); experiment.clientHtml = Experiment.defaultClientHTML(); experiment.clientGraph = Experiment.defaultClientGraph(); } @@ -375,7 +375,7 @@ public UntypedActor create() { String source = FileUtils.readFileToString(stepFile); step.name = stepName; step.source = source; - importedExperiment.steps.add(step); + importedExperiment.addStep(step); Logger.debug("Adding step: " + stepName); } } @@ -605,7 +605,7 @@ public UntypedActor create() { "\tprintln \"" + nameVariableName + ".done\"\n" + "}\n"; - selectedExperiment.steps.add(newStep); + selectedExperiment.addStep(newStep); selectedExperiment.save(); } } else if (message instanceof DeleteStep) { diff --git a/app/models/Experiment.java b/app/models/Experiment.java index e09bc75..f492670 100644 --- a/app/models/Experiment.java +++ b/app/models/Experiment.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.UUID; @@ -38,7 +39,7 @@ public class Experiment extends Model { public String uid; @OneToMany(cascade = CascadeType.ALL) - public List steps = new ArrayList<>(); + private List steps = new ArrayList<>(); @OneToMany(cascade = CascadeType.ALL) public List content = new ArrayList<>(); @@ -71,6 +72,9 @@ public class Experiment extends Model { public static final String ON_JOIN_STEP_NAME = "OnJoinStep"; public static final String ON_LEAVE_STEP_NAME = "OnLeaveStep"; + @Transient + public boolean fileMode = true; + /* * The CSS Style for the experiment */ @@ -153,6 +157,55 @@ public Experiment(Experiment experiment) { } } + public List getSteps() { + if (fileMode) { + ArrayList returnSteps = new ArrayList<>(); + File devDirectory = new File(Play.application().path().toString() + "/dev"); + String[] extensions = {"groovy"}; + Iterator iter = FileUtils.iterateFiles(devDirectory, extensions, false); + while (iter.hasNext()) { + try { + File stepFile = iter.next(); + String stepName = stepFile.getName(); + int indexOfGroovy = stepName.indexOf(".groovy"); + if (indexOfGroovy > -1) { + stepName = stepName.substring(0, indexOfGroovy); + } + String stepContents = FileUtils.readFileToString(stepFile); + Step readStep = new Step(); + readStep.setName(stepName); + readStep.setSource(stepContents); + returnSteps.add(readStep); + } catch (IOException ioe) { + Logger.error("Error reading steps file from the dev directory, check your permissions."); + } + } + return returnSteps; + } else { + return this.steps; + } + } + + public void addStep(Step step) { + if (fileMode) { + File devDirectory = new File(Play.application().path().toString() + "/dev"); + try { + FileUtils.writeStringToFile(new File(devDirectory, step.name.concat(".groovy")), step.source); + } catch (IOException ioe) { + Logger.error("Error writing step to the dev directory, check your permissions."); + } + } else { + this.steps.add(step); + } + } + + public void setFileMode(boolean mode) { + this.fileMode = mode; + if (mode) { + // TODO: watch files here + } + } + public void export() throws IOException { File experimentDirectory = new File(Play.application().path().toString() + "/experiments/" + this.name); FileUtils.writeStringToFile(new File(experimentDirectory, "style.css"), this.style); @@ -198,7 +251,9 @@ public static String defaultClientHTML() { } else { contents = IOUtils.toString(defaultClientHtml); } - } catch(IOException e){} + } catch(IOException e){ + Logger.error("Error reading the conf/defaults/client-html.html file."); + } return contents; } @@ -213,7 +268,9 @@ public static String defaultClientGraph() { } else { contents = IOUtils.toString(defaultClientGraph); } - } catch(IOException e){} + } catch(IOException e){ + Logger.error("Error reading the conf/defaults/default-client-graph.js file."); + } return contents; } diff --git a/app/models/ScriptBoard.java b/app/models/ScriptBoard.java index d264a31..88cbcac 100644 --- a/app/models/ScriptBoard.java +++ b/app/models/ScriptBoard.java @@ -165,7 +165,7 @@ private void resetEngine(Experiment experiment) throws IOException, ScriptExcept } private void loadSteps(Experiment experiment, ThrottledWebSocketOut out) { - for (Step step : experiment.steps) { + for (Step step : experiment.getSteps()) { //should call RunStep? processScript(step.source, out, step.name); } @@ -449,7 +449,7 @@ public void run() { gameListener.start(); // Re-run the Steps - for (Step step : instance.experiment.steps) + for (Step step : instance.experiment.getSteps()) Breadboard.instances.get(breadboardMessage.user.email).tell(new Breadboard.RunStep(breadboardMessage.user, step.source, breadboardMessage.out), null); } // END if (breadboardMessage.user.selectedExperiment != null) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 3f386f3..902fa6d 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -2073,7 +2073,7 @@ "buffer-indexof": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", - "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", + "integrity": "sha1-Uvq8xqYG0aADAoAmSO9o9jnaJow=", "dev": true }, "buffer-xor": { @@ -2557,7 +2557,7 @@ "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==", + "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=", "dev": true }, "continuable-cache": { @@ -2607,6 +2607,11 @@ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", "dev": true }, + "core-js": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", + "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==" + }, "core-js-compat": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.2.1.tgz", @@ -7133,6 +7138,11 @@ } } }, + "regenerator-runtime": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", + "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==" + }, "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index fc4e689..1a678e6 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -25,11 +25,13 @@ "async-mutex": "^0.1.3", "bootstrap": "^4.3.1", "codemirror": "^5.32.0", + "core-js": "^3.2.1", "d3": "^5.9.2", "jquery": "^3.4.1", "jquery-ui": "1.12.1", "jscssp": "^0.5.0", "ng-file-upload": "^12.2.13", + "regenerator-runtime": "^0.13.3", "tinymce": "^4.1.3", "underscore": "1.8.3" }, From 1b45b27dfabf495bdf5b71a0778b688ae4aec3a1 Mon Sep 17 00:00:00 2001 From: wyattis Date: Wed, 2 Oct 2019 14:38:09 -0400 Subject: [PATCH 003/234] Basic graph layout is working in Vue within proper separation of styles. --- frontend/client/client.sass | 8 + frontend/client/client.ts | 50 +++++ frontend/client/components/Choice.vue | 20 +- frontend/client/components/Graph.vue | 15 -- frontend/client/components/PlayerChoices.vue | 41 +++- frontend/client/components/PlayerText.vue | 18 +- frontend/client/components/PlayerTimers.vue | 14 +- frontend/client/components/SVGGraph.vue | 197 +++++++++++++++++++ frontend/client/components/Timer.vue | 51 ++++- frontend/client/lib/DateTime.ts | 16 ++ frontend/client/lib/graph.ts | 151 ++++++++++++++ frontend/client/main.ts | 31 --- frontend/client/mixins/DefaultView.js | 33 ++++ frontend/client/plugins/vuetify.ts | 9 - frontend/client/types.d.ts | 20 +- frontend/client/vue-components.ts | 10 + frontend/core/breadboard.ts | 189 ++++++++++++++++-- frontend/core/breadboard.types.ts | 83 ++++++++ frontend/package-lock.json | 33 +++- frontend/package.json | 6 +- frontend/tsconfig.json | 13 +- frontend/util.ts | 15 ++ frontend/webpack/webpack.base.js | 66 ++++--- frontend/webpack/webpack.client.js | 40 +++- frontend/webpack/webpack.dev.js | 18 +- frontend/webpack/webpack.prod.js | 4 +- frontend/webpack/webpack.server.js | 10 +- 27 files changed, 1004 insertions(+), 157 deletions(-) create mode 100644 frontend/client/client.sass create mode 100644 frontend/client/client.ts delete mode 100644 frontend/client/components/Graph.vue create mode 100644 frontend/client/components/SVGGraph.vue create mode 100644 frontend/client/lib/DateTime.ts create mode 100644 frontend/client/lib/graph.ts delete mode 100644 frontend/client/main.ts create mode 100644 frontend/client/mixins/DefaultView.js delete mode 100644 frontend/client/plugins/vuetify.ts create mode 100644 frontend/client/vue-components.ts create mode 100644 frontend/core/breadboard.types.ts create mode 100644 frontend/util.ts diff --git a/frontend/client/client.sass b/frontend/client/client.sass new file mode 100644 index 0000000..2c07bc9 --- /dev/null +++ b/frontend/client/client.sass @@ -0,0 +1,8 @@ +.h-full + height: 100% +.h-screen + height: 100vh +.w-50 + width: 50% +.w-full + width: 100% diff --git a/frontend/client/client.ts b/frontend/client/client.ts new file mode 100644 index 0000000..b39c6e2 --- /dev/null +++ b/frontend/client/client.ts @@ -0,0 +1,50 @@ +import { BreadboardConfig } from '../core/breadboard.types' +import './client.sass' + +const Breadboard = window.Breadboard + +async function client () { + let config: BreadboardConfig + try { + config = await Breadboard.loadConfig() + } catch (err) { + console.error('Breadboard: Unable to load Breadboard') + throw err + } + + try { + await Breadboard.addScriptFromString(config.clientGraph) + } catch (err) { + console.error('Breadboard: Unable to run client-graph.js') + throw err + } + + // TODO: Move this to client graph + await Breadboard.loadVueDependencies({ + useDev: true + }) + await Breadboard.createDefaultVue(` + + + + + + + + + + + + + + `) + +} + +client() diff --git a/frontend/client/components/Choice.vue b/frontend/client/components/Choice.vue index 004a9fd..9045fb1 100644 --- a/frontend/client/components/Choice.vue +++ b/frontend/client/components/Choice.vue @@ -1,15 +1,23 @@ - - diff --git a/frontend/client/components/Graph.vue b/frontend/client/components/Graph.vue deleted file mode 100644 index e483b4a..0000000 --- a/frontend/client/components/Graph.vue +++ /dev/null @@ -1,15 +0,0 @@ - - - - - diff --git a/frontend/client/components/PlayerChoices.vue b/frontend/client/components/PlayerChoices.vue index a4932fd..ee9019b 100644 --- a/frontend/client/components/PlayerChoices.vue +++ b/frontend/client/components/PlayerChoices.vue @@ -1,15 +1,44 @@ - - diff --git a/frontend/client/components/PlayerText.vue b/frontend/client/components/PlayerText.vue index 9a9ff15..d4ae909 100644 --- a/frontend/client/components/PlayerText.vue +++ b/frontend/client/components/PlayerText.vue @@ -1,15 +1,21 @@ - - diff --git a/frontend/client/components/PlayerTimers.vue b/frontend/client/components/PlayerTimers.vue index 89713e3..f74d2dc 100644 --- a/frontend/client/components/PlayerTimers.vue +++ b/frontend/client/components/PlayerTimers.vue @@ -1,12 +1,22 @@ diff --git a/frontend/client/components/SVGGraph.vue b/frontend/client/components/SVGGraph.vue new file mode 100644 index 0000000..b4b06d3 --- /dev/null +++ b/frontend/client/components/SVGGraph.vue @@ -0,0 +1,197 @@ + + + + + diff --git a/frontend/client/components/Timer.vue b/frontend/client/components/Timer.vue index 157ba06..f2d81d0 100644 --- a/frontend/client/components/Timer.vue +++ b/frontend/client/components/Timer.vue @@ -1,12 +1,59 @@ diff --git a/frontend/client/lib/DateTime.ts b/frontend/client/lib/DateTime.ts new file mode 100644 index 0000000..7b8a867 --- /dev/null +++ b/frontend/client/lib/DateTime.ts @@ -0,0 +1,16 @@ +export function toHHMMSS (str: string): string { + let ms_num = parseInt(str, 10) // don't forget the second parm + if (ms_num < 0) return '00:00' + + let sec_num = Math.round(ms_num / 1000) // don't forget the second parm + let hours: any = Math.floor(sec_num / 3600) + let minutes: any = Math.floor((sec_num - (hours * 3600)) / 60) + let seconds: any = sec_num - (hours * 3600) - (minutes * 60) + + if (hours < 10) {hours = '0' + hours} + if (minutes < 10) {minutes = '0' + minutes} + if (seconds < 10) {seconds = '0' + seconds} + let time = minutes + ':' + seconds + if (hours > 0) time = hours + ':' + time + return time +} diff --git a/frontend/client/lib/graph.ts b/frontend/client/lib/graph.ts new file mode 100644 index 0000000..89e33d4 --- /dev/null +++ b/frontend/client/lib/graph.ts @@ -0,0 +1,151 @@ +import { Emitter } from 'goodish' +import { BreadboardClass } from '../../core/breadboard' +import { BreadboardGraphData, Edge, GraphEvents, LinkData, Node, NodeData } from '../../core/breadboard.types' + +export class Graph extends Emitter implements GraphEvents { + + public edges: Edge[] = [] + private edgeIdMap: Map = new Map() + public nodes: Node[] = [] + private nodeIdMap: Map = new Map() + private breadboard!: BreadboardClass + + constructor () { + super() + this.handleGraphChanges = this.handleGraphChanges.bind(this) + } + + attachToBreadboard (breadboard: BreadboardClass) { + this.breadboard = breadboard + breadboard.on('graph', this.handleGraphChanges) + } + + releaseFromBreadboard () { + if (this.breadboard) { + this.breadboard.off('graph', this.handleGraphChanges) + } + } + + addNode (data: NodeData) { + const node = { + id: data.id, + data, + x: 0, + y: 0, + } + this.nodes.push(node) + this.nodeIdMap.set(node.id, node) + this.emit('addNode', node) + } + + addEdge (data: LinkData) { + const source = this.nodeIdMap.get(data.sourceId) + const target = this.nodeIdMap.get(data.targetId) + if (source && target) { + // delete data.source + // delete data.target + const edge = { id: data.id, source, target, data, index: this.edges.length - 1 } + this.edges.push(edge) + this.edgeIdMap.set(data.id, edge) + this.emit('addEdge', edge) + } + } + + clearEdges () { + this.edges = [] + this.edgeIdMap.clear() + this.emit('clearEdges') + } + + clearNodes () { + this.nodes = [] + this.nodeIdMap.clear() + this.emit('clearNodes') + } + + removeEdge (edge: Edge): void + removeEdge (edgeId: number): void + removeEdge (edgeOrId: Edge | number): void { + const edgeId = typeof edgeOrId === 'object' ? edgeOrId.id : edgeOrId + const index = this.edges.findIndex(e => e.id === edgeId) + if (index !== -1) { + const edge = this.edges.splice(index, 1)[0] + this.edgeIdMap.delete(edgeId) + this.emit('removeEdge', edge) + } + } + + removeNode (node: Node): void + removeNode (nodeId: string): void + removeNode (nodeOrId: Node | string): void { + const nodeId = typeof nodeOrId === 'object' ? nodeOrId.id : nodeOrId + const index = this.nodes.findIndex(n => n.id === nodeId) + if (index !== -1) { + const node = this.nodes.splice(index, 1)[0] + this.nodeIdMap.delete(nodeId) + this.emit('removeNode', node) + } + } + + /** + * Diff algorithm: + * - Check if all nodes were removed + * - Check if all edges were removed + * - Check for removed nodes + * - Check if any nodes need updated + * - Check for removed edges + * - Check if any edges need updated + * - Check for new nodes + * - Check for new edges + */ + handleGraphChanges (data: BreadboardGraphData) { + if (!data.nodes || !data.nodes.length) { + this.clearNodes() + this.clearEdges() + return + } + if (!data.links || !data.links.length) { + this.clearEdges() + } + + for (const node of this.nodes) { + // Check for old nodes + const existingNode = data.nodes.find(n => n.id === node.id) + if (!existingNode) { + this.removeNode(node) + } else if (existingNode !== node.data) { + // TODO: update the existing node + node.data = existingNode + // this.emit('updateNode', node) + } + } + + for (const edge of this.edges) { + const existingEdge = data.links.find(l => l.id === edge.id) + if (!existingEdge) { + this.removeEdge(edge) + } else if (existingEdge !== edge.data) { + // TODO: Update the existing edge + // this.emit('updateEdge', edge) + } + } + + for (const node of data.nodes) { + const nodeAlreadyExists = this.nodeIdMap.has(node.id) + if (!nodeAlreadyExists) { + this.addNode(node) + } + } + + for (const link of data.links) { + const edgeAlreadyExists = this.edgeIdMap.has(link.id) + if (!edgeAlreadyExists) { + link.sourceId = data.nodes[link.source].id + link.targetId = data.nodes[link.target].id + this.addEdge(link) + } + } + + } + +} diff --git a/frontend/client/main.ts b/frontend/client/main.ts deleted file mode 100644 index f62e586..0000000 --- a/frontend/client/main.ts +++ /dev/null @@ -1,31 +0,0 @@ -import Vue from 'vue' -import vuetify from '@/plugins/vuetify' -import { Breadboard } from './types' - -async function main () { - let config - try { - config = await Breadboard.loadConfig() - } catch (err) { - console.error('Breadboard: Unable to load Breadboard') - throw err - } - - try { - await Breadboard.addScriptFromString(config.clientGraph) - } catch (err) { - console.error('Breadboard: Unable to run client-graph.js') - throw err - } - - // TODO: Move this to client graph instead - Breadboard.loadConfig().then(config => { - new Vue({ - vuetify, - // template: config.clientHtml - template: `` - }).$mount('#app') - }) -} - -main() diff --git a/frontend/client/mixins/DefaultView.js b/frontend/client/mixins/DefaultView.js new file mode 100644 index 0000000..672ee6c --- /dev/null +++ b/frontend/client/mixins/DefaultView.js @@ -0,0 +1,33 @@ +import { Graph } from '../lib/graph' + +export default { + data () { + return { + graph: new Graph(), + player: { + text: 'Loading...', + choices: [] + }, + config: null + } + }, + async created () { + const [_, __, config] = await Promise.all([window.Breadboard.connect(), window.Breadboard.login(), window.Breadboard.loadConfig()]) + this.config = config + window.Breadboard.on('data', console.log) + window.Breadboard.on('style', contents => { + if (contents.length) { + window.Breadboard.addStyleFromString(contents) + } + }) + window.Breadboard.on('player', player => { + // TODO: First check if anything has changed before updating + this.player = player + this.player.id = this.config.clientId + }) + this.graph.attachToBreadboard(window.Breadboard) + }, + beforeDestroy () { + this.graph.releaseFromBreadboard() + } +} diff --git a/frontend/client/plugins/vuetify.ts b/frontend/client/plugins/vuetify.ts deleted file mode 100644 index d3848b1..0000000 --- a/frontend/client/plugins/vuetify.ts +++ /dev/null @@ -1,9 +0,0 @@ -import Vue from 'vue' -import Vuetify from 'vuetify' -import 'vuetify/dist/vuetify.min.css' - -Vue.use(Vuetify) - -const opts = {} - -export default new Vuetify(opts) diff --git a/frontend/client/types.d.ts b/frontend/client/types.d.ts index 7575c74..e0045a8 100644 --- a/frontend/client/types.d.ts +++ b/frontend/client/types.d.ts @@ -1,3 +1,21 @@ import { BreadboardClass } from '../core/breadboard' +import { Vuetify } from 'vuetify' +import { VueConstructor } from 'vue/types/vue' + +declare global { + interface Window { + Breadboard: BreadboardClass + Vuetify: Vuetify + Vue: VueConstructor + BreadboardVueComponents: { name: string, component: VueConstructor }[] + } +} + +export interface Exports extends SimpleMap { + default: T +} + +export type SimpleMap = { + [key: string]: T +} -declare const Breadboard: BreadboardClass diff --git a/frontend/client/vue-components.ts b/frontend/client/vue-components.ts new file mode 100644 index 0000000..7540f9e --- /dev/null +++ b/frontend/client/vue-components.ts @@ -0,0 +1,10 @@ +import { requireAll } from '../util' +import { Exports, SimpleMap } from './types' +import { VueConstructor } from 'vue/types/vue' + +const components: SimpleMap> = requireAll(require.context('./components', false, /\.vue$/)) + +window.BreadboardVueComponents = Object.keys(components).map(filename => ({ + name: filename.replace('.vue', '').replace('./', ''), + component: components[filename].default +})) diff --git a/frontend/core/breadboard.ts b/frontend/core/breadboard.ts index 6931725..649d5d7 100644 --- a/frontend/core/breadboard.ts +++ b/frontend/core/breadboard.ts @@ -2,38 +2,38 @@ import 'core-js' import 'regenerator-runtime' import { http } from './http' import { Mutex } from 'async-mutex' +import { Vue as VueType } from 'vue/types/vue' +import { Emitter } from 'goodish' +// @ts-ignore +import DefaultView from '../client/mixins/DefaultView' +import { BreadboardConfig, BreadboardMessages, VueLoadOpts } from './breadboard.types' +import { SimpleMap } from '../client/types' -type BreadboardState = { - [key: string]: string | number, - connectSocket: string, - clientGraph: string, - clientHtml: string -} - -export class BreadboardClass { +export class BreadboardClass extends Emitter implements BreadboardMessages { private socket!: WebSocket - private state: BreadboardState + private isConnected: boolean = false + private config!: BreadboardConfig private socketMutex = new Mutex() - private stateMutex = new Mutex() + private configMutex = new Mutex() /** * Load the client config. * @returns {Promise} */ - async loadConfig (): Promise { - const release = await this.stateMutex.acquire() - if (this.state) { + async loadConfig (): Promise { + const release = await this.configMutex.acquire() + if (this.config) { release() - return this.state + return this.config } try { - const res = await http.get('state') - this.state = await res.json() - } finally { + const res = await http.get('state') + this.config = await res.json() + } finally { release() } - return this.state + return this.config } /** @@ -42,19 +42,75 @@ export class BreadboardClass { */ async connect (): Promise { const release = await this.socketMutex.acquire() - if (this.socket) { + if (this.isConnected) { release() return this.socket } try { const config = await this.loadConfig() this.socket = new WebSocket(config.connectSocket) + this.isConnected = true + this.attachParser() } finally { release() } return this.socket } + /** + * Disconnect the websocket + */ + disconnect () { + this.socket.close() + this.isConnected = false + this.removeListeners() + } + + /** + * Send data to breadboard server + * @param action + * @param data + */ + send (action: string, data: SimpleMap) { + if (!this.isConnected) throw new Error('Unable to send data when connection is closed') + const d = Object.assign(data, { + action + }) + this.socket.send(JSON.stringify(d)) + } + + /** + * Login method + */ + async login () { + const config = await this.loadConfig() + return new Promise(async resolve => { + await this.connect() + const sendLogin = () => { + this.socket.send(JSON.stringify({ + action: 'LogIn', + clientId: config.clientId, + referer: config.referer, + connection: config.connection, + accept: config.accept, + acceptLanguage: config.acceptLanguage, + acceptEncoding: config.acceptEncoding, + userAgent: config.userAgent, + host: config.host, + ipAddress: config.ipAddress, + requestURI: config.requestURI + })) + resolve() + } + if (this.socket.readyState === WebSocket.OPEN) { + sendLogin() + } else { + this.socket.addEventListener('open', sendLogin, { once: true }) + } + + }) + } + /** * Load a script from a url. * @param src @@ -64,12 +120,16 @@ export class BreadboardClass { return new Promise((resolve, reject) => { const script = document.createElement('script') script.src = src - script.onload = () => resolve() + script.onload = () => setTimeout(resolve) script.onerror = reject document.body.appendChild(script) }) } + /** + * Load a script from text + * @param contents + */ addScriptFromString (contents: string): Promise { return new Promise((resolve, reject) => { try { @@ -82,7 +142,94 @@ export class BreadboardClass { }) } + /** + * Inject styles from a string + * @param contents + */ + addStyleFromString (contents: string): Promise { + return new Promise(resolve => { + const style = document.createElement('style') + const text = document.createTextNode(contents) + style.appendChild(text) + document.body.appendChild(style) + }) + } + + /** + * Inject CSS from a url using a "link" node + * @param href + */ + addStyleFromURL (href: string, type = 'text/css'): Promise { + return new Promise((resolve, reject) => { + const link = document.createElement('link') + link.href = href + link.rel = 'stylesheet' + link.type = type + link.onload = () => resolve() + link.onerror = reject + document.head.appendChild(link) + }) + } + + /** + * Load Vue, Vuetify and Breadboard component dependencies + * @param opts + */ + async loadVueDependencies (opts: VueLoadOpts = {}) { + opts = Object.assign({ + vueVersion: '2.6.10', + vuetifyVersion: '2.0.19', + useDev: false + }, opts) + await this.addScriptFromURL(`https://cdnjs.cloudflare.com/ajax/libs/vue/${opts.vueVersion}/vue.${opts.useDev ? 'common.dev.' : ''}js`) + await Promise.all([ + this.addScriptFromURL(`https://cdnjs.cloudflare.com/ajax/libs/vuetify/${opts.vuetifyVersion}/vuetify.min.js`), + this.addScriptFromURL('/bundles/vue-components.js'), + this.addStyleFromURL(`https://cdnjs.cloudflare.com/ajax/libs/vuetify/${opts.vuetifyVersion}/vuetify.min.css`), + this.addStyleFromURL('/bundles/client.css') + ]) + + const Vue = window.Vue + const Vuetify = window.Vuetify + + // Register Vuetify components + Vue.use(Vuetify) + + // Register all Breadboard components globally + for (const c of window.BreadboardVueComponents) { + Vue.component(c.name, c.component) + } + } + + /** + * Create default Vue instance + * @param template + */ + async createDefaultVue (template: string,): Promise { + const Vue = window.Vue + const Vuetify = window.Vuetify + return new Vue({ + vuetify: new Vuetify(), + mixins: [DefaultView], + template: template + }).$mount('#app') + } + + /** + * Handle parsing breadboard socket events + */ + private attachParser () { + this.socket.addEventListener('message', ev => { + this.emit('message', ev) + const data = JSON.parse(ev.data) + this.emit('data', data) + for (const key of ['graph', 'player', 'style']) { + if (data[key]) { + this.emit(key, data[key]) + } + } + }) + } } -// @ts-ignore export globally window.Breadboard = new BreadboardClass() diff --git a/frontend/core/breadboard.types.ts b/frontend/core/breadboard.types.ts new file mode 100644 index 0000000..a9b91e0 --- /dev/null +++ b/frontend/core/breadboard.types.ts @@ -0,0 +1,83 @@ +import { SimpleMap } from '../client/types' + +export interface BreadboardConfig extends SimpleMap { + connectSocket: string, + clientGraph: string, + clientHtml: string +} + +export interface VueLoadOpts { + vueVersion?: string + vuetifyVersion?: string + useDev?: boolean +} + +export interface PlayerChoice { + name: string + uid: string +} + +export interface PlayerTimer { + id: string + duration: number + appearance: 'success' | 'danger' | 'warn' | 'info' + elapsed: number + direction: 'down' | 'up' + type: 'default' | 'currency' | 'percent' + currencyAmount: number + timerText: string +} + +export interface PlayerData extends SimpleMap { + text: string + choices: PlayerChoice[] + timers?: PlayerTimer[] +} + +export interface BreadboardMessages { + on (event: 'graph', callback: (d: BreadboardGraphData) => any, context?: object): void + on (event: 'message', callback: (ev: Event) => any, context?: object): void + on (event: 'player', callback: (d: PlayerData) => any, context?: object): void + on (event: 'style', callback: (d: string) => any, context?: object): void + on (event: 'data', callback: (d: object) => any, context?: object): void +} + +export interface Edge { + id: number + source: Node + target: Node + data: SimpleMap +} + +export interface Node { + id: string + x: number + y: number + data: SimpleMap +} + +export interface NodeData extends SimpleMap { + ai: number + id: string +} + +export interface LinkData extends SimpleMap { + id: number + source: number + target: number + name: string +} + +export type BreadboardGraphData = { + nodes: NodeData[] + links: LinkData[] +} + +export interface GraphEvents { + on (event: 'addNode', cb: (node: Node) => void, context?: object): void + on (event: 'removeNode', cb: (node: Node) => void, context?: object): void + on (event: 'addEdge', cb: (edge: Edge) => void, context?: object): void + on (event: 'removeEdge', cb: (edge: Edge) => void, context?: object): void + on (event: 'updateNode', cb: (node: Node) => void, context?: object): void + on (event: 'updateEdge', cb: (edge: Edge) => void, context?: object): void +} diff --git a/frontend/package-lock.json b/frontend/package-lock.json index dafdefb..ac0d2cf 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1155,6 +1155,12 @@ "integrity": "sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w==", "dev": true }, + "@types/webpack-env": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.14.0.tgz", + "integrity": "sha512-Fv+0gYJzE/czLoRKq+gnXWr4yBpPM3tO3C8pDLFwqVKlMICQUq5OsxwwFZYDaVr7+L6mgNDp16iOcJHEz3J5RQ==", + "dev": true + }, "@uirouter/angularjs": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@uirouter/angularjs/-/angularjs-1.0.11.tgz", @@ -1712,9 +1718,9 @@ "dev": true }, "async-mutex": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.1.3.tgz", - "integrity": "sha1-Cq0hEjaXlas/F+M3RFVtLs9UdWY=" + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.1.4.tgz", + "integrity": "sha512-zVWTmAnxxHaeB2B1te84oecI8zTDJ/8G49aVBblRX6be0oq6pAybNcUSxwfgVOmOjSCvN4aYZAqwtyNI8e1YGw==" }, "asynckit": { "version": "0.4.0", @@ -3171,6 +3177,12 @@ "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", "dev": true }, + "de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=", + "dev": true + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -4887,6 +4899,11 @@ "minimatch": "~3.0.2" } }, + "goodish": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/goodish/-/goodish-0.0.7.tgz", + "integrity": "sha512-9hZIYcljbUAP1GyHbdUZeUYfXYMaQ5redkjpLv6BpMRpscVK7T0wNfl9csbo223Mva2/UCuC/q5fw+b0RBmkdg==" + }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", @@ -9346,6 +9363,16 @@ "loader-utils": "^1.0.2" } }, + "vue-template-compiler": { + "version": "2.6.10", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.10.tgz", + "integrity": "sha512-jVZkw4/I/HT5ZMvRnhv78okGusqe0+qH2A0Em0Cp8aq78+NK9TII263CDVz2QXZsIT+yyV/gZc/j/vlwa+Epyg==", + "dev": true, + "requires": { + "de-indent": "^1.0.2", + "he": "^1.1.0" + } + }, "vue-template-es2015-compiler": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index e9c2fa6..56e2867 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -22,10 +22,11 @@ "angular-ui-codemirror": "^0.3.0", "angular-ui-router": "^0.4.3", "angular-ui-utils": "^0.1.1", - "async-mutex": "^0.1.3", + "async-mutex": "^0.1.4", "bootstrap": "^4.3.1", "codemirror": "^5.32.0", "d3": "^5.9.2", + "goodish": "0.0.7", "jquery": "^3.4.1", "jquery-ui": "1.12.1", "jscssp": "^0.5.0", @@ -37,6 +38,8 @@ "@babel/core": "^7.6.0", "@babel/polyfill": "^7.6.0", "@babel/preset-env": "^7.6.0", + "@types/webpack-env": "^1.14.0", + "@vue/component-compiler-utils": "^3.0.0", "ajv": "^6.10.0", "babel-loader": "^8.0.6", "css-loader": "^2.1.1", @@ -53,6 +56,7 @@ "style-loader": "^0.19.1", "vue": "^2.6.10", "vue-loader": "^15.7.1", + "vue-template-compiler": "^2.6.10", "vuetify": "^2.0.19", "webpack": "^4.0.0", "webpack-cli": "^3.3.9", diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 55c5692..bae7dac 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -8,11 +8,13 @@ "esModuleInterop": true, "allowSyntheticDefaultImports": true, "sourceMap": true, + "strict": true, "baseUrl": ".", + "typeRoots": [ + "client/**/*.d.ts" + ], "types": [ "webpack-env", - "mocha", - "chai", "vuetify" ], "lib": [ @@ -22,10 +24,7 @@ ] }, "include": [ - "src/**/*", - "src/**/*" - ], - "exclude": [ - "node_modules" + "client/**/*", + "core/**/*" ] } diff --git a/frontend/util.ts b/frontend/util.ts new file mode 100644 index 0000000..f01aa9f --- /dev/null +++ b/frontend/util.ts @@ -0,0 +1,15 @@ +import RequireContext = __WebpackModuleApi.RequireContext +import { Exports, SimpleMap } from './client/types' + +export function requireAll (r: RequireContext) { + const o: {[key: string]: Exports} = {} + for (let fileName of r.keys()) { + o[fileName] = r(fileName) + } + return o +} + +export function requireAllModules (r: RequireContext): T[] { + const modules: SimpleMap> = requireAll(r) + return Object.values(modules).map(m => m.default) +} diff --git a/frontend/webpack/webpack.base.js b/frontend/webpack/webpack.base.js index 2114a37..1cce36f 100644 --- a/frontend/webpack/webpack.base.js +++ b/frontend/webpack/webpack.base.js @@ -1,7 +1,8 @@ 'use strict' const webpack = require('webpack') const path = require('path') -console.log(__dirname) +const VueLoaderPlugin = require('vue-loader/lib/plugin') +const MiniCssExtractPlugin = require('mini-css-extract-plugin') const buildPath = path.resolve(__dirname, '../../public/bundles/') /** @@ -14,10 +15,38 @@ module.exports = { }, module: { rules: [{ + test: /\.vue$/, + loader: 'vue-loader' + }, { + test: /\.(sass|scss)$/, + use: [MiniCssExtractPlugin.loader, + 'css-loader?url=false', + { + loader: 'sass-loader', + options: { + implementation: require('sass'), + fiber: require('fibers'), + indentedSyntax: true + } + }], + exclude: /node_modules/, + }, { test: /\.css$/, use: ['style-loader','css-loader?url=false'], - // exclude: /node_modules/, + exclude: /node_modules/, }, { + test: /\.tsx?$/, + use: [{ + loader: 'ts-loader', + options: { + appendTsSuffixTo: [/\.vue$/] + }, + }], + exclude: { + include: /node_modules/, + exclude: /goodish/ + } + }, { test: /\.js$/, use: { loader: 'babel-loader', @@ -25,28 +54,10 @@ module.exports = { presets: ['@babel/preset-env'] } }, - exclude: /node_modules/, - }, { - test: /\.tsx?$/, - loader: 'ts-loader', - exclude: /node_modules/, - options: { - appendTsSuffixTo: [/\.vue$/] + exclude: { + include: /node_modules/, + exclude: /goodish/ } - }, { - test: /\.vue$/, - use: 'vue-loader' - }, { - test: /\.(sass|scss)$/, - use: ['vue-style-loader', 'css-loader?url=false', { - loader: 'sass-loader', - options: { - implementation: require('sass'), - fiber: require('fibers'), - indentedSyntax: true - } - }], - exclude: /node_modules/, }, { test: /\.html$/, use: ['ngtemplate-loader?relativeTo=frontend&prefix=files', 'html-loader'], @@ -67,10 +78,17 @@ module.exports = { resolve: { extensions: ['.js','.json','.css','.html', '.jsx', '.ts', '.tsx', '.vue'] }, + externals: { + vue: 'Vue' + }, plugins: [ new webpack.ContextReplacementPlugin( /angular(\\|\/)core(\\|\/)@angular/, path.resolve(__dirname, './design') - ) + ), + new VueLoaderPlugin(), + new MiniCssExtractPlugin({ + filename: '[name].css', + }), ] } diff --git a/frontend/webpack/webpack.client.js b/frontend/webpack/webpack.client.js index 6a5b7b8..0b13556 100644 --- a/frontend/webpack/webpack.client.js +++ b/frontend/webpack/webpack.client.js @@ -1,11 +1,41 @@ const merge = require('webpack-merge') -const config = require('./webpack.base.js'); +const config = require('./webpack.base.js') + +function recursiveIssuer(m) { + if (m.issuer) { + return recursiveIssuer(m.issuer) + } else if (m.name) { + return m.name + } else { + return false + } +} + +const cacheGroups = ['client', 'vue-components', 'breadboard', 'design'].reduce((map, entry) => { + map[entry + 'Styles'] = { + name: entry, + test: (m, c) => m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry, + chunks: 'all', + enforce: false + } + return map +}, {}) + module.exports = merge(Object.create(config), { - entry: ['./design/client.js'], + entry: { + client: './client/client.ts', + 'vue-components': './client/vue-components.ts', + breadboard: './core/breadboard.ts', + design: './design/design.js' + }, output: { path: config.output.path, publicPath: config.output.publicPath, - filename: 'client.js', - sourceMapFilename: 'client.map' - } + filename: '[name].js' + }, + optimization: { + splitChunks: { + cacheGroups: cacheGroups + } + }, }) diff --git a/frontend/webpack/webpack.dev.js b/frontend/webpack/webpack.dev.js index 9c39e07..a34783c 100644 --- a/frontend/webpack/webpack.dev.js +++ b/frontend/webpack/webpack.dev.js @@ -1,14 +1,8 @@ -const webpack = require('webpack') - -const config = require('./webpack.base.js') +const clientConfig = require('./webpack.client') -config.mode = 'development' -config.devtool = 'source-map' -config.plugins = [ - // new webpack.HotModuleReplacementPlugin() -] +clientConfig.mode = 'development' +clientConfig.devtool = 'source-map' -const clientConfig = require('./webpack.client') -const designConfig = require('./webpack.design') -const coreConfig = require('./webpack.core') -module.exports = [clientConfig, designConfig, coreConfig] +// const designConfig = require('./webpack.design') +// const coreConfig = require('./webpack.core') +module.exports = [clientConfig] diff --git a/frontend/webpack/webpack.prod.js b/frontend/webpack/webpack.prod.js index aa199cc..35808cd 100644 --- a/frontend/webpack/webpack.prod.js +++ b/frontend/webpack/webpack.prod.js @@ -1,7 +1,5 @@ -const designConfig = require('./webpack.design') const clientConfig = require('./webpack.client') -const coreConfig = require('./webpack.core') // TODO: add minification and prod stuff for client here -module.exports = [coreConfig, clientConfig, designConfig]; +module.exports = [clientConfig]; diff --git a/frontend/webpack/webpack.server.js b/frontend/webpack/webpack.server.js index fd9ab73..609562b 100644 --- a/frontend/webpack/webpack.server.js +++ b/frontend/webpack/webpack.server.js @@ -6,6 +6,8 @@ const webpackConfig = require('./webpack.dev.js') // Notify about the path where the server is running console.log('[Webpack] Server running at location: ' + __dirname) +const PORT = 8765 + // First we fire up Webpack an pass in the configuration file const compiler = webpack(webpackConfig) @@ -31,10 +33,12 @@ const server = new webpackDevServer(compiler, { // We need to tell Webpack to serve our bundled application // from the build path. publicPath: '/bundles/', + // sockHost: `http://localhost`, + sockPort: PORT, // Configure hot replacement - hot: false, - liveReload: false, + // hot: false, + // liveReload: false, // The rest is terminal configurations quiet: false, @@ -46,6 +50,6 @@ const server = new webpackDevServer(compiler, { // We fire up the development server and give notice in the terminal // that we are starting the initial bundle -server.listen(8765, 'localhost', function () { +server.listen(PORT, 'localhost', function () { console.log('[Webpack] Bundling project, please wait...') }) From 223242cf7bc656402e7dcc793109ca8f8ac9d6ff Mon Sep 17 00:00:00 2001 From: wyattis Date: Fri, 4 Oct 2019 16:02:38 -0400 Subject: [PATCH 004/234] All basic client functionality is working. Notably, named slots in the graph are simple to use. --- CONTRIBUTING.md | 16 ++ README.md | 3 + app/views/client.scala.html | 15 +- conf/application-dev.conf | 6 +- frontend/client/client.ts | 13 +- frontend/client/components/PlayerChoices.vue | 2 +- frontend/client/components/SVGGraph.vue | 163 +++++++++++------- frontend/client/lib/graph.ts | 107 +++++++----- frontend/client/mixins/DefaultView.js | 3 +- frontend/core/breadboard.types.ts | 8 +- frontend/design/content/content.controller.js | 2 +- frontend/design/design/controllers.js | 3 +- frontend/design/design/design.sass | 2 +- frontend/design/design/routes.js | 3 +- frontend/package-lock.json | 60 +++---- frontend/package.json | 2 +- frontend/tsconfig.json | 1 + frontend/webpack/webpack.base.js | 38 ++-- frontend/webpack/webpack.client.js | 4 +- frontend/webpack/webpack.prod.js | 3 +- frontend/webpack/webpack.server.js | 8 +- public/templates/breadboard.html | 4 +- 22 files changed, 282 insertions(+), 184 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..3abcbc1 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,16 @@ +# Contributing +There are many different ways to contribute to the Breadboard open-source project. We welcome issues, code, documentation +and examples. + +## Development + +### Environment setup +Breadboard works with Java 7+. Make sure this SDK is installed before starting development. + +- `cd frontend` +- `npm install` + +#### Windows + +From a terminal run `sbt "run -Dconfig.file=conf/application-dev.conf"`. This will start a dev server which will +automatically rebuild the frontend files whenever a file changes. diff --git a/README.md b/README.md index a0c36fd..2b38746 100644 --- a/README.md +++ b/README.md @@ -27,3 +27,6 @@ breadboard is built using: * [CodeMirror](https://codemirror.net/) Also [Apache Commons](https://commons.apache.org/), [imgscalr](https://github.com/thebuzzmedia/imgscalr), [JUNG](http://jung.sourceforge.net/), [jQuery](https://jquery.com/), [Modernizr](https://modernizr.com/), [Underscore](http://underscorejs.org/), and [Bootstrap](http://getbootstrap.com/). + +### Contributing +See the [contributing guide](CONTRIBUTING.md) diff --git a/app/views/client.scala.html b/app/views/client.scala.html index 134d01a..54928fc 100644 --- a/app/views/client.scala.html +++ b/app/views/client.scala.html @@ -5,19 +5,14 @@ breadboard: Client - - - - - + +
Loading... - +
- + - - - \ No newline at end of file + diff --git a/conf/application-dev.conf b/conf/application-dev.conf index e3a2583..7957753 100644 --- a/conf/application-dev.conf +++ b/conf/application-dev.conf @@ -8,15 +8,15 @@ breadboard.amtFrameHeight=600 # How frequently, in milliseconds, to send updates to the client # If 0, or omitted, default to v2.2 event based updates -breadboard.clientUpdateRate=500 +breadboard.clientUpdateRate=1500 # DEV http #breadboard.rootUrl="http://localhost:9000" #breadboard.wsUrl="ws://localhost:9000/connect" # DEV https -breadboard.rootUrl="https://localhost:9443" -breadboard.wsUrl="wss://localhost:9443/connect" +breadboard.rootUrl="http://localhost:9000" +breadboard.wsUrl="ws://localhost:9000/connect" # PROD #breadboard.rootUrl="https://[your server here]:9443" diff --git a/frontend/client/client.ts b/frontend/client/client.ts index b39c6e2..e96c161 100644 --- a/frontend/client/client.ts +++ b/frontend/client/client.ts @@ -30,8 +30,17 @@ async function client () { :player="player" :graph="graph" :nodeBorderWidth="node => node.isEgo ? 2 : 1" - :nodeFill="node => node.isEgo ? 'blue' : 'red'" - :nodeRadius="node => node.isEgo ? 50 : 30"> + :nodeFill="node => node.isEgo ? 'blue' : 'lightgrey'" + :nodeRadius="node => node.data.score * 2 || 10"> + + diff --git a/frontend/client/components/PlayerChoices.vue b/frontend/client/components/PlayerChoices.vue index ee9019b..b1fe8ca 100644 --- a/frontend/client/components/PlayerChoices.vue +++ b/frontend/client/components/PlayerChoices.vue @@ -30,7 +30,7 @@ }, updated () { this.choicesAreEnabled = true - console.log('player choices updated') + // console.log('player choices updated') }, methods: { submit (choice: PlayerChoice) { diff --git a/frontend/client/components/SVGGraph.vue b/frontend/client/components/SVGGraph.vue index b4b06d3..3cd7dbb 100644 --- a/frontend/client/components/SVGGraph.vue +++ b/frontend/client/components/SVGGraph.vue @@ -4,32 +4,40 @@ + v-for="edge in graph.edges" + v-bind:edge="edge"> - + + + - - - + + + + + @@ -61,18 +69,17 @@ type: Object as () => Graph, required: true }, - layout: { - type: Object as () => LayoutOptions, + layout: >{ + type: Object, default: () => ({ - chargeStrength: -10000, - linkStrength: 10, - centerRepel: 10, - friction: 0.8 - } as LayoutOptions) + linkDistance: 100, + chargeStrength: -500, + centerRepel: 500 + }) }, nodeStroke: >>{ type: [String, Function], - default: 'lightblue' + default: 'black' }, nodeStrokeWidth: >>{ type: [Number, Function], @@ -110,7 +117,8 @@ data () { return { width: 600, - height: 600 + height: 600, + listenerIds: {} as { [key: string]: number } } }, created () { @@ -118,72 +126,105 @@ }, methods: { setupSimulation () { - console.log('nodes', this.graph.nodes.length) - const simulation = forceSimulation(this.graph.nodes) - // @ts-ignore - this.simulation = simulation - this.updateForces() - - this.graph.on('addNode', (node: Node) => { - // @ts-ignore - node.isEgo = node.id === this.player.id - console.log('addNode', node) + this.restartSimulation() + this.graph.on('addNodes', (nodes: Node[]) => { + for (const node of nodes) { + // @ts-ignore + node.isEgo = node.id === this.player.id + if (node.id === this.player.id) { + // @ts-ignore + node.fx = this.center.x; node.fy = this.center.y + } + } + console.log('addNodes') this.restartSimulation() + console.log('graph', JSON.parse(JSON.stringify(this.graph))) }) - this.graph.on('addEdge', () => { - console.log('addEdge') + this.graph.on('addEdges', () => { + console.log('addEdges') this.restartSimulation() + this.updateLinkForce() }) - this.graph.on('removeEdge', () => { - console.log('removeEdge') + this.graph.on('removeEdges', () => { + console.log('removeEdges') this.restartSimulation() }) - this.graph.on('removeNode', () => { - console.log('removeNode') + this.graph.on('removeNodes', () => { + console.log('removeNodes') this.restartSimulation() }) - this.graph.on('updateEdge', () => console.log('updateEdge')) - this.graph.on('updateNode', () => console.log('updateNode')) + // this.graph.on('updateEdge', () => console.log('updateEdge')) + // this.graph.on('updateNode', () => console.log('updateNode')) }, - restartSimulation () { + restartSimulation (updateForces = true) { + console.log('restarting simulation') // @ts-ignore - const simulation: Simulation = this.simulation - simulation.stop() - const nodes = simulation.nodes(this.graph.nodes) - const playerId = this.player.id - for (const node of nodes) { - if (node.id === playerId) { - node.fixed = true - } + let simulation: Simulation = this.simulation + if (!simulation) { + simulation = forceSimulation() + // @ts-ignore + this.simulation = simulation + } + simulation.nodes(this.graph.nodes) + if (updateForces) { + simulation.stop() + this.updateForces() } - simulation.force('link').links(this.graph.edges); simulation.alpha(1).restart() }, + updateLinkForce () { + const linkForce = forceLink(this.graph.edges) + if (this.layout.linkDistance) { + linkForce.distance(this.layout.linkDistance) + } + // @ts-ignore + this.simulation.force('link', linkForce) + }, updateForces () { + console.log('updating simulation forces') // @ts-ignore const simulation: Simulation = this.simulation - simulation.force('link', forceLink(this.graph.edges).distance(this.layout.linkDistance || this.linkDistance)) - .force('charge', forceManyBody().strength(this.layout.chargeStrength as number)) - // .force('center-repel', forceRadial(this.layout.centerRepel as number, this.width, this.height)) - .force('center', forceCenter(this.width / 2, this.height / 2)) - .velocityDecay(this.layout.friction as number) + + this.updateLinkForce() + + const manyBody = forceManyBody() + if (this.layout.chargeStrength) { + manyBody.strength(this.layout.chargeStrength) + } + + simulation.force('charge', manyBody) + // .force('center', forceCenter(this.center.x, this.center.y)) + + if (this.layout.centerRepel) { + simulation.force('center-repel', forceRadial(this.layout.centerRepel, this.center.x, this.center.y)) + } + + if (this.layout.friction) { + simulation.velocityDecay(this.layout.friction as number) + } }, - evaluateProp (key: keyof Vue, node: Node): string | number { - // console.log('evaluating', key) - return typeof this[key] === 'function' ? this[key](node, this.player) : this[key] + evaluateProp (key: keyof Vue, obj: object): string | number { + const res = typeof this[key] === 'function' ? this[key](obj, this.player) : this[key] + // console.log('evaluating prop', key, 'returned', res, 'for', obj) + return res }, resize () { if (this.$refs.container instanceof Element) { - this.width = this.$refs.container.clientWidth || 600 - this.height = this.$refs.container.clientHeight || 600 - this.updateForces() - this.restartSimulation() + // this.width = this.$refs.container.clientWidth || 600 + // this.height = this.$refs.container.clientHeight || 600 + this.restartSimulation(true) } } }, computed: { linkDistance (): number { return (Math.min(this.width, this.height) / 2) - (2 * this.graphPadding) - 50 + }, + center (): {x: number, y: number} { + return { + x: this.width / 2, + y: this.height / 2 + } } }, }) diff --git a/frontend/client/lib/graph.ts b/frontend/client/lib/graph.ts index 89e33d4..da19fc8 100644 --- a/frontend/client/lib/graph.ts +++ b/frontend/client/lib/graph.ts @@ -26,29 +26,37 @@ export class Graph extends Emitter implements GraphEvents { } } - addNode (data: NodeData) { - const node = { - id: data.id, - data, - x: 0, - y: 0, + addNodes (data: NodeData[]) { + const addedNodes = [] + for (const datum of data) { + const node = { + id: datum.id, + data: datum, + x: 0, + y: 0, + } + this.nodes.push(node) + this.nodeIdMap.set(node.id, node) + addedNodes.push(node) } - this.nodes.push(node) - this.nodeIdMap.set(node.id, node) - this.emit('addNode', node) + this.emit('addNodes', addedNodes) } - addEdge (data: LinkData) { - const source = this.nodeIdMap.get(data.sourceId) - const target = this.nodeIdMap.get(data.targetId) - if (source && target) { - // delete data.source - // delete data.target - const edge = { id: data.id, source, target, data, index: this.edges.length - 1 } - this.edges.push(edge) - this.edgeIdMap.set(data.id, edge) - this.emit('addEdge', edge) + addEdges (data: LinkData[]) { + let addedEdges = [] + for (const datum of data) { + const source = this.nodeIdMap.get(datum.sourceId) + const target = this.nodeIdMap.get(datum.targetId) + if (source && target) { + // delete datum.source + // delete datum.target + const edge = { id: datum.id, source, target, data: datum, index: this.edges.length - 1 } + this.edges.push(edge) + this.edgeIdMap.set(datum.id, edge) + addedEdges.push(edge) + } } + this.emit('addEdges', addedEdges) } clearEdges () { @@ -63,28 +71,36 @@ export class Graph extends Emitter implements GraphEvents { this.emit('clearNodes') } - removeEdge (edge: Edge): void - removeEdge (edgeId: number): void - removeEdge (edgeOrId: Edge | number): void { - const edgeId = typeof edgeOrId === 'object' ? edgeOrId.id : edgeOrId - const index = this.edges.findIndex(e => e.id === edgeId) - if (index !== -1) { - const edge = this.edges.splice(index, 1)[0] - this.edgeIdMap.delete(edgeId) - this.emit('removeEdge', edge) + removeEdges (edges: Edge[]): void + removeEdges (edgeIds: number[]): void + removeEdges (edgesOrIds: (Edge | number)[]): void { + const removedEdges = [] + for (const edgeOrId of edgesOrIds) { + const edgeId = typeof edgeOrId === 'object' ? edgeOrId.id : edgeOrId + const index = this.edges.findIndex(e => e.id === edgeId) + if (index !== -1) { + const edge = this.edges.splice(index, 1)[0] + this.edgeIdMap.delete(edgeId) + removedEdges.push(edge) + } } + this.emit('removeEdges', removedEdges) } - removeNode (node: Node): void - removeNode (nodeId: string): void - removeNode (nodeOrId: Node | string): void { - const nodeId = typeof nodeOrId === 'object' ? nodeOrId.id : nodeOrId - const index = this.nodes.findIndex(n => n.id === nodeId) - if (index !== -1) { - const node = this.nodes.splice(index, 1)[0] - this.nodeIdMap.delete(nodeId) - this.emit('removeNode', node) + removeNodes (nodes: Node[]): void + removeNodes (nodeIds: string[]): void + removeNodes (nodesOrIds: (Node | string)[]): void { + const removedNodes = [] + for (const nodeOrId of nodesOrIds) { + const nodeId = typeof nodeOrId === 'object' ? nodeOrId.id : nodeOrId + const index = this.nodes.findIndex(n => n.id === nodeId) + if (index !== -1) { + const node = this.nodes.splice(index, 1)[0] + this.nodeIdMap.delete(nodeId) + removedNodes.push(node) + } } + this.emit('removeNodes', removedNodes) } /** @@ -108,43 +124,52 @@ export class Graph extends Emitter implements GraphEvents { this.clearEdges() } + const removedNodes = [] for (const node of this.nodes) { // Check for old nodes const existingNode = data.nodes.find(n => n.id === node.id) if (!existingNode) { - this.removeNode(node) + removedNodes.push(node) } else if (existingNode !== node.data) { // TODO: update the existing node node.data = existingNode + // this.emit('updateNode', node) } } + if (removedNodes.length) this.removeNodes(removedNodes) + let removedEdges = [] for (const edge of this.edges) { const existingEdge = data.links.find(l => l.id === edge.id) if (!existingEdge) { - this.removeEdge(edge) + removedEdges.push(edge) } else if (existingEdge !== edge.data) { // TODO: Update the existing edge // this.emit('updateEdge', edge) } } + if (removedEdges.length) this.removeEdges(removedEdges) + const addedNodes = [] for (const node of data.nodes) { const nodeAlreadyExists = this.nodeIdMap.has(node.id) if (!nodeAlreadyExists) { - this.addNode(node) + addedNodes.push(node) } } + if (addedNodes.length) this.addNodes(addedNodes) + const addedEdges = [] for (const link of data.links) { const edgeAlreadyExists = this.edgeIdMap.has(link.id) if (!edgeAlreadyExists) { link.sourceId = data.nodes[link.source].id link.targetId = data.nodes[link.target].id - this.addEdge(link) + addedEdges.push(link) } } + if (addedEdges.length) this.addEdges(addedEdges) } diff --git a/frontend/client/mixins/DefaultView.js b/frontend/client/mixins/DefaultView.js index 672ee6c..bc78fc1 100644 --- a/frontend/client/mixins/DefaultView.js +++ b/frontend/client/mixins/DefaultView.js @@ -14,7 +14,8 @@ export default { async created () { const [_, __, config] = await Promise.all([window.Breadboard.connect(), window.Breadboard.login(), window.Breadboard.loadConfig()]) this.config = config - window.Breadboard.on('data', console.log) + this.player.id = config.clientId + // window.Breadboard.on('data', console.log) window.Breadboard.on('style', contents => { if (contents.length) { window.Breadboard.addStyleFromString(contents) diff --git a/frontend/core/breadboard.types.ts b/frontend/core/breadboard.types.ts index a9b91e0..b0d350f 100644 --- a/frontend/core/breadboard.types.ts +++ b/frontend/core/breadboard.types.ts @@ -74,10 +74,10 @@ export type BreadboardGraphData = { } export interface GraphEvents { - on (event: 'addNode', cb: (node: Node) => void, context?: object): void - on (event: 'removeNode', cb: (node: Node) => void, context?: object): void - on (event: 'addEdge', cb: (edge: Edge) => void, context?: object): void - on (event: 'removeEdge', cb: (edge: Edge) => void, context?: object): void + on (event: 'addNodes', cb: (node: Node[]) => void, context?: object): void + on (event: 'removeNodes', cb: (node: Node[]) => void, context?: object): void + on (event: 'addEdges', cb: (edge: Edge[]) => void, context?: object): void + on (event: 'removeEdges', cb: (edge: Edge[]) => void, context?: object): void on (event: 'updateNode', cb: (node: Node) => void, context?: object): void on (event: 'updateEdge', cb: (edge: Edge) => void, context?: object): void } diff --git a/frontend/design/content/content.controller.js b/frontend/design/content/content.controller.js index 8712de9..0bba9f5 100644 --- a/frontend/design/content/content.controller.js +++ b/frontend/design/content/content.controller.js @@ -246,4 +246,4 @@ export default function ContentCtrl($scope, ContentSrv, STATUS, $timeout, orderB }); }; -} \ No newline at end of file +} diff --git a/frontend/design/design/controllers.js b/frontend/design/design/controllers.js index d002c88..27d41f7 100644 --- a/frontend/design/design/controllers.js +++ b/frontend/design/design/controllers.js @@ -150,6 +150,7 @@ function ($scope, $breadboardFactory, $timeout, $http, $state, csvService, confi $http.get('/logout').then(function(res){ // $state.go('login'); // Remove this redirect once the application cleans up after itself correctly + window.Breadboard.disconnect() setTimeout(function(){ window.location.reload(); }); @@ -735,4 +736,4 @@ function ($scope, $breadboardFactory, $timeout, $http, $state, csvService, confi // TODO: Disconnect from websockets and other cleanup so that the application can restart without redirect }); -}]); \ No newline at end of file +}]); diff --git a/frontend/design/design/design.sass b/frontend/design/design/design.sass index f37d0a5..883755d 100644 --- a/frontend/design/design/design.sass +++ b/frontend/design/design/design.sass @@ -1,6 +1,6 @@ /* html, body */ html, body - height: 100% + height: 100vh width: 100% padding: 0 margin: 0 diff --git a/frontend/design/design/routes.js b/frontend/design/design/routes.js index 2cb4727..ab4a928 100644 --- a/frontend/design/design/routes.js +++ b/frontend/design/design/routes.js @@ -19,6 +19,7 @@ angular.module('breadboard.routes', ['ui.router', 'breadboard.middleware', 'ngCo $cookieStore.put('email', res.data.email); $cookieStore.put('juid', res.data.juid); $cookieStore.put('uid', res.data.uid); + window.Breadboard.disconnect() $state.go('home'); }; }] @@ -39,4 +40,4 @@ angular.module('breadboard.routes', ['ui.router', 'breadboard.middleware', 'ngCo $httpProvider.interceptors.push('AuthorizationMiddleware'); -}]); \ No newline at end of file +}]); diff --git a/frontend/package-lock.json b/frontend/package-lock.json index ac0d2cf..c515c7c 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1150,9 +1150,9 @@ "dev": true }, "@types/node": { - "version": "12.7.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.5.tgz", - "integrity": "sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w==", + "version": "12.7.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.11.tgz", + "integrity": "sha512-Otxmr2rrZLKRYIybtdG/sgeO+tHY20GxeDjcGmUnmmlCWyEnv2a2x1ZXBo3BTec4OiTXMQCiazB8NMBf0iRlFw==", "dev": true }, "@types/webpack-env": { @@ -3594,9 +3594,9 @@ "dev": true }, "eventemitter3": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", - "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", + "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==", "dev": true }, "events": { @@ -5175,12 +5175,12 @@ "dev": true }, "http-proxy": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", - "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz", + "integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==", "dev": true, "requires": { - "eventemitter3": "^3.0.0", + "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", "requires-port": "^1.0.0" } @@ -5364,9 +5364,9 @@ "dev": true }, "is-absolute-url": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.2.tgz", - "integrity": "sha512-+5g/wLlcm1AcxSP7014m6GvbPHswDx980vD/3bZaap8aGV9Yfs7Q6y6tfaupgZ5O74Byzc8dGrSCJ+bFXx0KdA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", + "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==", "dev": true }, "is-accessor-descriptor": { @@ -6312,9 +6312,9 @@ } }, "node-forge": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.8.2.tgz", - "integrity": "sha512-mXQ9GBq1N3uDCyV1pdSzgIguwgtVpM7f5/5J4ipz12PKWElmPpVWLDuWl8iXmhysr21+WmX/OJ5UKx82wjomgg==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz", + "integrity": "sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==", "dev": true }, "node-gyp": { @@ -7867,12 +7867,12 @@ "dev": true }, "selfsigned": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.6.tgz", - "integrity": "sha512-i3+CeqxL7DpAazgVpAGdKMwHuL63B5nhJMh9NQ7xmChGkA3jNFflq6Jyo1LLJYcr3idWiNOPWHCrm4zMayLG4w==", + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.7.tgz", + "integrity": "sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA==", "dev": true, "requires": { - "node-forge": "0.8.2" + "node-forge": "0.9.0" } }, "semver": { @@ -9729,9 +9729,9 @@ } }, "webpack-dev-middleware": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.1.tgz", - "integrity": "sha512-5MWu9SH1z3hY7oHOV6Kbkz5x7hXbxK56mGHNqHTe6d+ewxOwKUxoUJBs7QIaJb33lPjl9bJZ3X0vCoooUzC36A==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz", + "integrity": "sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw==", "dev": true, "requires": { "memory-fs": "^0.4.1", @@ -9750,9 +9750,9 @@ } }, "webpack-dev-server": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.8.1.tgz", - "integrity": "sha512-9F5DnfFA9bsrhpUCAfQic/AXBVHvq+3gQS+x6Zj0yc1fVVE0erKh2MV4IV12TBewuTrYeeTIRwCH9qLMvdNvTw==", + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.8.2.tgz", + "integrity": "sha512-0xxogS7n5jHDQWy0WST0q6Ykp7UGj4YvWh+HVN71JoE7BwPxMZrwgraBvmdEMbDVMBzF0u+mEzn8TQzBm5NYJQ==", "dev": true, "requires": { "ansi-html": "0.0.7", @@ -9764,18 +9764,18 @@ "del": "^4.1.1", "express": "^4.17.1", "html-entities": "^1.2.1", - "http-proxy-middleware": "^0.19.1", + "http-proxy-middleware": "0.19.1", "import-local": "^2.0.0", "internal-ip": "^4.3.0", "ip": "^1.1.5", - "is-absolute-url": "^3.0.2", + "is-absolute-url": "^3.0.3", "killable": "^1.0.1", "loglevel": "^1.6.4", "opn": "^5.5.0", "p-retry": "^3.0.1", "portfinder": "^1.0.24", "schema-utils": "^1.0.0", - "selfsigned": "^1.10.6", + "selfsigned": "^1.10.7", "semver": "^6.3.0", "serve-index": "^1.9.1", "sockjs": "0.3.19", @@ -9784,7 +9784,7 @@ "strip-ansi": "^3.0.1", "supports-color": "^6.1.0", "url": "^0.11.0", - "webpack-dev-middleware": "^3.7.1", + "webpack-dev-middleware": "^3.7.2", "webpack-log": "^2.0.0", "ws": "^6.2.1", "yargs": "12.0.5" diff --git a/frontend/package.json b/frontend/package.json index 56e2867..6113f62 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -60,7 +60,7 @@ "vuetify": "^2.0.19", "webpack": "^4.0.0", "webpack-cli": "^3.3.9", - "webpack-dev-server": "^3.8.1", + "webpack-dev-server": "^3.8.2", "webpack-livereload-plugin": "^2.2.0" }, "engines": { diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index bae7dac..2dfdea9 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -7,6 +7,7 @@ "moduleResolution": "node", "esModuleInterop": true, "allowSyntheticDefaultImports": true, + "experimentalDecorators": true, "sourceMap": true, "strict": true, "baseUrl": ".", diff --git a/frontend/webpack/webpack.base.js b/frontend/webpack/webpack.base.js index 1cce36f..bfa6aae 100644 --- a/frontend/webpack/webpack.base.js +++ b/frontend/webpack/webpack.base.js @@ -5,9 +5,20 @@ const VueLoaderPlugin = require('vue-loader/lib/plugin') const MiniCssExtractPlugin = require('mini-css-extract-plugin') const buildPath = path.resolve(__dirname, '../../public/bundles/') -/** - * Base configuration object for Webpack - */ +const isProd = process.env.NODE_ENV === 'production' +const plugins = [ + new webpack.ContextReplacementPlugin( + /angular(\\|\/)core(\\|\/)@angular/, + path.resolve(__dirname, './design') + ), + new VueLoaderPlugin() +] +if (isProd) { + plugins.push(new MiniCssExtractPlugin({ + filename: '[name].css', + })) +} + module.exports = { output: { path: buildPath, @@ -19,7 +30,7 @@ module.exports = { loader: 'vue-loader' }, { test: /\.(sass|scss)$/, - use: [MiniCssExtractPlugin.loader, + use: [isProd ? MiniCssExtractPlugin.loader : 'vue-style-loader', 'css-loader?url=false', { loader: 'sass-loader', @@ -54,10 +65,10 @@ module.exports = { presets: ['@babel/preset-env'] } }, - exclude: { - include: /node_modules/, - exclude: /goodish/ - } + // exclude: { + // include: /node_modules/, + // exclude: /goodish/ + // } }, { test: /\.html$/, use: ['ngtemplate-loader?relativeTo=frontend&prefix=files', 'html-loader'], @@ -81,14 +92,5 @@ module.exports = { externals: { vue: 'Vue' }, - plugins: [ - new webpack.ContextReplacementPlugin( - /angular(\\|\/)core(\\|\/)@angular/, - path.resolve(__dirname, './design') - ), - new VueLoaderPlugin(), - new MiniCssExtractPlugin({ - filename: '[name].css', - }), - ] + plugins: plugins } diff --git a/frontend/webpack/webpack.client.js b/frontend/webpack/webpack.client.js index 0b13556..eb49941 100644 --- a/frontend/webpack/webpack.client.js +++ b/frontend/webpack/webpack.client.js @@ -33,9 +33,9 @@ module.exports = merge(Object.create(config), { publicPath: config.output.publicPath, filename: '[name].js' }, - optimization: { + /*optimization: { splitChunks: { cacheGroups: cacheGroups } - }, + },*/ }) diff --git a/frontend/webpack/webpack.prod.js b/frontend/webpack/webpack.prod.js index 35808cd..826e9c3 100644 --- a/frontend/webpack/webpack.prod.js +++ b/frontend/webpack/webpack.prod.js @@ -1,5 +1,6 @@ +process.env.NODE_ENV = 'production' const clientConfig = require('./webpack.client') // TODO: add minification and prod stuff for client here -module.exports = [clientConfig]; +module.exports = [clientConfig] diff --git a/frontend/webpack/webpack.server.js b/frontend/webpack/webpack.server.js index 609562b..f15b8bd 100644 --- a/frontend/webpack/webpack.server.js +++ b/frontend/webpack/webpack.server.js @@ -33,16 +33,16 @@ const server = new webpackDevServer(compiler, { // We need to tell Webpack to serve our bundled application // from the build path. publicPath: '/bundles/', - // sockHost: `http://localhost`, sockPort: PORT, // Configure hot replacement - // hot: false, - // liveReload: false, + hot: true, + liveReload: false, + writeToDisk: false, // The rest is terminal configurations quiet: false, - noInfo: true, + noInfo: false, stats: { colors: true } diff --git a/public/templates/breadboard.html b/public/templates/breadboard.html index 8f59549..8cda53c 100644 --- a/public/templates/breadboard.html +++ b/public/templates/breadboard.html @@ -8,6 +8,7 @@ + @@ -21,7 +22,8 @@ + - \ No newline at end of file + From 523534b8dc9b613574146f190053c4bef9d064e8 Mon Sep 17 00:00:00 2001 From: wyattis Date: Fri, 4 Oct 2019 17:13:52 -0400 Subject: [PATCH 005/234] Made todo list. Start working on Gremlins --- frontend/client/TODO.md | 35 ++++++++++++++++++++----- frontend/client/client.ts | 10 +++---- frontend/client/components/SVGGraph.vue | 4 +-- frontend/client/gremlins.js | 31 ++++++++++++++++++++++ frontend/client/mixins/DefaultView.js | 22 +++++++++++++--- frontend/package-lock.json | 23 ++++++++++++++-- frontend/package.json | 1 + frontend/webpack/webpack.base.js | 3 ++- 8 files changed, 109 insertions(+), 20 deletions(-) create mode 100644 frontend/client/gremlins.js diff --git a/frontend/client/TODO.md b/frontend/client/TODO.md index 9a5d78a..e7dc55a 100644 --- a/frontend/client/TODO.md +++ b/frontend/client/TODO.md @@ -1,12 +1,35 @@ # TODO - [ ] Locales - [ ] Gremlins -- [ ] Graph -- [ ] Choices - - [ ] Custom choices -- [ ] Player text -- [ ] Custom styles -- [ ] Timer +- [ ] Graph API + - [ ] Handle node and edge updates with a diff first + - [x] Basic graph diffing +- [ ] SVGGraph + - [ ] debounce graph updates to avoid multiple, rapid resets of the force-directed graph simulation + - [ ] handle input passing + - [ ] optional centering of the ego node + - [ ] filter ignored props from binding to SVG +- [ ] Component slots + - [ ] Timer label + - [ ] Button contents +- [ ] Documentation + - [ ] SVGGraph properties + - [ ] Events + - [ ] Breadboard events + - [ ] Graph events + - [ ] Examples + - [ ] Most basic example of frontend use + - [ ] Mapping props (fill, stroke, strokeWidth) using map functions + - [ ] Using slots to customize existing components + - [ ] Loading an external library to use + - [ ] Tutorials + - [ ] How to use a completely separate UI (phaser?) + - [ ] Overriding a Vue component to customize something (buttons) +- [x] Choices + - [x] Custom choices +- [x] Player text +- [x] Custom styles +- [x] Timer # Flow diff --git a/frontend/client/client.ts b/frontend/client/client.ts index e96c161..efa1f3b 100644 --- a/frontend/client/client.ts +++ b/frontend/client/client.ts @@ -31,15 +31,13 @@ async function client () { :graph="graph" :nodeBorderWidth="node => node.isEgo ? 2 : 1" :nodeFill="node => node.isEgo ? 'blue' : 'lightgrey'" - :nodeRadius="node => node.data.score * 2 || 10"> + :nodeRadius="node => node.data.score * 2 || 30"> diff --git a/frontend/client/components/SVGGraph.vue b/frontend/client/components/SVGGraph.vue index 3cd7dbb..e33e0e7 100644 --- a/frontend/client/components/SVGGraph.vue +++ b/frontend/client/components/SVGGraph.vue @@ -1,5 +1,5 @@ diff --git a/frontend/client/components/SVGGraph.vue b/frontend/client/components/SVGGraph.vue index 1e5b150..8cd7c93 100644 --- a/frontend/client/components/SVGGraph.vue +++ b/frontend/client/components/SVGGraph.vue @@ -9,6 +9,7 @@ - + @@ -25,9 +27,9 @@ name="node" v-bind:node="node" v-for="node in graph.nodes"> - + String[], - default: () => ['text', 'choices', 'x', 'y', 'timers'] + default: () => ['text', 'choices', 'x', 'y', 'timers', 'timerUpdatedAt'] } }, data () { @@ -129,6 +131,13 @@ this.setupSimulation() }, methods: { + filteredObject (obj: { [key: string]: any }, keys: string[]) { + let o = Object.assign(obj) + for (const key of keys) { + delete o[key] + } + return o + }, setupSimulation () { this.restartSimulation() this.graph.on('addNodes', (nodes: Node[]) => { @@ -218,6 +227,15 @@ // this.height = this.$refs.container.clientHeight || 600 this.restartSimulation(true) } + }, + nodeClick (node: Node, e: MouseEvent) { + this.$emit('nodeClick', node, e) + }, + edgeClick (edge: Edge, e: MouseEvent) { + this.$emit('edgeClick', edge, e) + }, + edgeLabelClick (edge: Edge, e: MouseEvent) { + this.$emit('edgeLabelClick', edge, e) } }, computed: { diff --git a/frontend/client/components/Timer.vue b/frontend/client/components/Timer.vue index f2d81d0..c3ffa68 100644 --- a/frontend/client/components/Timer.vue +++ b/frontend/client/components/Timer.vue @@ -4,7 +4,22 @@ :value="value" :color="color" reactive> - {{message}} + + + + + + {{message}} + + + + @@ -19,10 +34,6 @@ timer: { type: Object as () => PlayerTimer, required: true - }, - rate: { - type: Number, - default: 1000 } }, computed: { diff --git a/frontend/client/gremlins/gremlins.js b/frontend/client/gremlins/gremlins.js index d3c394d..4f74b46 100644 --- a/frontend/client/gremlins/gremlins.js +++ b/frontend/client/gremlins/gremlins.js @@ -2,14 +2,19 @@ import gremlins from 'gremlins-ts' import targetedClickerGremlin from './TargetedClickerGremlin' let horde +let isStarted = false export function startGremlins (player, doneCb) { - console.log('start gremlins') - if (player.droprate !== 0) { - const r = Math.random() - if (r < player.droprate || r < 0.2) return - } + if (isStarted) return + isStarted = true if (player.testmode) { - + if (player.droprate) { + const r = Math.random() + if (r < player.droprate) { + console.log('dropping player') + return + } + } + console.log('start gremlins') horde = gremlins.createHorde() .gremlin(gremlins.species.formFiller()) .gremlin(targetedClickerGremlin(['button', 'circle', 'edge', 'input'])) @@ -18,16 +23,15 @@ export function startGremlins (player, doneCb) { // .gremlin(gremlins.species.toucher().canTouch(e => { // return acceptedTypes.indexOf(e.tagName) > -1 || e.className.includes('svg-container') // })) - .gremlin(gremlins.species.scroller()) .mogwai(gremlins.mogwais.gizmo()) .mogwai(gremlins.mogwais.alert()) - .strategy(gremlins.strategies.distribution([0.4, 0.4, 0.2]).delay(100)) -/* .logger({ - log: () => {}, - info: () => {}, - error: () => {}, - warn: () => {} - })*/ + .strategy(gremlins.strategies.distribution([0.4, 0.4, 0.2]).delay(1000)) + .logger({ + log: null, + info: null, + error: null, + warn: null + }) .after(() => { console.log('stop gremlins') if (horde) { @@ -40,7 +44,8 @@ export function startGremlins (player, doneCb) { } export function stopGremlins () { - if (horde) { + if (isStarted && horde) { + console.log('stop gremlins') horde.stop() } } diff --git a/frontend/client/lib/graph.ts b/frontend/client/lib/graph.ts index bcc4db6..280e8b0 100644 --- a/frontend/client/lib/graph.ts +++ b/frontend/client/lib/graph.ts @@ -1,7 +1,8 @@ import { Emitter } from 'goodish' import { BreadboardClass } from '../../core/breadboard' import { BreadboardGraphData, Edge, GraphEvents, LinkData, Node, NodeData } from '../../core/breadboard.types' -import { isEqual, isEqualWith } from 'lodash' +import isEqual from 'lodash/isEqual' +import isEqualWith from 'lodash/isEqualWith' export class Graph extends Emitter implements GraphEvents { diff --git a/frontend/client/mixins/DefaultView.js b/frontend/client/mixins/DefaultView.js index 4f487ed..8e22a70 100644 --- a/frontend/client/mixins/DefaultView.js +++ b/frontend/client/mixins/DefaultView.js @@ -1,6 +1,8 @@ import { Graph } from '../lib/graph' import { isEqual, isEqualWith } from 'lodash' +import { Mutex } from 'async-mutex' +const gremlinsMutex = new Mutex() export default { data () { return { @@ -9,8 +11,7 @@ export default { text: 'Loading...', choices: [] }, - config: null, - gremlinsStarted: false + config: null } }, async created () { @@ -30,25 +31,9 @@ export default { }) window.Breadboard.on('player', async player => { - // First check if anything has changed before updating the view - const playerHasChanged = !isEqualWith(this.player, player, (a, b, key) => { - // Ignore the fact the player id is not included in the payload... It would be great if it were included by default? - if (key === 'id' && a.hasOwnProperty('timers') && b.hasOwnProperty('timers')) { - return true - } else { - return isEqual(a, b) - } - }) - - if (playerHasChanged) { - this.player = player - this.player.id = this.config.clientId - } else { - return - } - + this.player = player + this.player.id = this.config.clientId this.checkGremlins() - }) this.graph.attachToBreadboard(window.Breadboard) @@ -58,20 +43,32 @@ export default { this.graph.releaseFromBreadboard() }, methods: { + log (...args) { + console.log(...args) + }, async checkGremlins () { // Inject gremlins if in test mode let stopGremlins let startGremlins - if (!this.gremlinsStarted && this.player.testmode) { - this.gremlinsStarted = true - let d = await import(/* webpackChunkName: "gremlins" */'../gremlins/gremlins.js') - startGremlins = d.startGremlins - stopGremlins = d.stopGremlins() + if (this.player.testmode) { + const release = await gremlinsMutex.acquire() + if (startGremlins) { + release() + } else { + try { + let d = await import(/* webpackChunkName: "gremlins" */'../gremlins/gremlins.js') + startGremlins = d.startGremlins + stopGremlins = d.stopGremlins + } finally { + release() + } + } + // The gremlins script takes care of checking for overlapping const restartGremlins = () => { startGremlins(this.player, restartGremlins) } restartGremlins() - } else if (this.gremlinsStarted && stopGremlins) { + } else if (stopGremlins) { stopGremlins() } } diff --git a/frontend/package-lock.json b/frontend/package-lock.json index fed5a38..31731f6 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1044,6 +1044,15 @@ } } }, + "@babel/runtime": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.3.tgz", + "integrity": "sha512-kq6anf9JGjW8Nt5rYfEuGRaEAaH1mkv3Bbu6rYvLOpPh/RusSJXuKPEAoZ7L7gybZkchE8+NV5g9vKF4AGAtsA==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.2" + } + }, "@babel/template": { "version": "7.6.0", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.6.0.tgz", @@ -1126,6 +1135,37 @@ } } }, + "@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "dev": true, + "requires": { + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" + } + }, + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "dev": true + }, + "@types/babel-types": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/babel-types/-/babel-types-7.0.7.tgz", + "integrity": "sha512-dBtBbrc+qTHy1WdfHYjBwRln4+LWqASWakLHsWHR2NWHIFkv4W3O070IGoGLEBrJBvct3r0L1BUPuvURi7kYUQ==", + "dev": true + }, + "@types/babylon": { + "version": "6.16.5", + "resolved": "https://registry.npmjs.org/@types/babylon/-/babylon-6.16.5.tgz", + "integrity": "sha512-xH2e58elpj1X4ynnKp9qSnWlsRTIs6n3tgLGNfwAGHwePw0mulHQllV34n0T25uYSu1k0hRKkWXF890B1yS47w==", + "dev": true, + "requires": { + "@types/babel-types": "*" + } + }, "@types/chance": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@types/chance/-/chance-1.0.7.tgz", @@ -1171,6 +1211,33 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.11.tgz", "integrity": "sha512-Otxmr2rrZLKRYIybtdG/sgeO+tHY20GxeDjcGmUnmmlCWyEnv2a2x1ZXBo3BTec4OiTXMQCiazB8NMBf0iRlFw==" }, + "@types/unist": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz", + "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==", + "dev": true + }, + "@types/vfile": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/vfile/-/vfile-3.0.2.tgz", + "integrity": "sha512-b3nLFGaGkJ9rzOcuXRfHkZMdjsawuDD0ENL9fzTophtBg8FJHSGbH7daXkEpcwy3v7Xol3pAvsmlYyFhR4pqJw==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/unist": "*", + "@types/vfile-message": "*" + } + }, + "@types/vfile-message": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/vfile-message/-/vfile-message-1.0.1.tgz", + "integrity": "sha512-mlGER3Aqmq7bqR1tTTIVHq8KSAFFRyGbrxuM8C/H82g6k7r2fS+IMEkIu3D7JHzG10NvPdR8DNx0jr0pwpp4dA==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/unist": "*" + } + }, "@types/webpack-env": { "version": "1.14.0", "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.14.0.tgz", @@ -1232,6 +1299,15 @@ } } }, + "@vxna/mini-html-webpack-template": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/@vxna/mini-html-webpack-template/-/mini-html-webpack-template-0.1.7.tgz", + "integrity": "sha512-qV2VslV48ECPwyuG7c4O6JpYgjnvdm88YYkMncIXzakXXwVUxhcg6YipXxWK7U+pixHkWWSnDX/8DIOmWeh+PQ==", + "dev": true, + "requires": { + "common-tags": "^1.7.2" + } + }, "@webassemblyjs/ast": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", @@ -1448,6 +1524,35 @@ "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==", "dev": true }, + "acorn-globals": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz", + "integrity": "sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=", + "dev": true, + "requires": { + "acorn": "^4.0.4" + }, + "dependencies": { + "acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", + "dev": true + } + } + }, + "acorn-jsx": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.2.tgz", + "integrity": "sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw==", + "dev": true + }, + "address": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/address/-/address-1.0.3.tgz", + "integrity": "sha512-z55ocwKBRLryBs394Sm3ushTtBeg6VAeuku7utSoSnsJKvKcnXFIyC6vh27n3rXyxSgkJBBCAvyOn7gSUcTYjg==", + "dev": true + }, "ajv": { "version": "6.10.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", @@ -1472,6 +1577,17 @@ "integrity": "sha512-aUjdRFISbuFOl0EIZc+9e4FfZp0bDZgAdOOf30bJmw8VM9v84SHyVyxDfbWxpGYbdZD/9XoKxfHVNmxPkhwyGw==", "dev": true }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true, + "requires": { + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" + } + }, "amdefine": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", @@ -1535,6 +1651,12 @@ "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", "dev": true }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, "ansi-html": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", @@ -1608,6 +1730,12 @@ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", "dev": true }, + "array-filter": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", + "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=", + "dev": true + }, "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", @@ -1620,6 +1748,18 @@ "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", "dev": true }, + "array-map": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", + "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=", + "dev": true + }, + "array-reduce": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", + "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=", + "dev": true + }, "array-union": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", @@ -1641,6 +1781,18 @@ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", "dev": true }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", + "dev": true + }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", @@ -1756,6 +1908,17 @@ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", "dev": true }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + } + }, "babel-loader": { "version": "8.0.6", "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.6.tgz", @@ -1785,6 +1948,54 @@ "object.assign": "^4.1.0" } }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + }, + "dependencies": { + "core-js": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz", + "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + } + } + }, + "babel-types": { + "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", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "bail": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.4.tgz", + "integrity": "sha512-S8vuDB4w6YpRhICUDET3guPlQpaJl7od94tpZ0Fvnyp+MKW/HyDTcRDck+29C9g+d/qQHnddRH3+94kZdrW0Ww==", + "dev": true + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -2117,6 +2328,61 @@ "pako": "~1.0.5" } }, + "browserslist": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.4.1.tgz", + "integrity": "sha512-pEBxEXg7JwaakBXjATYw/D1YZh4QUSCX/Mnd/wnqSRPPSi1U39iDhDoKGoBUcraKdxDlrYqJxSI5nNvD+dWP2A==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000929", + "electron-to-chromium": "^1.3.103", + "node-releases": "^1.1.3" + } + }, + "buble": { + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/buble/-/buble-0.19.7.tgz", + "integrity": "sha512-YLgWxX/l+NnfotydBlxqCMPR4FREE4ubuHphALz0FxQ7u2hp3BzxTKQ4nKpapOaRJfEm1gukC68KnT2OymRK0g==", + "dev": true, + "requires": { + "acorn": "^6.1.1", + "acorn-dynamic-import": "^4.0.0", + "acorn-jsx": "^5.0.1", + "chalk": "^2.4.2", + "magic-string": "^0.25.2", + "minimist": "^1.2.0", + "os-homedir": "^1.0.1", + "regexpu-core": "^4.5.4" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, "buffer": { "version": "4.9.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", @@ -2254,6 +2520,12 @@ } } }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", + "dev": true + }, "camel-case": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", @@ -2288,12 +2560,34 @@ } } }, + "caniuse-lite": { + "version": "1.0.30000999", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000999.tgz", + "integrity": "sha512-1CUyKyecPeksKwXZvYw0tEoaMCo/RwBlXmEtN5vVnabvO0KPd9RQLcaAuR9/1F+KDMv6esmOFWlsXuzDk+8rxg==", + "dev": true + }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "dev": true }, + "ccount": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.0.4.tgz", + "integrity": "sha512-fpZ81yYfzentuieinmGnphk0pLkOTMm6MZdVqwd77ROvhko6iujLNGrHH5E7utq3ygWklwfmwuG+A7P+NpqT6w==", + "dev": true + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "dev": true, + "requires": { + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" + } + }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", @@ -2320,6 +2614,45 @@ "resolved": "https://registry.npmjs.org/chance/-/chance-1.1.0.tgz", "integrity": "sha512-DwT4HVvl1VwZ73lqEyWYtrI59iSERBDfioMhw0gMMNySLMcx7/pzy+JAam3+3WcEH4ITNzwRtuQH4Geyko70gw==" }, + "character-entities": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.3.tgz", + "integrity": "sha512-yB4oYSAa9yLcGyTbB4ItFwHw43QHdH129IJ5R+WvxOkWlyFnR5FAaBNnUq4mcxsTVZGh28bHoeTHMKXH1wZf3w==", + "dev": true + }, + "character-entities-html4": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.3.tgz", + "integrity": "sha512-SwnyZ7jQBCRHELk9zf2CN5AnGEc2nA+uKMZLHvcqhpPprjkYhiLn0DywMHgN5ttFZuITMATbh68M6VIVKwJbcg==", + "dev": true + }, + "character-entities-legacy": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.3.tgz", + "integrity": "sha512-YAxUpPoPwxYFsslbdKkhrGnXAtXoHNgYjlBM3WMXkWGTl5RsY3QmOyhwAgL8Nxm9l5LBThXGawxKPn68y6/fww==", + "dev": true + }, + "character-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", + "integrity": "sha1-x84o821LzZdE5f/CxfzeHHMmH8A=", + "dev": true, + "requires": { + "is-regex": "^1.0.3" + } + }, + "character-reference-invalid": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.3.tgz", + "integrity": "sha512-VOq6PRzQBam/8Jm6XBGk2fNEnHXAdGd6go0rtd4weAGECBamHDwwCQSOT12TACIYUZegUXnV6xBXqUssijtxIg==", + "dev": true + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, "chokidar": { "version": "2.1.6", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz", @@ -2394,6 +2727,12 @@ } } }, + "classnames": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", + "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==", + "dev": true + }, "clean-css": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.1.11.tgz", @@ -2403,6 +2742,54 @@ "source-map": "0.5.x" } }, + "clean-webpack-plugin": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/clean-webpack-plugin/-/clean-webpack-plugin-0.1.19.tgz", + "integrity": "sha512-M1Li5yLHECcN2MahoreuODul5LkjohJGFxLPTjl3j1ttKrF5rgjZET1SJduuqxLAuT1gAPOdkhg03qcaaU1KeA==", + "dev": true, + "requires": { + "rimraf": "^2.6.1" + } + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-spinners": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-1.3.1.tgz", + "integrity": "sha512-1QL4544moEsDVH9T/l6Cemov/37iv1RtoKf7NJ04A60+4MREXNfx/QvavbH6QoGdsD4N4Mwy49cmaINR/o2mdg==", + "dev": true + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "clipboard": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.4.tgz", + "integrity": "sha512-Vw26VSLRpJfBofiVaFb/I8PVfdI1OxKcYShe6fm0sP/DtmiWQNCjhM/okTvdCo0G+lMMm1rMYbk4IK4x1X+kgQ==", + "dev": true, + "optional": true, + "requires": { + "good-listener": "^1.2.2", + "select": "^1.1.2", + "tiny-emitter": "^2.0.0" + } + }, + "clipboard-copy": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/clipboard-copy/-/clipboard-copy-3.1.0.tgz", + "integrity": "sha512-Xsu1NddBXB89IUauda5BIq3Zq73UWkjkaQlPQbLNvNsd5WBMnTWPNKYR6HGaySOxGYZ+BKxP2E9X4ElnI3yiPA==", + "dev": true + }, "cliui": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", @@ -2447,6 +2834,12 @@ } } }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true + }, "clone-deep": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.3.0.tgz", @@ -2470,6 +2863,12 @@ } } }, + "clsx": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.0.4.tgz", + "integrity": "sha512-1mQ557MIZTrL/140j+JVdRM6e31/OA4vTYxXgqIIZlndyfjHpyawKZia1Im05Vp9BWmImkcNrNtFYQMyFcgJDg==", + "dev": true + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -2487,6 +2886,12 @@ "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.32.0.tgz", "integrity": "sha1-y2/12O820LEPAxEw4tnr7ukskC4=" }, + "collapse-white-space": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.5.tgz", + "integrity": "sha512-703bOOmytCYAX9cXYqoikYIx6twmFCXsnzRQheBcTG3nzKYBR4P/+wkYeH+Mvj7qUz8zZDtdyzbxfnEi/kYzRQ==", + "dev": true + }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", @@ -2512,11 +2917,38 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "colors": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", + "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=", + "dev": true + }, "commander": { "version": "2.12.2", "resolved": "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz", "integrity": "sha1-D1lGxCftnsDZGka7ne9T5UZQ5VU=" }, + "common-dir": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/common-dir/-/common-dir-2.0.2.tgz", + "integrity": "sha512-AiVcdIuevkFWyqrcHhpOWJbaFBLm+OLPiaRy3QikrMypalgA4ehU1SugZO2rPawgdzkTAycXGs3F65PGPA2DWg==", + "dev": true, + "requires": { + "common-sequence": "^1.0.2" + } + }, + "common-sequence": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/common-sequence/-/common-sequence-1.0.2.tgz", + "integrity": "sha1-MOB/P49vf5s97oVPILLTnu4Ibeg=", + "dev": true + }, + "common-tags": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", + "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==", + "dev": true + }, "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -2609,6 +3041,18 @@ "bluebird": "^3.1.1" } }, + "constantinople": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-3.1.2.tgz", + "integrity": "sha512-yePcBqEFhLOqSBtwYOGGS1exHo/s1xjekXiinh4itpNQGCu4KA1euPh1fg07N2wMITZXQkBz75Ntdt1ctGZouw==", + "dev": true, + "requires": { + "@types/babel-types": "^7.0.0", + "@types/babylon": "^6.16.2", + "babel-types": "^6.26.0", + "babylon": "^6.18.0" + } + }, "constants-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", @@ -2685,35 +3129,215 @@ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", "dev": true }, - "core-js": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", - "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==", - "dev": true - }, - "core-js-compat": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.2.1.tgz", - "integrity": "sha512-MwPZle5CF9dEaMYdDeWm73ao/IflDH+FjeJCWEADcEgFSE9TLimFKwJsfmkwzI8eC0Aj0mgvMDjeQjrElkz4/A==", + "copy-webpack-plugin": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.6.0.tgz", + "integrity": "sha512-Y+SQCF+0NoWQryez2zXn5J5knmr9z/9qSQt7fbL78u83rxmigOy8X5+BFn8CFSuX+nKT8gpYwJX68ekqtQt6ZA==", "dev": true, "requires": { - "browserslist": "^4.6.6", - "semver": "^6.3.0" + "cacache": "^10.0.4", + "find-cache-dir": "^1.0.0", + "globby": "^7.1.1", + "is-glob": "^4.0.0", + "loader-utils": "^1.1.0", + "minimatch": "^3.0.4", + "p-limit": "^1.0.0", + "serialize-javascript": "^1.4.0" }, "dependencies": { - "browserslist": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.7.0.tgz", - "integrity": "sha512-9rGNDtnj+HaahxiVV38Gn8n8Lr8REKsel68v1sPFfIGEK6uSXTY3h9acgiT1dZVtOOUtifo/Dn8daDQ5dUgVsA==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30000989", - "electron-to-chromium": "^1.3.247", - "node-releases": "^1.1.29" + "cacache": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz", + "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==", + "dev": true, + "requires": { + "bluebird": "^3.5.1", + "chownr": "^1.0.1", + "glob": "^7.1.2", + "graceful-fs": "^4.1.11", + "lru-cache": "^4.1.1", + "mississippi": "^2.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.2", + "ssri": "^5.2.4", + "unique-filename": "^1.1.0", + "y18n": "^4.0.0" } }, - "caniuse-lite": { - "version": "1.0.30000989", + "find-cache-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", + "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^1.0.0", + "pkg-dir": "^2.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "globby": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", + "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "^2.0.0", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "mississippi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz", + "integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==", + "dev": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^2.0.1", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "ssri": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.3.0.tgz", + "integrity": "sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.1" + } + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + } + } + }, + "core-js": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", + "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==", + "dev": true + }, + "core-js-compat": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.2.1.tgz", + "integrity": "sha512-MwPZle5CF9dEaMYdDeWm73ao/IflDH+FjeJCWEADcEgFSE9TLimFKwJsfmkwzI8eC0Aj0mgvMDjeQjrElkz4/A==", + "dev": true, + "requires": { + "browserslist": "^4.6.6", + "semver": "^6.3.0" + }, + "dependencies": { + "browserslist": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.7.0.tgz", + "integrity": "sha512-9rGNDtnj+HaahxiVV38Gn8n8Lr8REKsel68v1sPFfIGEK6uSXTY3h9acgiT1dZVtOOUtifo/Dn8daDQ5dUgVsA==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000989", + "electron-to-chromium": "^1.3.247", + "node-releases": "^1.1.29" + } + }, + "caniuse-lite": { + "version": "1.0.30000989", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000989.tgz", "integrity": "sha512-vrMcvSuMz16YY6GSVZ0dWDTJP8jqk3iFQ/Aq5iqblPwxSVVZI+zxDyTX0VPqtQsDnfdrBDcsmhgTEOh5R8Lbpw==", "dev": true @@ -2798,6 +3422,12 @@ "randomfill": "^1.0.3" } }, + "css-initials": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/css-initials/-/css-initials-0.2.0.tgz", + "integrity": "sha512-t80yjg0pi4VAIc5itIqLh6M+ZlA+cB+gUXEQkDR09+ExTDwLMGfJ8YviBsGW+DklIrb2k9fwB75Io8ooWXDxxw==", + "dev": true + }, "css-loader": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-2.1.1.tgz", @@ -3258,6 +3888,12 @@ "regexp.prototype.flags": "^1.2.0" } }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, "deepmerge": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.0.0.tgz", @@ -3274,6 +3910,15 @@ "ip-regex": "^2.1.0" } }, + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -3365,6 +4010,13 @@ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true }, + "delegate": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", + "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==", + "dev": true, + "optional": true + }, "delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -3411,6 +4063,16 @@ "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", "dev": true }, + "detect-port-alt": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", + "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", + "dev": true, + "requires": { + "address": "^1.0.1", + "debug": "^2.6.0" + } + }, "diffie-hellman": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", @@ -3422,6 +4084,32 @@ "randombytes": "^2.0.0" } }, + "dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "dev": true, + "requires": { + "path-type": "^3.0.0" + }, + "dependencies": { + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, "dns-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", @@ -3447,12 +4135,33 @@ "buffer-indexof": "^1.0.0" } }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "doctypes": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", + "integrity": "sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk=", + "dev": true + }, "domain-browser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", "dev": true }, + "duplexer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", + "dev": true + }, "duplexify": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", @@ -3568,6 +4277,18 @@ "is-arrayish": "^0.2.1" } }, + "es6-object-assign": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", + "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=", + "dev": true + }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, "es6-templates": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/es6-templates/-/es6-templates-0.2.3.tgz", @@ -3590,6 +4311,28 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, + "escodegen": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.12.0.tgz", + "integrity": "sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg==", + "dev": true, + "requires": { + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } + } + }, "eslint-scope": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", @@ -3621,6 +4364,12 @@ "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", "dev": true }, + "estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -3796,6 +4545,12 @@ } } }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, "extend-shallow": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", @@ -3817,6 +4572,17 @@ } } }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, "extglob": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", @@ -3900,12 +4666,32 @@ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", "dev": true }, + "fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", + "dev": true, + "requires": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + } + }, "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 }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, "fastparse": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.1.tgz", @@ -3936,6 +4722,15 @@ "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==", "dev": true }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, "file-loader": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-4.0.0.tgz", @@ -4015,6 +4810,12 @@ } } }, + "filesize": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz", + "integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==", + "dev": true + }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -4074,6 +4875,24 @@ "pinkie-promise": "^2.0.0" } }, + "findup": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/findup/-/findup-0.1.5.tgz", + "integrity": "sha1-itkpozk7rGJ5V6fl3kYjsGsOLOs=", + "dev": true, + "requires": { + "colors": "~0.6.0-1", + "commander": "~2.1.0" + }, + "dependencies": { + "commander": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz", + "integrity": "sha1-0SG7roYNmZKj1Re6lvVliOR8Z4E=", + "dev": true + } + } + }, "findup-sync": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", @@ -4166,34 +4985,78 @@ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", "dev": true }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", - "dev": true - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "dev": true - }, - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "fork-ts-checker-webpack-plugin": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-1.5.0.tgz", + "integrity": "sha512-zEhg7Hz+KhZlBhILYpXy+Beu96gwvkROWJiTXOCyOOMMrdBIRPvsBpBqgTI4jfJGrJXcqGwJR8zsBGDmzY0jsA==", "dev": true, "requires": { - "inherits": "^2.0.1", + "babel-code-frame": "^6.22.0", + "chalk": "^2.4.1", + "chokidar": "^2.0.4", + "micromatch": "^3.1.10", + "minimatch": "^3.0.4", + "semver": "^5.6.0", + "tapable": "^1.0.0", + "worker-rpc": "^0.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", "readable-stream": "^2.0.0" } }, @@ -4265,12 +5128,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -4290,7 +5155,8 @@ "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", @@ -4438,6 +5304,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -4778,6 +5645,12 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, + "function.name-polyfill": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/function.name-polyfill/-/function.name-polyfill-1.0.6.tgz", + "integrity": "sha512-ejQivNFbBPTY5O/waFta6D5AzV8GJiM/fMDaT6LrsYax1cb4eipxuQqKNlugF2jlcXIjifsqvju3wsgV35TELg==", + "dev": true + }, "gauge": { "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", @@ -4809,6 +5682,12 @@ "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", "dev": true }, + "get-own-enumerable-property-symbols": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.1.tgz", + "integrity": "sha512-09/VS4iek66Dh2bctjRkowueRJbY1JDGR1L/zRxO1Qk8Uxs6PnqaNSqalpizPT+CDjre3hnEsuzvhgomz9qYrA==", + "dev": true + }, "get-stdin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", @@ -4839,6 +5718,23 @@ "assert-plus": "^1.0.0" } }, + "github-slugger": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.2.1.tgz", + "integrity": "sha512-SsZUjg/P03KPzQBt7OxJPasGw6NRO5uOgiZ5RGXVud5iSIZ0eNZeNp5rTwCxtavrRUa/A77j8mePVc5lEvk0KQ==", + "dev": true, + "requires": { + "emoji-regex": ">=6.0.0 <=6.1.1" + }, + "dependencies": { + "emoji-regex": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.1.1.tgz", + "integrity": "sha1-xs0OwbBkLio8Z6ETfvxeeW2k+I4=", + "dev": true + } + } + }, "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", @@ -4874,6 +5770,12 @@ } } }, + "glob-to-regexp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", + "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", + "dev": true + }, "global-modules": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", @@ -4939,6 +5841,25 @@ "minimatch": "~3.0.2" } }, + "glogg": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", + "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", + "dev": true, + "requires": { + "sparkles": "^1.0.0" + } + }, + "good-listener": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", + "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", + "dev": true, + "optional": true, + "requires": { + "delegate": "^3.1.2" + } + }, "goodish": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/goodish/-/goodish-0.0.7.tgz", @@ -4960,6 +5881,24 @@ "chance": "^1.0.18" } }, + "gzip-size": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.0.0.tgz", + "integrity": "sha512-5iI7omclyqrnWw4XbXAmGhPsABkSIDQonv2K0h61lybgofWa6iZyvrI3r2zsJH4P8Nb64fFVzlvfhs0g7BBxAA==", + "dev": true, + "requires": { + "duplexer": "^0.1.1", + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, "handle-thing": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.0.tgz", @@ -5264,6 +6203,12 @@ "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", "dev": true }, + "hyphenate-style-name": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.3.tgz", + "integrity": "sha512-EcuixamT82oplpoJ2XU4pDtKGWQ7b00CD9f1ug9IaQ3p1bkHMiKCZ9ut9QDI6qsa6cpUuB+A/I+zLtdNK4n2DQ==", + "dev": true + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -5299,6 +6244,18 @@ "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", "dev": true }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "immer": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/immer/-/immer-1.10.0.tgz", + "integrity": "sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg==", + "dev": true + }, "import-local": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", @@ -5364,6 +6321,99 @@ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true }, + "inquirer": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.1.tgz", + "integrity": "sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg==", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.0", + "figures": "^2.0.0", + "lodash": "^4.17.10", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.1.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.0.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } + } + } + } + }, "internal-ip": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", @@ -5428,6 +6478,28 @@ "kind-of": "^3.0.2" } }, + "is-alphabetical": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.3.tgz", + "integrity": "sha512-eEMa6MKpHFzw38eKm56iNNi6GJ7lf6aLLio7Kr23sJPAECscgRtZvOBYybejWDQ2bM949Y++61PY+udzj5QMLA==", + "dev": true + }, + "is-alphanumeric": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-alphanumeric/-/is-alphanumeric-1.0.0.tgz", + "integrity": "sha1-Spzvcdr0wAHB2B1j0UDPU/1oifQ=", + "dev": true + }, + "is-alphanumerical": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.3.tgz", + "integrity": "sha512-A1IGAPO5AW9vSh7omxIlOGwIqEvpW/TA+DksVOPM5ODuxKlZS09+TEM1E3275lJqO2oJ38vDpeAL3DCIiHE6eA==", + "dev": true, + "requires": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + } + }, "is-arguments": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", @@ -5479,6 +6551,12 @@ "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", "dev": true }, + "is-decimal": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.3.tgz", + "integrity": "sha512-bvLSwoDg2q6Gf+E2LEPiklHZxxiSi3XAh4Mav65mKqTfCO1HM3uBs24TjEH8iJX3bbDdLXKJXBTmGzuTUuAEjQ==", + "dev": true + }, "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", @@ -5498,6 +6576,30 @@ } } }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, + "is-expression": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-3.0.0.tgz", + "integrity": "sha1-Oayqa+f9HzRx3ELHQW5hwkMXrJ8=", + "dev": true, + "requires": { + "acorn": "~4.0.2", + "object-assign": "^4.0.1" + }, + "dependencies": { + "acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", + "dev": true + } + } + }, "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", @@ -5537,6 +6639,18 @@ "is-extglob": "^2.1.1" } }, + "is-hexadecimal": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.3.tgz", + "integrity": "sha512-zxQ9//Q3D/34poZf8fiy3m3XVpbQc7ren15iKqrTtLPwkPD/t3Scy9Imp63FujULGxuK0ZlCwoo5xNpktFgbOA==", + "dev": true + }, + "is-in-browser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", + "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=", + "dev": true + }, "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", @@ -5546,6 +6660,12 @@ "kind-of": "^3.0.2" } }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true + }, "is-path-cwd": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", @@ -5593,6 +6713,12 @@ } } }, + "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 + }, "is-regex": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", @@ -5602,6 +6728,18 @@ "has": "^1.0.1" } }, + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", + "dev": true + }, + "is-root": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.0.0.tgz", + "integrity": "sha512-F/pJIk8QD6OX5DNhRB7hWamLsUilmkDGho48KbgZ6xg/lmAZXHxzXQ91jzB3yRSw5kdQGGGc4yz8HYhTYIMWPg==", + "dev": true + }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", @@ -5620,12 +6758,24 @@ "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", "dev": true }, + "is-whitespace-character": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.3.tgz", + "integrity": "sha512-SNPgMLz9JzPccD3nPctcj8sZlX9DAMJSKH8bP7Z6bohCwuNgX8xbWr1eTAYXX9Vpi/aSn8Y1akL9WgM3t43YNQ==", + "dev": true + }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true }, + "is-word-character": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.3.tgz", + "integrity": "sha512-0wfcrFgOOOBdgRNT9H33xe6Zi6yhX/uoc4U8NBZGeQQB0ctU1dnlNTyL9JM2646bHDTpsDm1Brb3VPoCIMrd/A==", + "dev": true + }, "is-wsl": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", @@ -5656,6 +6806,12 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "dev": true }, + "javascript-stringify": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-1.6.0.tgz", + "integrity": "sha1-FC0RHzpuPa6PSpr9d9RYVbWpzOM=", + "dev": true + }, "jquery": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.4.1.tgz", @@ -5678,6 +6834,12 @@ "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", "dev": true }, + "js-stringify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", + "integrity": "sha1-Fzb939lyTyijaCrcYjCufk6Weds=", + "dev": true + }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -5737,6 +6899,12 @@ "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 + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -5749,21 +6917,102 @@ "verror": "1.10.0" } }, - "killable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", - "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "jss": { + "version": "9.8.7", + "resolved": "https://registry.npmjs.org/jss/-/jss-9.8.7.tgz", + "integrity": "sha512-awj3XRZYxbrmmrx9LUSj5pXSUfm12m8xzi/VKeqI1ZwWBtQ0kVPTs3vYs32t4rFw83CgFDukA8wKzOE9sMQnoQ==", + "dev": true, + "requires": { + "is-in-browser": "^1.1.3", + "symbol-observable": "^1.1.0", + "warning": "^3.0.0" + } + }, + "jss-camel-case": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jss-camel-case/-/jss-camel-case-6.1.0.tgz", + "integrity": "sha512-HPF2Q7wmNW1t79mCqSeU2vdd/vFFGpkazwvfHMOhPlMgXrJDzdj9viA2SaHk9ZbD5pfL63a8ylp4++irYbbzMQ==", + "dev": true, + "requires": { + "hyphenate-style-name": "^1.0.2" + } + }, + "jss-compose": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/jss-compose/-/jss-compose-5.0.0.tgz", + "integrity": "sha512-YofRYuiA0+VbeOw0VjgkyO380sA4+TWDrW52nSluD9n+1FWOlDzNbgpZ/Sb3Y46+DcAbOS21W5jo6SAqUEiuwA==", + "dev": true, + "requires": { + "warning": "^3.0.0" + } + }, + "jss-default-unit": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/jss-default-unit/-/jss-default-unit-8.0.2.tgz", + "integrity": "sha512-WxNHrF/18CdoAGw2H0FqOEvJdREXVXLazn7PQYU7V6/BWkCV0GkmWsppNiExdw8dP4TU1ma1dT9zBNJ95feLmg==", + "dev": true + }, + "jss-global": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/jss-global/-/jss-global-3.0.0.tgz", + "integrity": "sha512-wxYn7vL+TImyQYGAfdplg7yaxnPQ9RaXY/cIA8hawaVnmmWxDHzBK32u1y+RAvWboa3lW83ya3nVZ/C+jyjZ5Q==", + "dev": true + }, + "jss-isolate": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/jss-isolate/-/jss-isolate-5.1.0.tgz", + "integrity": "sha512-8OVa/SObXRMaKvFeCqzpDOZY8So4fAcTH0K6LsITiYpEQNABICSx1NCmubnt/JbPQaqnnQsF5F47uG86uQ9ZRA==", + "dev": true, + "requires": { + "css-initials": "^0.2.0" + } + }, + "jss-nested": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/jss-nested/-/jss-nested-6.0.1.tgz", + "integrity": "sha512-rn964TralHOZxoyEgeq3hXY8hyuCElnvQoVrQwKHVmu55VRDd6IqExAx9be5HgK0yN/+hQdgAXQl/GUrBbbSTA==", + "dev": true, + "requires": { + "warning": "^3.0.0" + } + }, + "jstransformer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", + "integrity": "sha1-7Yvwkh4vPx7U1cGkT2hwntJHIsM=", + "dev": true, + "requires": { + "is-promise": "^2.0.0", + "promise": "^7.0.1" + } + }, + "killable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { "is-buffer": "^1.1.5" } }, + "kleur": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-2.0.2.tgz", + "integrity": "sha512-77XF9iTllATmG9lSlIv0qdQ2BQ/h9t0bJllHlbvsQ0zUWfU7Yi0S8L5JXzPZgkefIiajLmBJJ4BsMJmqcf7oxQ==", + "dev": true + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true + }, "lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", @@ -5773,6 +7022,28 @@ "invert-kv": "^1.0.0" } }, + "leven": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", + "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "listify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/listify/-/listify-1.0.0.tgz", + "integrity": "sha1-A8p7otFQ1CZ3c/dOV1WNEFPSvuM=", + "dev": true + }, "livereload-js": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.4.0.tgz", @@ -5838,12 +7109,55 @@ "integrity": "sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=", "dev": true }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } + } + }, "loglevel": { "version": "1.6.4", "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.4.tgz", "integrity": "sha512-p0b6mOGKcGa+7nnmKbpzR6qloPbrgLcnio++E+14Vo/XffOGwZtRpUhr8dTH/x2oCMmEoIU0Zwm3ZauhvYD17g==", "dev": true }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true + }, + "longest-streak": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.3.tgz", + "integrity": "sha512-9lz5IVdpwsKLMzQi0MQ+oD9EA0mIGcWYP7jXMTZVXP8D42PwuAk+M/HBFYQoxt1G5OR8m7aSIgb1UymfWGBWEw==", + "dev": true + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -5869,6 +7183,12 @@ "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", "dev": true }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, "lru-cache": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", @@ -5879,6 +7199,15 @@ "yallist": "^2.1.2" } }, + "magic-string": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.4.tgz", + "integrity": "sha512-oycWO9nEVAP2RVPbIoDoA4Y7LFIJ3xRYov93gAyJhZkET1tNuB0u7uWkZS2LpBWTJUWnmau/To8ECWRC+jKNfw==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, "make-dir": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", @@ -5939,6 +7268,28 @@ "object-visit": "^1.0.0" } }, + "markdown-escapes": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.3.tgz", + "integrity": "sha512-XUi5HJhhV5R74k8/0H2oCbCiYf/u4cO/rX8tnGkRvrqhsr5BRNU6Mg0yt/8UIx1iIS8220BNJsDb7XnILhLepw==", + "dev": true + }, + "markdown-table": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz", + "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==", + "dev": true + }, + "markdown-to-jsx": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-6.10.3.tgz", + "integrity": "sha512-PSoUyLnW/xoW6RsxZrquSSz5eGEOTwa15H5eqp3enmrp8esmgDJmhzd6zmQ9tgAA9TxJzx1Hmf3incYU/IamoQ==", + "dev": true, + "requires": { + "prop-types": "^15.6.2", + "unquote": "^1.1.0" + } + }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -5958,6 +7309,15 @@ } } }, + "mdast-util-compact": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-compact/-/mdast-util-compact-1.0.3.tgz", + "integrity": "sha512-nRiU5GpNy62rZppDKbLwhhtw5DXoFMqw9UNZFmlPsNaQCZ//WLjGKUwWMdJrUH+Se7UvtO2gXtAMe0g/N+eI5w==", + "dev": true, + "requires": { + "unist-util-visit": "^1.1.0" + } + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -6034,12 +7394,24 @@ } } }, + "merge2": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz", + "integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==", + "dev": true + }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", "dev": true }, + "microevent.ts": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/microevent.ts/-/microevent.ts-0.1.1.tgz", + "integrity": "sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g==", + "dev": true + }, "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", @@ -6131,6 +7503,15 @@ } } }, + "mini-html-webpack-plugin": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/mini-html-webpack-plugin/-/mini-html-webpack-plugin-0.2.3.tgz", + "integrity": "sha512-wfkLf+CmyDg++K1S0QdAvUvS29DfVHe9SQ63syX8aX375mInzC5uwHxb/1+3exiiv84xnPrf6zsOnReRe15rjg==", + "dev": true, + "requires": { + "webpack-sources": "^1.1.0" + } + }, "minimalistic-assert": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz", @@ -6271,6 +7652,12 @@ "run-queue": "^1.0.3" } }, + "mri": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.4.tgz", + "integrity": "sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w==", + "dev": true + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -6293,6 +7680,12 @@ "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", "dev": true }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -6391,6 +7784,15 @@ "lower-case": "^1.1.1" } }, + "node-dir": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", + "integrity": "sha1-X1Zl2TNRM1yqvvjxxVRRbPXx5OU=", + "dev": true, + "requires": { + "minimatch": "^3.0.2" + } + }, "node-forge": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz", @@ -6716,6 +8118,32 @@ "wrappy": "1" } }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + }, + "dependencies": { + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + } + } + }, + "open": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz", + "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + } + }, "opn": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", @@ -6725,6 +8153,71 @@ "is-wsl": "^1.1.0" } }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + } + }, + "ora": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-2.1.0.tgz", + "integrity": "sha512-hNNlAd3gfv/iPmsNxYoAPLvxg7HuPozww7fFonMZvL84tP6Ox5igfk5j/+a9rtJJwqMgKK+JgWsAQik5o0HTLA==", + "dev": true, + "requires": { + "chalk": "^2.3.1", + "cli-cursor": "^2.1.0", + "cli-spinners": "^1.1.0", + "log-symbols": "^2.2.0", + "strip-ansi": "^4.0.0", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, "original": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", @@ -6868,6 +8361,20 @@ "safe-buffer": "^5.1.1" } }, + "parse-entities": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-1.2.2.tgz", + "integrity": "sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg==", + "dev": true, + "requires": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + } + }, "parse-json": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", @@ -7023,6 +8530,66 @@ } } }, + "pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, "popper.js": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.15.0.tgz", @@ -7176,6 +8743,12 @@ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, "prepend-http": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", @@ -7188,6 +8761,15 @@ "integrity": "sha512-kn/GU6SMRYPxUakNXhpP0EedT/KmaPzr0H5lIsDogrykbaxOpOfAFfk5XA7DZrJyMAv1wlMV3CPcZruGXVVUZw==", "dev": true }, + "prismjs": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.17.1.tgz", + "integrity": "sha512-PrEDJAFdUGbOP6xK/UsfkC5ghJsPJviKgnQOoxaDbBjwc8op68Quupwt1DeAFoG8GImPhiKXAvvsH7wDSLsu1Q==", + "dev": true, + "requires": { + "clipboard": "^2.0.0" + } + }, "private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", @@ -7206,12 +8788,32 @@ "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", "dev": true }, - "promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dev": true, + "requires": { + "asap": "~2.0.3" + } + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", "dev": true }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "dev": true, + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, "proxy-addr": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", @@ -7259,124 +8861,1091 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true - } - } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "pumpify": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", - "dev": true, - "requires": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - }, - "dependencies": { - "pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + } + } + }, + "pug": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pug/-/pug-2.0.4.tgz", + "integrity": "sha512-XhoaDlvi6NIzL49nu094R2NA6P37ijtgMDuWE+ofekDChvfKnzFal60bhSdiy8y2PBO6fmz3oMEIcfpBVRUdvw==", + "dev": true, + "requires": { + "pug-code-gen": "^2.0.2", + "pug-filters": "^3.1.1", + "pug-lexer": "^4.1.0", + "pug-linker": "^3.0.6", + "pug-load": "^2.0.12", + "pug-parser": "^5.0.1", + "pug-runtime": "^2.0.5", + "pug-strip-comments": "^1.0.4" + } + }, + "pug-attrs": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-2.0.4.tgz", + "integrity": "sha512-TaZ4Z2TWUPDJcV3wjU3RtUXMrd3kM4Wzjbe3EWnSsZPsJ3LDI0F3yCnf2/W7PPFF+edUFQ0HgDL1IoxSz5K8EQ==", + "dev": true, + "requires": { + "constantinople": "^3.0.1", + "js-stringify": "^1.0.1", + "pug-runtime": "^2.0.5" + } + }, + "pug-code-gen": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-2.0.2.tgz", + "integrity": "sha512-kROFWv/AHx/9CRgoGJeRSm+4mLWchbgpRzTEn8XCiwwOy6Vh0gAClS8Vh5TEJ9DBjaP8wCjS3J6HKsEsYdvaCw==", + "dev": true, + "requires": { + "constantinople": "^3.1.2", + "doctypes": "^1.1.0", + "js-stringify": "^1.0.1", + "pug-attrs": "^2.0.4", + "pug-error": "^1.3.3", + "pug-runtime": "^2.0.5", + "void-elements": "^2.0.1", + "with": "^5.0.0" + } + }, + "pug-error": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-1.3.3.tgz", + "integrity": "sha512-qE3YhESP2mRAWMFJgKdtT5D7ckThRScXRwkfo+Erqga7dyJdY3ZquspprMCj/9sJ2ijm5hXFWQE/A3l4poMWiQ==", + "dev": true + }, + "pug-filters": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-3.1.1.tgz", + "integrity": "sha512-lFfjNyGEyVWC4BwX0WyvkoWLapI5xHSM3xZJFUhx4JM4XyyRdO8Aucc6pCygnqV2uSgJFaJWW3Ft1wCWSoQkQg==", + "dev": true, + "requires": { + "clean-css": "^4.1.11", + "constantinople": "^3.0.1", + "jstransformer": "1.0.0", + "pug-error": "^1.3.3", + "pug-walk": "^1.1.8", + "resolve": "^1.1.6", + "uglify-js": "^2.6.1" + } + }, + "pug-lexer": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-4.1.0.tgz", + "integrity": "sha512-i55yzEBtjm0mlplW4LoANq7k3S8gDdfC6+LThGEvsK4FuobcKfDAwt6V4jKPH9RtiE3a2Akfg5UpafZ1OksaPA==", + "dev": true, + "requires": { + "character-parser": "^2.1.1", + "is-expression": "^3.0.0", + "pug-error": "^1.3.3" + } + }, + "pug-linker": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-3.0.6.tgz", + "integrity": "sha512-bagfuHttfQOpANGy1Y6NJ+0mNb7dD2MswFG2ZKj22s8g0wVsojpRlqveEQHmgXXcfROB2RT6oqbPYr9EN2ZWzg==", + "dev": true, + "requires": { + "pug-error": "^1.3.3", + "pug-walk": "^1.1.8" + } + }, + "pug-load": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-2.0.12.tgz", + "integrity": "sha512-UqpgGpyyXRYgJs/X60sE6SIf8UBsmcHYKNaOccyVLEuT6OPBIMo6xMPhoJnqtB3Q3BbO4Z3Bjz5qDsUWh4rXsg==", + "dev": true, + "requires": { + "object-assign": "^4.1.0", + "pug-walk": "^1.1.8" + } + }, + "pug-parser": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-5.0.1.tgz", + "integrity": "sha512-nGHqK+w07p5/PsPIyzkTQfzlYfuqoiGjaoqHv1LjOv2ZLXmGX1O+4Vcvps+P4LhxZ3drYSljjq4b+Naid126wA==", + "dev": true, + "requires": { + "pug-error": "^1.3.3", + "token-stream": "0.0.1" + } + }, + "pug-runtime": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-2.0.5.tgz", + "integrity": "sha512-P+rXKn9un4fQY77wtpcuFyvFaBww7/91f3jHa154qU26qFAnOe6SW1CbIDcxiG5lLK9HazYrMCCuDvNgDQNptw==", + "dev": true + }, + "pug-strip-comments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-1.0.4.tgz", + "integrity": "sha512-i5j/9CS4yFhSxHp5iKPHwigaig/VV9g+FgReLJWWHEHbvKsbqL0oP/K5ubuLco6Wu3Kan5p7u7qk8A4oLLh6vw==", + "dev": true, + "requires": { + "pug-error": "^1.3.3" + } + }, + "pug-walk": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-1.1.8.tgz", + "integrity": "sha512-GMu3M5nUL3fju4/egXwZO0XLi6fW/K3T3VTgFQ14GxNi8btlxgT5qZL//JwZFm/2Fa64J/PNS8AZeys3wiMkVA==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "q-i": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/q-i/-/q-i-2.0.1.tgz", + "integrity": "sha512-tr7CzPNxkBDBuPzqi/HDUS4uBOppb91akNTeh56TYio8TiIeXp2Yp8ea9NmDu2DmGH35ZjJDq6C3E4SepVZ4bQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "is-plain-object": "^2.0.4", + "stringify-object": "^3.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + } + } + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true + }, + "qss": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/qss/-/qss-2.0.3.tgz", + "integrity": "sha512-j48ZBT5IZbSqJiSU8EX4XrN8nXiflHvmMvv2XpFc31gh7n6EpSs75bNr6+oj3FOLWyT8m09pTmqLNl34L7/uPQ==", + "dev": true + }, + "query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "dev": true, + "requires": { + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true + }, + "querystringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", + "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "dev": true + } + } + }, + "react": { + "version": "16.10.2", + "resolved": "https://registry.npmjs.org/react/-/react-16.10.2.tgz", + "integrity": "sha512-MFVIq0DpIhrHFyqLU0S3+4dIcBhhOvBE8bJ/5kHPVOVaGdo0KuiQzpcjCPsf585WvhypqtrMILyoE2th6dT+Lw==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2" + } + }, + "react-codemirror2": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-codemirror2/-/react-codemirror2-5.1.0.tgz", + "integrity": "sha512-Cksbgbviuf2mJfMyrKmcu7ycK6zX/ukuQO8dvRZdFWqATf5joalhjFc6etnBdGCcPA2LbhIwz+OPnQxLN/j1Fw==", + "dev": true + }, + "react-dev-utils": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-7.0.5.tgz", + "integrity": "sha512-zJnqqb0x6gd63E3xoz5pXAxBPNaW75Hyz7GgQp0qPhMroBCRQtRvG67AoTZZY1z4yCYVJQZAfQJFdnea0Ujbug==", + "dev": true, + "requires": { + "@babel/code-frame": "7.0.0", + "address": "1.0.3", + "browserslist": "4.4.1", + "chalk": "2.4.2", + "cross-spawn": "6.0.5", + "detect-port-alt": "1.1.6", + "escape-string-regexp": "1.0.5", + "filesize": "3.6.1", + "find-up": "3.0.0", + "global-modules": "2.0.0", + "globby": "8.0.2", + "gzip-size": "5.0.0", + "immer": "1.10.0", + "inquirer": "6.2.1", + "is-root": "2.0.0", + "loader-utils": "1.2.3", + "opn": "5.4.0", + "pkg-up": "2.0.0", + "react-error-overlay": "^5.1.4", + "recursive-readdir": "2.2.2", + "shell-quote": "1.6.1", + "sockjs-client": "1.3.0", + "strip-ansi": "5.0.0", + "text-table": "0.2.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", + "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "dir-glob": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", + "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "path-type": "^3.0.0" + } + }, + "faye-websocket": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz", + "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "globby": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", + "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "2.0.0", + "fast-glob": "^2.0.2", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + } + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "opn": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.4.0.tgz", + "integrity": "sha512-YF9MNdVy/0qvJvDtunAOzFw9iasOQHpVthTCvGzxt61Il64AYSGdK+rYwld7NAfk9qJ7dt+hymBNSc9LNYS+Sw==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "sockjs-client": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.3.0.tgz", + "integrity": "sha512-R9jxEzhnnrdxLCNln0xg5uGHqMnkhPSTzUZH2eXcR03S/On9Yvoq2wyUZILRUhZCNVu2PmwWVoyuiPz8th8zbg==", + "dev": true, + "requires": { + "debug": "^3.2.5", + "eventsource": "^1.0.7", + "faye-websocket": "~0.11.1", + "inherits": "^2.0.3", + "json3": "^3.3.2", + "url-parse": "^1.4.3" + } + }, + "strip-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz", + "integrity": "sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow==", + "dev": true, + "requires": { + "ansi-regex": "^4.0.0" + } + } + } + }, + "react-docgen": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-4.1.1.tgz", + "integrity": "sha512-o1wdswIxbgJRI4pckskE7qumiFyqkbvCO++TylEDOo2RbMiueIOg8YzKU4X9++r0DjrbXePw/LHnh81GRBTWRw==", + "dev": true, + "requires": { + "@babel/core": "^7.0.0", + "@babel/runtime": "^7.0.0", + "async": "^2.1.4", + "commander": "^2.19.0", + "doctrine": "^3.0.0", + "node-dir": "^0.1.10", + "recast": "^0.17.3" + }, + "dependencies": { + "ast-types": { + "version": "0.12.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.12.4.tgz", + "integrity": "sha512-ky/YVYCbtVAS8TdMIaTiPFHwEpRB5z1hctepJplTr3UW5q8TDrpIMCILyk8pmLxGtn2KCtC/lSn7zOsaI7nzDw==", + "dev": true + }, + "commander": { + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.1.tgz", + "integrity": "sha512-cCuLsMhJeWQ/ZpsFTbE765kvVfoeSddc4nU3up4fV+fDBcfUXnbITJ+JzhkdjzOqhURjZgujxaioam4RM9yGUg==", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "recast": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.17.6.tgz", + "integrity": "sha512-yoQRMRrK1lszNtbkGyM4kN45AwylV5hMiuEveUBlxytUViWevjvX6w+tzJt1LH4cfUhWt4NZvy3ThIhu6+m5wQ==", + "dev": true, + "requires": { + "ast-types": "0.12.4", + "esprima": "~4.0.0", + "private": "^0.1.8", + "source-map": "~0.6.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "react-docgen-annotation-resolver": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/react-docgen-annotation-resolver/-/react-docgen-annotation-resolver-1.1.0.tgz", + "integrity": "sha512-wTUI7IqWkV+BNRmEh1eHkU+Ijwh0XcFUdbgktynWVqe++MgtovdlbfMehFAw5b49mv8NN2DK0NF/G8x+UdIyNw==", + "dev": true + }, + "react-docgen-displayname-handler": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/react-docgen-displayname-handler/-/react-docgen-displayname-handler-2.1.3.tgz", + "integrity": "sha512-XfQCjDC/8hy0rDZ+VudYplQCdp/fx3z7Ffp22+6s2MSbZ2I/1yw4Tn+ntxkUgI0hrQzB6Nidg/wzLpA5Dbj+xg==", + "dev": true, + "requires": { + "ast-types": "0.13.2" + }, + "dependencies": { + "ast-types": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.2.tgz", + "integrity": "sha512-uWMHxJxtfj/1oZClOxDEV1sQ1HCDkA4MG8Gr69KKeBjEVH0R84WlejZ0y2DcwyBlpAEMltmVYkVgqfLFb2oyiA==", + "dev": true + } + } + }, + "react-dom": { + "version": "16.10.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.10.2.tgz", + "integrity": "sha512-kWGDcH3ItJK4+6Pl9DZB16BXYAZyrYQItU4OMy0jAkv5aNqc+mAKb4TpFtAteI6TJZu+9ZlNhaeNQSVQDHJzkw==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.16.2" + } + }, + "react-error-overlay": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-5.1.6.tgz", + "integrity": "sha512-X1Y+0jR47ImDVr54Ab6V9eGk0Hnu7fVWGeHQSOXHf/C2pF9c6uy3gef8QUeuUiWlNb0i08InPSE5a/KJzNzw1Q==", + "dev": true + }, + "react-group": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/react-group/-/react-group-1.0.6.tgz", + "integrity": "sha1-jdfADDs10FzhZAIUWLsH1YDjABo=", + "dev": true, + "requires": { + "prop-types": "^15.6.0" + } + }, + "react-icons": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-3.7.0.tgz", + "integrity": "sha512-7MyPwjIhuyW0D2N3s4DEd0hGPGFf0sK+IIRKhc1FvSpZNVmnUoGvHbmAwzGJU+3my+fvihVWgwU5SDtlAri56Q==", + "dev": true, + "requires": { + "camelcase": "^5.0.0" + } + }, + "react-is": { + "version": "16.10.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.10.2.tgz", + "integrity": "sha512-INBT1QEgtcCCgvccr5/86CfD71fw9EPmDxgiJX4I2Ddr6ZsV6iFXsuby+qWJPtmNuMY0zByTsG4468P7nHuNWA==", + "dev": true + }, + "react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==", + "dev": true + }, + "react-simple-code-editor": { + "version": "0.9.15", + "resolved": "https://registry.npmjs.org/react-simple-code-editor/-/react-simple-code-editor-0.9.15.tgz", + "integrity": "sha512-M8iKgjBTBZK92tZYgOEfMuR7c3zZ0q0v3QYllSxIPx3SU+w003VofH50txXQSBTu92pSOm2tidON1HbQ1l8BDA==", + "dev": true + }, + "react-styleguidist": { + "version": "9.1.16", + "resolved": "https://registry.npmjs.org/react-styleguidist/-/react-styleguidist-9.1.16.tgz", + "integrity": "sha512-F9EQx92jIRI/u36kT8XNitMLaFWIJvh4WHvt0EDl7eoVz2UUB+URxqq2Gn3w50bc5mjanzSeqJAfxMR17wSAng==", + "dev": true, + "requires": { + "@vxna/mini-html-webpack-template": "^0.1.7", + "acorn": "^6.1.1", + "acorn-jsx": "^5.0.1", + "ast-types": "^0.12.2", + "buble": "0.19.7", + "clean-webpack-plugin": "^1.0.1", + "clipboard-copy": "^3.0.0", + "clsx": "^1.0.3", + "common-dir": "^2.0.2", + "copy-webpack-plugin": "^4.6.0", + "core-js": "^3.0.0", + "doctrine": "^3.0.0", + "es6-object-assign": "~1.1.0", + "es6-promise": "^4.2.6", + "escodegen": "^1.11.1", + "estree-walker": "^0.6.0", + "findup": "^0.1.5", + "function.name-polyfill": "^1.0.6", + "github-slugger": "^1.2.1", + "glob": "^7.1.3", + "glogg": "^1.0.2", + "is-directory": "^0.3.1", + "javascript-stringify": "^1.6.0", + "jss": "^9.8.7", + "jss-camel-case": "^6.1.0", + "jss-compose": "^5.0.0", + "jss-default-unit": "^8.0.2", + "jss-global": "^3.0.0", + "jss-isolate": "^5.1.0", + "jss-nested": "^6.0.1", + "kleur": "^3.0.2", + "leven": "^2.1.0", + "listify": "^1.0.0", + "loader-utils": "^1.2.3", + "lodash": "^4.17.11", + "lowercase-keys": "^1.0.1", + "markdown-to-jsx": "^6.9.3", + "mini-html-webpack-plugin": "^0.2.3", + "mri": "^1.1.4", + "ora": "^3.2.0", + "prismjs": "^1.16.0", + "prop-types": "^15.7.2", + "q-i": "^2.0.1", + "qss": "^2.0.3", + "react-dev-utils": "^9.0.3", + "react-docgen": "^4.1.0", + "react-docgen-annotation-resolver": "^1.0.0", + "react-docgen-displayname-handler": "^2.1.1", + "react-group": "^3.0.0", + "react-icons": "^3.7.0", + "react-lifecycles-compat": "^3.0.4", + "react-simple-code-editor": "^0.9.7", + "recast": "^0.17.4", + "remark": "^10.0.1", + "rewrite-imports": "1.2.0", + "strip-html-comments": "^1.0.0", + "terser-webpack-plugin": "^1.2.3", + "to-ast": "^1.0.0", + "type-detect": "^4.0.8", + "unist-util-visit": "^1.4.0", + "webpack-dev-server": "^3.2.1", + "webpack-merge": "^4.2.1" + }, + "dependencies": { + "address": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.1.2.tgz", + "integrity": "sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==", + "dev": true + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "ast-types": { + "version": "0.12.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.12.4.tgz", + "integrity": "sha512-ky/YVYCbtVAS8TdMIaTiPFHwEpRB5z1hctepJplTr3UW5q8TDrpIMCILyk8pmLxGtn2KCtC/lSn7zOsaI7nzDw==", + "dev": true + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "browserslist": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.7.0.tgz", + "integrity": "sha512-9rGNDtnj+HaahxiVV38Gn8n8Lr8REKsel68v1sPFfIGEK6uSXTY3h9acgiT1dZVtOOUtifo/Dn8daDQ5dUgVsA==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000989", + "electron-to-chromium": "^1.3.247", + "node-releases": "^1.1.29" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "clean-webpack-plugin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/clean-webpack-plugin/-/clean-webpack-plugin-1.0.1.tgz", + "integrity": "sha512-gvwfMsqu3HBgTVvaBa1H3AZKO03CHpr5uP92SPIktP3827EovAitwW+1xoqXyTxCuXnLYpMHG5ytS4AoukHDWA==", + "dev": true, + "requires": { + "rimraf": "^2.6.1" + } + }, + "cli-spinners": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.2.0.tgz", + "integrity": "sha512-tgU3fKwzYjiLEQgPMD9Jt+JjHVL9kW93FiIMX/l7rivvOD4/LL0Mf7gda3+4U2KJBloybwgj5KEoQgGRioMiKQ==", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "dir-glob": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", + "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "path-type": "^3.0.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "globby": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", + "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "2.0.0", + "fast-glob": "^2.0.2", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + } + }, + "gzip-size": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz", + "integrity": "sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==", + "dev": true, + "requires": { + "duplexer": "^0.1.1", + "pify": "^4.0.1" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, + "inquirer": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.0.tgz", + "integrity": "sha512-scfHejeG/lVZSpvCXpsB4j/wQNPM5JC8kiElOI0OUTwmc1RTpXr4H32/HOlQHcZiYl2z2VElwuCVDRG8vFmbnA==", + "dev": true, + "requires": { + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.12", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-root": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", + "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "ora": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-3.4.0.tgz", + "integrity": "sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==", "dev": true, "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-spinners": "^2.0.0", + "log-symbols": "^2.2.0", + "strip-ansi": "^5.2.0", + "wcwidth": "^1.0.1" } - } - } - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - }, - "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", - "dev": true - }, - "query-string": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", - "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", - "dev": true, - "requires": { - "object-assign": "^4.1.0", - "strict-uri-encode": "^1.0.0" - } - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "dev": true - }, - "querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", - "dev": true - }, - "querystringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", - "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==", - "dev": true - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "dev": true, - "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true - }, - "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "dev": true, - "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "dependencies": { - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "react-dev-utils": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-9.1.0.tgz", + "integrity": "sha512-X2KYF/lIGyGwP/F/oXgGDF24nxDA2KC4b7AFto+eqzc/t838gpSGiaU8trTqHXOohuLxxc5qi1eDzsl9ucPDpg==", + "dev": true, + "requires": { + "@babel/code-frame": "7.5.5", + "address": "1.1.2", + "browserslist": "4.7.0", + "chalk": "2.4.2", + "cross-spawn": "6.0.5", + "detect-port-alt": "1.1.6", + "escape-string-regexp": "1.0.5", + "filesize": "3.6.1", + "find-up": "3.0.0", + "fork-ts-checker-webpack-plugin": "1.5.0", + "global-modules": "2.0.0", + "globby": "8.0.2", + "gzip-size": "5.1.1", + "immer": "1.10.0", + "inquirer": "6.5.0", + "is-root": "2.1.0", + "loader-utils": "1.2.3", + "open": "^6.3.0", + "pkg-up": "2.0.0", + "react-error-overlay": "^6.0.3", + "recursive-readdir": "2.2.2", + "shell-quote": "1.7.2", + "sockjs-client": "1.4.0", + "strip-ansi": "5.2.0", + "text-table": "0.2.0" + } + }, + "react-error-overlay": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.3.tgz", + "integrity": "sha512-bOUvMWFQVk5oz8Ded9Xb7WVdEi3QGLC8tH7HmYP0Fdp4Bn3qw0tRFmr5TW6mvahzvmrK4a6bqWGfCevBflP+Xw==", + "dev": true + }, + "react-group": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/react-group/-/react-group-3.0.2.tgz", + "integrity": "sha512-0Jy99MD27jHSJ0PeynomUM0WArxywdcqQUKLttBWV6KYH+zlKWT/RhDwVxrODtMkRxf644BzuJFie1Hvfun7jA==", + "dev": true, + "requires": { + "prop-types": "^15.7.2" + } + }, + "recast": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.17.6.tgz", + "integrity": "sha512-yoQRMRrK1lszNtbkGyM4kN45AwylV5hMiuEveUBlxytUViWevjvX6w+tzJt1LH4cfUhWt4NZvy3ThIhu6+m5wQ==", + "dev": true, + "requires": { + "ast-types": "0.12.4", + "esprima": "~4.0.0", + "private": "^0.1.8", + "source-map": "~0.6.1" + } + }, + "rewrite-imports": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/rewrite-imports/-/rewrite-imports-1.2.0.tgz", + "integrity": "sha512-oVoZ3QImciK+S7I89vPyxDgohkwhJyWLP5EKcMvF2NOhaFkmdKFiJMJzTM35VeNV1gQfGvv9Cve6sMq5E7unHg==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "shell-quote": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", + "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } } } }, @@ -7439,6 +10008,15 @@ "source-map": "~0.5.0" } }, + "recursive-readdir": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", + "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", + "dev": true, + "requires": { + "minimatch": "3.0.4" + } + }, "redent": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", @@ -7449,6 +10027,12 @@ "strip-indent": "^1.0.1" } }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", + "dev": true + }, "regenerate-unicode-properties": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz", @@ -7497,12 +10081,105 @@ "define-properties": "^1.1.2" } }, + "regexpu-core": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.6.0.tgz", + "integrity": "sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg==", + "dev": true, + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.1.0", + "regjsgen": "^0.5.0", + "regjsparser": "^0.6.0", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.1.0" + } + }, + "regjsgen": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.0.tgz", + "integrity": "sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==", + "dev": true + }, + "regjsparser": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", + "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + } + } + }, "relateurl": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", "dev": true }, + "remark": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/remark/-/remark-10.0.1.tgz", + "integrity": "sha512-E6lMuoLIy2TyiokHprMjcWNJ5UxfGQjaMSMhV+f4idM625UjjK4j798+gPs5mfjzDE6vL0oFKVeZM6gZVSVrzQ==", + "dev": true, + "requires": { + "remark-parse": "^6.0.0", + "remark-stringify": "^6.0.0", + "unified": "^7.0.0" + } + }, + "remark-parse": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-6.0.3.tgz", + "integrity": "sha512-QbDXWN4HfKTUC0hHa4teU463KclLAnwpn/FBn87j9cKYJWWawbiLgMfP2Q4XwhxxuuuOxHlw+pSN0OKuJwyVvg==", + "dev": true, + "requires": { + "collapse-white-space": "^1.0.2", + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-whitespace-character": "^1.0.0", + "is-word-character": "^1.0.0", + "markdown-escapes": "^1.0.0", + "parse-entities": "^1.1.0", + "repeat-string": "^1.5.4", + "state-toggle": "^1.0.0", + "trim": "0.0.1", + "trim-trailing-lines": "^1.0.0", + "unherit": "^1.0.4", + "unist-util-remove-position": "^1.0.0", + "vfile-location": "^2.0.0", + "xtend": "^4.0.1" + } + }, + "remark-stringify": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-6.0.4.tgz", + "integrity": "sha512-eRWGdEPMVudijE/psbIDNcnJLRVx3xhfuEsTDGgH4GsFF91dVhw5nhmnBppafJ7+NWINW6C7ZwWbi30ImJzqWg==", + "dev": true, + "requires": { + "ccount": "^1.0.0", + "is-alphanumeric": "^1.0.0", + "is-decimal": "^1.0.0", + "is-whitespace-character": "^1.0.0", + "longest-streak": "^2.0.1", + "markdown-escapes": "^1.0.0", + "markdown-table": "^1.1.0", + "mdast-util-compact": "^1.0.0", + "parse-entities": "^1.0.2", + "repeat-string": "^1.5.4", + "state-toggle": "^1.0.0", + "stringify-entities": "^1.0.1", + "unherit": "^1.0.4", + "xtend": "^4.0.1" + } + }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -7530,6 +10207,12 @@ "is-finite": "^1.0.0" } }, + "replace-ext": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", + "dev": true + }, "request": { "version": "2.88.0", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", @@ -7746,6 +10429,16 @@ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", "dev": true }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", @@ -7758,6 +10451,21 @@ "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", "dev": true }, + "rewrite-imports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/rewrite-imports/-/rewrite-imports-2.0.3.tgz", + "integrity": "sha512-R7ICJEeP3y+d/q4C8YEJj9nRP0JyiSqG07uc0oQh8JvAe706dDFVL95GBZYCjADqmhArZWWjfM/5EcmVu4/B+g==", + "dev": true + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "dev": true, + "requires": { + "align-text": "^0.1.1" + } + }, "rimraf": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", @@ -7793,6 +10501,15 @@ "inherits": "^2.0.1" } }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, "run-queue": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", @@ -7807,6 +10524,15 @@ "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=" }, + "rxjs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", @@ -7924,6 +10650,16 @@ } } }, + "scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-BqYVWqwz6s1wZMhjFvLfVR5WXP7ZY32M/wYPo04CcuPM7XZEbV2TBNW7Z0UkguPTl0dWMA59VbNXxK6q+pHItg==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, "schema-utils": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", @@ -7980,6 +10716,13 @@ } } }, + "select": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", + "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=", + "dev": true, + "optional": true + }, "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -8178,12 +10921,30 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, + "shell-quote": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", + "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", + "dev": true, + "requires": { + "array-filter": "~0.0.0", + "array-map": "~0.0.0", + "array-reduce": "~0.0.0", + "jsonify": "~0.0.0" + } + }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -8382,6 +11143,18 @@ "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", "dev": true }, + "sourcemap-codec": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.6.tgz", + "integrity": "sha512-1ZooVLYFxC448piVLBbtOxFcXwnymH9oUF8nRd3CuYDVvkRBxRl6pB4Mtas5a4drtL+E8LDgFkQNcgIw6tc8Hg==", + "dev": true + }, + "sparkles": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", + "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", + "dev": true + }, "spdx-correct": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", @@ -8525,6 +11298,12 @@ "figgy-pudding": "^3.5.1" } }, + "state-toggle": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.2.tgz", + "integrity": "sha512-8LpelPGR0qQM4PnfLiplOQNJcIN1/r2Gy0xKB2zKnIW2YzPMt2sR4I/+gtPjhN7Svh9kw+zqEg2SFwpBO9iNiw==", + "dev": true + }, "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", @@ -8664,6 +11443,29 @@ "safe-buffer": "~5.1.0" } }, + "stringify-entities": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-1.3.2.tgz", + "integrity": "sha512-nrBAQClJAPN2p+uGCVJRPIPakKeKWZ9GtBCmormE7pWOSlHat7+x5A8gx85M7HM5Dt0BP3pP5RhVW77WdbJJ3A==", + "dev": true, + "requires": { + "character-entities-html4": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-hexadecimal": "^1.0.0" + } + }, + "stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dev": true, + "requires": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + } + }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", @@ -8688,6 +11490,12 @@ "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, + "strip-html-comments": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-html-comments/-/strip-html-comments-1.0.0.tgz", + "integrity": "sha1-Cuff8DAKYHWkwpP7YRG0yx0Mt7c=", + "dev": true + }, "strip-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", @@ -8716,6 +11524,12 @@ "has-flag": "^3.0.0" } }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", + "dev": true + }, "tapable": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", @@ -8964,6 +11778,12 @@ } } }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -9027,6 +11847,13 @@ "setimmediate": "^1.0.4" } }, + "tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", + "dev": true, + "optional": true + }, "tiny-lr": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz", @@ -9063,12 +11890,51 @@ "resolved": "https://registry.npmjs.org/tinymce/-/tinymce-4.1.3.tgz", "integrity": "sha1-ln2RUAueXBiZ8d/omRIkWL2AO+Q=" }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, "to-arraybuffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", "dev": true }, + "to-ast": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-ast/-/to-ast-1.0.0.tgz", + "integrity": "sha1-DEoxyMmO396arwGSx5S0yLEe4oc=", + "dev": true, + "requires": { + "ast-types": "^0.7.2", + "esprima": "^2.1.0" + }, + "dependencies": { + "ast-types": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.7.8.tgz", + "integrity": "sha1-kC0uDWDQcb3NRtwRXhgJ7RHBOKk=", + "dev": true + }, + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + } + } + }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", @@ -9117,6 +11983,18 @@ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", "dev": true }, + "token-stream": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-0.0.1.tgz", + "integrity": "sha1-zu78cXp2xDFvEm0LnbqlXX598Bo=", + "dev": true + }, + "trim": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", + "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=", + "dev": true + }, "trim-newlines": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", @@ -9129,6 +12007,18 @@ "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", "dev": true }, + "trim-trailing-lines": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.2.tgz", + "integrity": "sha512-MUjYItdrqqj2zpcHFTkMa9WAv4JHTI6gnRQGPFLrt5L9a6tRMiDnIqYl8JBvu2d2Tc3lWJKQwlGCp0K8AvCM+Q==", + "dev": true + }, + "trough": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.4.tgz", + "integrity": "sha512-tdzBRDGWcI1OpPVmChbdSKhvSVurznZ8X36AYURAcl+0o2ldlCY2XPzyXNNxwJwwyIU+rIglTCG4kxtNKBQH7Q==", + "dev": true + }, "true-case-path": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", @@ -9222,6 +12112,12 @@ } } }, + "ts-map": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-map/-/ts-map-1.0.3.tgz", + "integrity": "sha512-vDWbsl26LIcPGmDpoVzjEP6+hvHZkBkLW7JpvwbCv/5IYPJlsbzCVXY3wsCeAxAUeTclNOUZxnLdGh3VBD/J6w==", + "dev": true + }, "tslib": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", @@ -9249,6 +12145,21 @@ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "dev": true }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, "type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -9271,11 +12182,76 @@ "integrity": "sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg==", "dev": true }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "dev": true, + "requires": { + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" + }, + "dependencies": { + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "requires": { + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" + } + }, + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "requires": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" + } + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "dev": true, + "optional": true + }, "underscore": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" }, + "unherit": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.2.tgz", + "integrity": "sha512-W3tMnpaMG7ZY6xe/moK04U9fBhi6wEiCYHUW5Mop/wQHf12+79EQGwxYejNdhEz2mkqkBlGwm7pxmgBKMVUj0w==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "xtend": "^4.0.1" + } + }, "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", @@ -9304,6 +12280,22 @@ "integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==", "dev": true }, + "unified": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/unified/-/unified-7.1.0.tgz", + "integrity": "sha512-lbk82UOIGuCEsZhPj8rNAkXSDXd6p0QLzIuSsCdxrqnqU56St4eyOB+AlXsVgVeRmetPTYydIuvFfpDIed8mqw==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "@types/vfile": "^3.0.0", + "bail": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^1.1.0", + "trough": "^1.0.0", + "vfile": "^3.0.0", + "x-is-string": "^0.1.0" + } + }, "union-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", @@ -9363,12 +12355,57 @@ "imurmurhash": "^0.1.4" } }, + "unist-util-is": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz", + "integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==", + "dev": true + }, + "unist-util-remove-position": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-1.1.3.tgz", + "integrity": "sha512-CtszTlOjP2sBGYc2zcKA/CvNdTdEs3ozbiJ63IPBxh8iZg42SCCb8m04f8z2+V1aSk5a7BxbZKEdoDjadmBkWA==", + "dev": true, + "requires": { + "unist-util-visit": "^1.1.0" + } + }, + "unist-util-stringify-position": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz", + "integrity": "sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ==", + "dev": true + }, + "unist-util-visit": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.4.1.tgz", + "integrity": "sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==", + "dev": true, + "requires": { + "unist-util-visit-parents": "^2.0.0" + } + }, + "unist-util-visit-parents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz", + "integrity": "sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==", + "dev": true, + "requires": { + "unist-util-is": "^3.0.0" + } + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", "dev": true }, + "unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", + "dev": true + }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", @@ -9544,6 +12581,41 @@ "extsprintf": "^1.2.0" } }, + "vfile": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-3.0.1.tgz", + "integrity": "sha512-y7Y3gH9BsUSdD4KzHsuMaCzRjglXN0W2EcMf0gpvu6+SbsGhMje7xDc8AEoeXy6mIwCKMI6BkjMsRjzQbhMEjQ==", + "dev": true, + "requires": { + "is-buffer": "^2.0.0", + "replace-ext": "1.0.0", + "unist-util-stringify-position": "^1.0.0", + "vfile-message": "^1.0.0" + }, + "dependencies": { + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", + "dev": true + } + } + }, + "vfile-location": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-2.0.5.tgz", + "integrity": "sha512-Pa1ey0OzYBkLPxPZI3d9E+S4BmvfVwNAAXrrqGbwTVXWaX2p9kM1zZ+n35UtVM06shmWKH4RPRN8KI80qE3wNQ==", + "dev": true + }, + "vfile-message": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-1.1.1.tgz", + "integrity": "sha512-1WmsopSGhWt5laNir+633LszXvZ+Z/lxveBf6yhGsqnQIhlhzooZae7zV6YVM1Sdkw68dtAW3ow0pOdPANugvA==", + "dev": true, + "requires": { + "unist-util-stringify-position": "^1.1.1" + } + }, "vm-browserify": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", @@ -9553,18 +12625,87 @@ "indexof": "0.0.1" } }, + "void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "dev": true + }, "vue": { "version": "2.6.10", "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.10.tgz", "integrity": "sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==", "dev": true }, + "vue-docgen-api": { + "version": "3.24.2", + "resolved": "https://registry.npmjs.org/vue-docgen-api/-/vue-docgen-api-3.24.2.tgz", + "integrity": "sha512-seZiKhzBMxuK3dU23pf0kYh7k33gtDvWJUEdVePK6purcCRIuTKpTsu02wBS1U+EwlDZR7FUkeyYuQydAuvR0Q==", + "dev": true, + "requires": { + "@babel/parser": "^7.2.3", + "@babel/types": "^7.0.0", + "ast-types": "^0.12.2", + "hash-sum": "^1.0.2", + "lru-cache": "^4.1.5", + "pug": "^2.0.3", + "recast": "^0.17.3", + "ts-map": "^1.0.3", + "typescript": "^3.2.2", + "vue-template-compiler": "^2.0.0" + }, + "dependencies": { + "ast-types": { + "version": "0.12.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.12.4.tgz", + "integrity": "sha512-ky/YVYCbtVAS8TdMIaTiPFHwEpRB5z1hctepJplTr3UW5q8TDrpIMCILyk8pmLxGtn2KCtC/lSn7zOsaI7nzDw==", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "recast": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.17.6.tgz", + "integrity": "sha512-yoQRMRrK1lszNtbkGyM4kN45AwylV5hMiuEveUBlxytUViWevjvX6w+tzJt1LH4cfUhWt4NZvy3ThIhu6+m5wQ==", + "dev": true, + "requires": { + "ast-types": "0.12.4", + "esprima": "~4.0.0", + "private": "^0.1.8", + "source-map": "~0.6.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "vue-hot-reload-api": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz", "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==", "dev": true }, + "vue-inbrowser-compiler": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/vue-inbrowser-compiler/-/vue-inbrowser-compiler-3.23.0.tgz", + "integrity": "sha512-DaIcYHinWyt9pJgWM02sJ7bdFAQba9YYQklQ8Fitk7kz+TMyeCeUNwntJQAk+6bplx27qCHyFqXm8yvL0xBwQA==", + "dev": true, + "requires": { + "acorn": "^6.1.1", + "acorn-jsx": "^5.0.1", + "buble": "^0.19.7", + "camelcase": "^5.3.1", + "walkes": "^0.2.1" + } + }, "vue-loader": { "version": "15.7.1", "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.7.1.tgz", @@ -9588,6 +12729,103 @@ "loader-utils": "^1.0.2" } }, + "vue-styleguidist": { + "version": "3.24.2", + "resolved": "https://registry.npmjs.org/vue-styleguidist/-/vue-styleguidist-3.24.2.tgz", + "integrity": "sha512-c00EKBPrIT00Oq2BPOZSaNummIS2NlDbr3k4B8tFun3XU8Ja6oYBk4/c3SzqT7cYTgQPjw5e2JmjfQp6t8/Z4w==", + "dev": true, + "requires": { + "@vxna/mini-html-webpack-template": "^0.1.7", + "ast-types": "^0.12.2", + "classnames": "^2.2.6", + "clean-webpack-plugin": "^0.1.19", + "clipboard-copy": "^3.0.0", + "codemirror": "^5.39.0", + "common-dir": "^2.0.2", + "copy-webpack-plugin": "^4.5.2", + "css-loader": "^2.1.1", + "es6-object-assign": "^1.1.0", + "es6-promise": "^4.2.6", + "escodegen": "^1.11.1", + "findup": "^0.1.5", + "function.name-polyfill": "^1.0.6", + "github-slugger": "^1.2.0", + "glob": "^7.1.2", + "glogg": "^1.0.1", + "hash-sum": "^1.0.2", + "is-directory": "^0.3.1", + "javascript-stringify": "^1.6.0", + "kleur": "^2.0.1", + "leven": "^2.1.0", + "loader-utils": "^1.1.0", + "lodash": "^4.17.15", + "lru-cache": "^4.1.3", + "mini-html-webpack-plugin": "^0.2.3", + "minimist": "^1.2.0", + "ora": "^2.1.0", + "prismjs": "^1.15.0", + "prop-types": "^15.6.2", + "q-i": "^2.0.1", + "qss": "^2.0.3", + "react": "^16.4.1", + "react-codemirror2": "^5.1.0", + "react-dev-utils": "^7.0.3", + "react-dom": "^16.4.1", + "react-group": "^1.0.6", + "react-icons": "^3.7.0", + "react-lifecycles-compat": "^3.0.4", + "react-simple-code-editor": "^0.9.4", + "react-styleguidist": "^9.1.16", + "rewrite-imports": "^2.0.3", + "style-loader": "^0.21.0", + "terser-webpack-plugin": "^1.3.0", + "to-ast": "^1.0.0", + "vue-docgen-api": "^3.24.2", + "vue-inbrowser-compiler": "^3.23.0", + "webpack-dev-server": "^3.7.1", + "webpack-merge": "^4.0.0" + }, + "dependencies": { + "ast-types": { + "version": "0.12.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.12.4.tgz", + "integrity": "sha512-ky/YVYCbtVAS8TdMIaTiPFHwEpRB5z1hctepJplTr3UW5q8TDrpIMCILyk8pmLxGtn2KCtC/lSn7zOsaI7nzDw==", + "dev": true + }, + "codemirror": { + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.49.0.tgz", + "integrity": "sha512-Hyzr0HToBdZpLBN9dYFO/KlJAsKH37/cXVHPAqa+imml0R92tb9AkmsvjnXL+SluEvjjdfkDgRjc65NG5jnMYA==", + "dev": true + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "schema-utils": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz", + "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0" + } + }, + "style-loader": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.21.0.tgz", + "integrity": "sha512-T+UNsAcl3Yg+BsPKs1vd22Fr8sVT+CJMtzqc6LEw9bbJZb43lm9GoeIfUcDEefBSWC0BhYbcdupV1GtI4DGzxg==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "schema-utils": "^0.4.5" + } + } + } + }, "vue-template-compiler": { "version": "2.6.10", "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.10.tgz", @@ -9610,6 +12848,21 @@ "integrity": "sha512-zBskf77Z+RH8+Qs1q0NIDv/1enVkOoVH2dcdjcs+ZUNOhnlG0IkDedmqE2+PNm0JvJdgpOaV8wq+Pl69TGD2Hg==", "dev": true }, + "walkes": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/walkes/-/walkes-0.2.1.tgz", + "integrity": "sha1-fsoUT+Z+0yeC//5ujpX7RIGGR5Y=", + "dev": true + }, + "warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", + "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, "watchpack": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", @@ -9630,6 +12883,15 @@ "minimalistic-assert": "^1.0.0" } }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, "webpack": { "version": "4.33.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.33.0.tgz", @@ -10199,6 +13461,36 @@ "string-width": "^1.0.2 || 2" } }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true + }, + "with": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/with/-/with-5.1.1.tgz", + "integrity": "sha1-+k2qktrzLE6pTtRTyB8EaGtXXf4=", + "dev": true, + "requires": { + "acorn": "^3.1.0", + "acorn-globals": "^3.0.0" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true + } + } + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, "worker-farm": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", @@ -10219,6 +13511,15 @@ } } }, + "worker-rpc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/worker-rpc/-/worker-rpc-0.1.1.tgz", + "integrity": "sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg==", + "dev": true, + "requires": { + "microevent.ts": "~0.1.1" + } + }, "wrap-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", @@ -10244,6 +13545,12 @@ "async-limiter": "~1.0.0" } }, + "x-is-string": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/x-is-string/-/x-is-string-0.1.0.tgz", + "integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=", + "dev": true + }, "xml-char-classes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/xml-char-classes/-/xml-char-classes-1.0.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 294cebf..4ad0ff4 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -9,7 +9,9 @@ "scripts": { "test": "test", "build": "webpack -p --config ./webpack/webpack.prod.js", - "start": "node ./webpack/webpack.server" + "start": "node ./webpack/webpack.server", + "styleguide": "vue-styleguidist server", + "styleguide:build": "vui-styleguidist build" }, "dependencies": { "@uirouter/angularjs": "^1.0.11", @@ -66,6 +68,7 @@ "typescript": "^3.6.4", "vue": "^2.6.10", "vue-loader": "^15.7.1", + "vue-styleguidist": "^3.24.2", "vue-template-compiler": "^2.6.10", "vuetify": "^2.0.19", "webpack": "^4.0.0", From 0c992355e29bbdfd0d1682928615f13aa6a2dbf4 Mon Sep 17 00:00:00 2001 From: wyattis Date: Thu, 17 Oct 2019 11:40:16 -0400 Subject: [PATCH 008/234] Added comments for automatic documentation generation. Changed placement of node slot in SVGGraph so that it will be placed automatically. --- frontend/client/components/Choice.vue | 32 ++++++++- frontend/client/components/PlayerChoices.vue | 3 + frontend/client/components/PlayerText.vue | 3 + frontend/client/components/PlayerTimers.vue | 3 + frontend/client/components/SVGGraph.vue | 72 ++++++++++++++++--- frontend/client/components/Timer.vue | 7 +- frontend/client/components/examples/Choice.md | 28 ++++++++ frontend/webpack/webpack.base.js | 3 - frontend/webpack/webpack.client.js | 3 + 9 files changed, 136 insertions(+), 18 deletions(-) create mode 100644 frontend/client/components/examples/Choice.md diff --git a/frontend/client/components/Choice.vue b/frontend/client/components/Choice.vue index b97f2ee..08e824c 100644 --- a/frontend/client/components/Choice.vue +++ b/frontend/client/components/Choice.vue @@ -1,11 +1,14 @@ - - diff --git a/frontend/client/components/examples/Choice.md b/frontend/client/components/examples/Choice.md new file mode 100644 index 0000000..fdd8ef0 --- /dev/null +++ b/frontend/client/components/examples/Choice.md @@ -0,0 +1,28 @@ +Prepend and append arrows in the choice. + +```vue + + + + +``` + +Replace the choice text with static text +```vue + + A choice + +``` + +Replace the choice text with a formatted date string +```vue + + + +``` diff --git a/frontend/webpack/webpack.base.js b/frontend/webpack/webpack.base.js index 75c3943..6cb587c 100644 --- a/frontend/webpack/webpack.base.js +++ b/frontend/webpack/webpack.base.js @@ -90,8 +90,5 @@ module.exports = { resolve: { extensions: ['.js','.json','.css','.html', '.jsx', '.ts', '.tsx', '.vue'] }, - externals: { - vue: 'Vue' - }, plugins: plugins } diff --git a/frontend/webpack/webpack.client.js b/frontend/webpack/webpack.client.js index eb49941..1e8fb7e 100644 --- a/frontend/webpack/webpack.client.js +++ b/frontend/webpack/webpack.client.js @@ -33,6 +33,9 @@ module.exports = merge(Object.create(config), { publicPath: config.output.publicPath, filename: '[name].js' }, + externals: { + vue: 'Vue' + } /*optimization: { splitChunks: { cacheGroups: cacheGroups From 74a262aa71824e47409b4ac40326289a4d85e2d5 Mon Sep 17 00:00:00 2001 From: wyattis Date: Tue, 22 Oct 2019 17:00:52 -0400 Subject: [PATCH 009/234] Added sendChoice method to Breadboard core to simplify correct message formation. If params is not a JSON string, the backend just fails silently. --- frontend/client/components/PlayerChoices.vue | 94 +++++++++++++------- frontend/core/breadboard.ts | 15 ++++ 2 files changed, 79 insertions(+), 30 deletions(-) diff --git a/frontend/client/components/PlayerChoices.vue b/frontend/client/components/PlayerChoices.vue index 81db741..ec952bd 100644 --- a/frontend/client/components/PlayerChoices.vue +++ b/frontend/client/components/PlayerChoices.vue @@ -2,46 +2,80 @@ - + + + + diff --git a/frontend/core/breadboard.ts b/frontend/core/breadboard.ts index 649d5d7..92063ea 100644 --- a/frontend/core/breadboard.ts +++ b/frontend/core/breadboard.ts @@ -79,6 +79,21 @@ export class BreadboardClass extends Emitter implements BreadboardMessages { this.socket.send(JSON.stringify(d)) } + /** + * Shortcut for sending a choice via breadboard. Helps keeps params from throwing silent bugs. + * @param uuid + * @param params + */ + sendChoice (uuid: string, params?: SimpleMap) { + const data: any = { + choiceUID: uuid + } + if (params && typeof params !== 'string') { + data.params = JSON.stringify(params) + } + return this.send('MakeChoice', data) + } + /** * Login method */ From 6d7eaee3e9090d50d5ae9481bd5ad477740b1bf6 Mon Sep 17 00:00:00 2001 From: wyattis Date: Wed, 23 Oct 2019 16:37:38 -0400 Subject: [PATCH 010/234] Added missing material design icons for Vuetify. Updated some slots. Added client-angular build in webpack config. Will try to provide backwards compatibility with this. --- .gitignore | 2 + conf/defaults/default-client-graph.js | 433 +------------------- conf/defaults/default-client-html.html | 55 +-- frontend/client/client.ts | 37 -- frontend/client/components/PlayerTimers.vue | 10 +- frontend/client/components/SVGGraph.vue | 6 +- frontend/client/lib/graph.ts | 19 +- frontend/client/lib/isEqual.ts | 30 ++ frontend/core/breadboard.ts | 19 +- frontend/core/breadboard.types.ts | 1 + frontend/package.json | 2 +- frontend/webpack/webpack.base.js | 4 +- frontend/webpack/webpack.client.js | 51 +-- 13 files changed, 134 insertions(+), 535 deletions(-) create mode 100644 frontend/client/lib/isEqual.ts diff --git a/.gitignore b/.gitignore index 898fc53..a79fa90 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,5 @@ node_modules client-graph.js client-html.html csv + +.vscode \ No newline at end of file diff --git a/conf/defaults/default-client-graph.js b/conf/defaults/default-client-graph.js index a9d0348..3937a9d 100644 --- a/conf/defaults/default-client-graph.js +++ b/conf/defaults/default-client-graph.js @@ -1,423 +1,10 @@ -function Graph(clientId, parentElement) { - - var width = parentElement ? parentElement.clientWidth : 600; - var height = parentElement ? parentElement.clientHeight : 600; - var egoNodeR = 50; - var alterNodeR = 30; - var arrowPadding = 7; - var graphPadding = 10; - var linkDistance = (Math.min(width, height) / 2) - alterNodeR - (2 * graphPadding); - - var ignoreProps = ["$$hashKey", "text", "choices", "x", "y", "px", "py"]; - - var div = parentElement ? d3.select(parentElement) : d3.select("#graph"); - var vis = div.append("svg:svg") - .attr("viewBox", "0 0 600 600") - - // set up arrow markers for graph links - // Thanks to rkirsling for the example here: http://bl.ocks.org/rkirsling/5001347 - vis.append('svg:defs').append('svg:marker') - .attr('id', 'end') - .attr('viewBox', '0 -5 10 10') //'0 -5 10 10' - .attr('refX', 6) - .attr('markerWidth', 4) - .attr('markerHeight', 4) - .attr('orient', 'auto') - .append('svg:path') - .attr('d', 'M0,-5L10,0L0,5') - .attr('fill', '#333'); - - vis.append('svg:defs').append('svg:marker') - .attr('id', 'start') - .attr('viewBox', '0 -5 10 10') //'0 -5 10 10' - .attr('refX', 4) - .attr('markerWidth', 4) - .attr('markerHeight', 4) - .attr('orient', 'auto') - .append('svg:path') - .attr('d', 'M10,-5L0,0L10,5') - .attr('fill', '#333'); - - vis.append('svg:defs').append('svg:marker') - .attr('id', 'end-green') - .attr('viewBox', '0 -5 10 10')//'0 -5 10 10' - .attr('refX', 6) - .attr('markerWidth', 4) - .attr('markerHeight', 4) - .attr('orient', 'auto') - .append('svg:path') - .attr('d', 'M0,-5L10,0L0,5') - .attr('fill', 'green'); - - vis.append('svg:defs').append('svg:marker') - .attr('id', 'end-red') - .attr('viewBox', '0 -5 10 10')//'0 -5 10 10' - .attr('refX', 6) - .attr('markerWidth', 4) - .attr('markerHeight', 4) - .attr('orient', 'auto') - .append('svg:path') - .attr('d', 'M0,-5L10,0L0,5') - .attr('fill', 'red'); - - vis.append('svg:defs').append('svg:marker') - .attr('id', 'start-green') - .attr('viewBox', '0 -5 10 10')//'0 -5 10 10' - .attr('refX', 4) - .attr('markerWidth', 4) - .attr('markerHeight', 4) - .attr('orient', 'auto') - .append('svg:path') - .attr('d', 'M10,-5L0,0L10,5') - .attr('fill', 'green'); - - vis.append('svg:defs').append('svg:marker') - .attr('id', 'start-red') - .attr('viewBox', '0 -5 10 10')//'0 -5 10 10' - .attr('refX', 4) - .attr('markerWidth', 4) - .attr('markerHeight', 4) - .attr('orient', 'auto') - .append('svg:path') - .attr('d', 'M10,-5L0,0L10,5') - .attr('fill', 'red'); - - var force = d3.layout.force() - .gravity(.05) - .friction(0.8) - .charge(-10000) //-500 - .linkStrength(10) //2 - .linkDistance(linkDistance * 0.9) - .size([width, height]); - - var nodes = force.nodes(), - links = force.links(); - - force.on("tick", function () { - vis.selectAll("line.link") - .attr("x1", function (d) { - var deltaX = d.target.x - d.source.x, - deltaY = d.target.y - d.source.y, - dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY), - normX = deltaX / dist, - sourcePadding = (d.source.id == clientId) ? egoNodeR : alterNodeR; - if (d.arrow && d.arrow.length > 0) { - sourcePadding += arrowPadding; - } - return d.source.x + (sourcePadding * normX); - }) - .attr("y1", function (d) { - var deltaX = d.target.x - d.source.x, - deltaY = d.target.y - d.source.y, - dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY), - normY = deltaY / dist, - sourcePadding = (d.source.id == clientId) ? egoNodeR : alterNodeR; - if (d.arrow && d.arrow.length > 0) { - sourcePadding += arrowPadding; - } - return d.source.y + (sourcePadding * normY); - }) - .attr("x2", function (d) { - var deltaX = d.target.x - d.source.x, - deltaY = d.target.y - d.source.y, - dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY), - normX = deltaX / dist, - targetPadding = (d.target.id == clientId) ? egoNodeR : alterNodeR; - if (d.arrow && d.arrow.length > 0) { - targetPadding += arrowPadding; - } - return targetX = d.target.x - (targetPadding * normX); - }) - .attr("y2", function (d) { - var deltaX = d.target.x - d.source.x, - deltaY = d.target.y - d.source.y, - dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY), - normY = deltaY / dist, - targetPadding = (d.target.id == clientId) ? egoNodeR : alterNodeR; - if (d.arrow && d.arrow.length > 0) { - targetPadding += arrowPadding; - } - return targetY = d.target.y - (targetPadding * normY); - }); - - vis.selectAll("g.node") - .attr("transform", function (d) { - return "translate(" + d.x + "," + d.y + ")" - }); - }); - - var removeNode = function (nid) { - var nodeIndex = findNode(nid); - if (nodeIndex > -1) { - nodes.splice(i, 1); - } - } - - var findNode = function (nid) { - for (var i = 0; i < nodes.length; i++) { - if (nodes[i].id == nid) { - return nodes[i]; - } - } - return null; - } - - var addLink = function (link, sourceId, targetId) { - link.source = findNode(sourceId); - link.target = findNode(targetId); - links.push(link); - } - - var updateLink = function (oldLink, newLink, sourceId, targetId) { - _.extend(oldLink, newLink); - oldLink.source = findNode(sourceId); - oldLink.target = findNode(targetId); - } - - this.updateGraph = function (newGraph) { - - if (newGraph == undefined) - return; - - if (newGraph.nodes == undefined || newGraph.nodes.length == 0) { - // Remove all nodes - nodes.length = 0; - } else { - // If there is anything in the old array that isn't in the new, it needs to be removed - for (var i = nodes.length - 1; i >= 0; i--) { - if (_.find(newGraph.nodes, function (n) { - return n.id === nodes[i].id; - }) === undefined) { - nodes.splice(i, 1); - } - } - - // Finally, anything in the new array that isn't in the old needs to be added - for (var i = 0; i < newGraph.nodes.length; i++) { - var oldNode = _.find(nodes, function (n) { - return n.id === newGraph.nodes[i].id; - }); - if (oldNode === null || oldNode === undefined) { - nodes.push(newGraph.nodes[i]); - } else { - // Update the old node - _.extend(oldNode, newGraph.nodes[i]); - } - } - } - - if (newGraph.links == undefined || newGraph.links.length == 0) { - // Remove all links - links.length = 0; - } else { - // If there is anything in the old array that isn't in the new, it needs to be removed - for (var i = links.length - 1; i >= 0; i--) { - // source or target could have been removed at this point - var sourceId = (links[i].source == undefined) ? null : links[i].source.id; - var targetId = (links[i].target == undefined) ? null : links[i].target.id; - - try { - if (_.find(newGraph.links, function (l) { - return ((newGraph.nodes[l.source].id === sourceId) && (newGraph.nodes[l.target].id === targetId)); - }) === undefined) { - links.splice(i, 1); - } - } catch (e) { - //TODO: Why is there an exception being thrown here? - } - } - - // Finally, anything in the new array that isn't in the old needs to be added - for (var i = 0; i < newGraph.links.length; i++) { - var sourceIdx, targetIdx, source, target, sourceId, targetId = undefined; - var link = newGraph.links[i]; - if (link != undefined) { - sourceIdx = link.source; - targetIdx = link.target; - } - - if (sourceIdx != undefined && targetIdx != undefined) { - source = newGraph.nodes[sourceIdx]; - target = newGraph.nodes[targetIdx]; - } - - if (source != undefined && target != undefined) { - sourceId = source.id; - targetId = target.id; - } - - if (sourceId != undefined && targetId != undefined) { - var oldLink = _.find(links, function (l) { - return ((l.target.id === targetId) && (l.source.id === sourceId)); - }); - if (oldLink === null || oldLink === undefined) { - addLink(link, sourceId, targetId); - } else { - // Update the old link - updateLink(oldLink, link, sourceId, targetId); - } - } - } - } - - update(); - }; - - var animateScore = function (amount, start, end, endNodeId) { - //console.log("animateScore(" + amount + ", " + start + ", " + end + ", " + endNodeId + ")"); - - var animText = vis.append("svg:text") - .attr("class", "anim") - .style("text-anchor", "middle") - .style("fill", "#1EFF1E") - .style("stroke", "#000") - .style("font-family", "Lucida Sans") - .style("font-weight", "bold") - .style("font-size", 18) - .text(((amount < 0) ? "" : "+") + amount) - .attr("x", start.x) - .attr("y", start.y) - .transition() - .duration(1500) - .attr("x", end.x) - .attr("y", end.y) - .remove(); - - } - - var update = function () { - var link = vis.selectAll("line.link") - .data(links, function (d) { - return d.id; - }); - - link.enter().insert("svg:line", "g.node") - .attr("class", "link client"); - - link.exit().remove(); - - var g = vis.selectAll("g.node") - .data(nodes, function (d) { - return d.id; - }); - - var gEnter = g.enter().append("svg:g") - .attr("class", "node client"); - //.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); - - gEnter.append("svg:text") - .attr("class", "node client") - .attr("r", 50) - .style("text-anchor", "middle") - .style("font-size", function (d) { - return (d.id == clientId) ? "18pt" : "14pt" - }) - .text(function (d) { - return (d.score == undefined) ? "" : d.score; - }); - - gEnter.insert("svg:circle", "text.node") - .attr("class", "node client") - .attr("r", function (d) { - return (d.id == clientId) ? egoNodeR : alterNodeR; - }) - .each(function (d) { - if (d.id == clientId) { - d.fixed = true; - d.x = width / 2; - d.y = height / 2; - } - }); - - g.exit().remove(); - - - var scoreText = vis.selectAll("text.node"); - - scoreText.text(function (d) { - return (d.score == undefined) ? "" : d.score; - }); - - force - .nodes(nodes) - .links(links) - .start(); - - var node = g.selectAll("circle.node"); - - d3.selectAll("circle.node").each(function (d, i) { - for (var propertyName in d) { - if (_.indexOf(ignoreProps, propertyName) == -1 && isNaN(propertyName)) { - d3.select(this).attr(propertyName, d[propertyName]); - } - } - }); - - d3.selectAll("line.link").each(function (d, i) { - d3.select(this).attr("marker-start", null); - d3.select(this).attr("marker-end", null); - - for (var propertyName in d) { - if (propertyName == "arrow") { - var arrowParams = d.arrow.split(","); - if (arrowParams.length < 1) { - return; - } - - if (d.source.id == arrowParams[0] || arrowParams[0] == "both") { - if (arrowParams.length > 1 && arrowParams[1] != "grey") { - d3.select(this).attr("marker-start", "url(#start-" + arrowParams[1] + ")") - } else { - d3.select(this).attr("marker-start", "url(#start)") - } - } else { - d3.select(this).attr("marker-start", null); - } - - if (d.target.id == arrowParams[0] || arrowParams[0] == "both") { - if (arrowParams.length > 1 && arrowParams[1] != "grey") { - d3.select(this).attr("marker-end", "url(#end-" + arrowParams[1] + ")") - } else { - d3.select(this).attr("marker-end", "url(#end)") - } - } else { - d3.select(this).attr("marker-end", null); - } - - } else if (_.indexOf(ignoreProps, propertyName) == -1) { - d3.select(this).attr(propertyName, d[propertyName]); - } - } - }); - - - var setupAnim = function () { - link.each(function (d) { - var animate = d3.select(this).attr("animate"); - if (animate != undefined) { - var params = animate.split(","); - if (params.length > 3) { - var round = params[0]; - var amount = params[1]; - var startNodeId = params[2]; - var endNodeId = params[3]; - - var startNode = findNode(startNodeId); - var endNode = findNode(endNodeId); - - var start = {"x": startNode.x, "y": startNode.y}; - var end = {"x": endNode.x, "y": endNode.y}; - - if ((d.animated != animate) && start != undefined && end != undefined && endNodeId != undefined) { - d.animated = animate; - animateScore(amount, start, end, endNodeId); - } - } - } - }); - }; - - var t = setTimeout(setupAnim, 1000); - - }; -} \ No newline at end of file +async function init () { + // Breadboard.connect() // Not required, but this slightly speeds up client's appearance in the graph. Using this will make styles not load correctly. + const config = await Breadboard.loadConfig() + await Breadboard.loadVueDependencies({ + useDev: true + }) + await Breadboard.createDefaultVue(config.clientHtml) +} + +init() \ No newline at end of file diff --git a/conf/defaults/default-client-html.html b/conf/defaults/default-client-html.html index 16e59d2..aa5fe20 100644 --- a/conf/defaults/default-client-html.html +++ b/conf/defaults/default-client-html.html @@ -1,25 +1,30 @@ -
-
-

You have been dropped for being idle.

-

Please return this HIT.

-
-
- -
-
-
-
-
-
- -
- -
-
-
-
-
\ No newline at end of file + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/client/client.ts b/frontend/client/client.ts index a3609ee..47db526 100644 --- a/frontend/client/client.ts +++ b/frontend/client/client.ts @@ -18,43 +18,6 @@ async function client () { console.error('Breadboard: Unable to run client-graph.js') throw err } - - // TODO: Move this to client graph - await Breadboard.loadVueDependencies({ - useDev: true - }) - await Breadboard.createDefaultVue(` - - - - - - - - - - - - - - - - `) - } client() diff --git a/frontend/client/components/PlayerTimers.vue b/frontend/client/components/PlayerTimers.vue index 21cbf34..54978ef 100644 --- a/frontend/client/components/PlayerTimers.vue +++ b/frontend/client/components/PlayerTimers.vue @@ -1,8 +1,12 @@ diff --git a/frontend/client/components/SVGGraph.vue b/frontend/client/components/SVGGraph.vue index 0f8d61b..0fc49e0 100644 --- a/frontend/client/components/SVGGraph.vue +++ b/frontend/client/components/SVGGraph.vue @@ -10,7 +10,7 @@ v-bind:edge="edge">
- + n.id === node.id) if (!existingNodeData) { removedNodes.push(node) - } else if (!isEqualWith(node.data, existingNodeData, this.nodeComparison)) { - console.log('node change', JSON.stringify(node), JSON.stringify(existingNodeData)) + } else if (!isEqual(node.data, existingNodeData, ['timers', 'timerUpdatedAt'])) { + // TODO: Why is this happening? + // console.log('node change') + // console.log('old node', JSON.stringify(node.data)) + // console.log('new node', JSON.stringify(existingNodeData)) node.data = existingNodeData + // console.log('updated node', JSON.stringify(node.data)) updatedNodes.push(node) } } @@ -178,12 +181,4 @@ export class Graph extends Emitter implements GraphEvents { } - private nodeComparison (a: any, b: any, key: string | number | Symbol | undefined): boolean { - if (key === 'timers' || key === 'timerUpdatedAt') { - return true - } else { - return isEqual(a, b) - } - } - } diff --git a/frontend/client/lib/isEqual.ts b/frontend/client/lib/isEqual.ts new file mode 100644 index 0000000..e45bcdd --- /dev/null +++ b/frontend/client/lib/isEqual.ts @@ -0,0 +1,30 @@ +export function isEqual (a: any, b: any, ignoredKeys: string[] = []): boolean { + if (a == null || b == null) { + return a == b + } else if (Array.isArray(a)) { + for (let i = 0; i < a.length; i++) { + if (!isEqual(a[i], b[i], ignoredKeys)) { + return false + } + } + return true + } else if (typeof a === 'object') { + const aKeys = Object.keys(a).filter(k => !ignoredKeys.includes(k)) + const bKeys = Object.keys(b).filter(k => !ignoredKeys.includes(k)) + if (aKeys.length !== bKeys.length) { + return false + } + for (const key of aKeys) { + // console.log(a[key], b[key], key) + if (!isEqual(a[key], b[key], ignoredKeys)) { + return false + } + } + return true + } else { + return a === b + } +} + +// @ts-ignore +window.isEqual = isEqual \ No newline at end of file diff --git a/frontend/core/breadboard.ts b/frontend/core/breadboard.ts index 92063ea..55742a7 100644 --- a/frontend/core/breadboard.ts +++ b/frontend/core/breadboard.ts @@ -193,15 +193,18 @@ export class BreadboardClass extends Emitter implements BreadboardMessages { async loadVueDependencies (opts: VueLoadOpts = {}) { opts = Object.assign({ vueVersion: '2.6.10', - vuetifyVersion: '2.0.19', + vuetifyVersion: '2.1.5', + mdiVersion: '4.5.95', useDev: false }, opts) + this.addStyleFromURL('https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900') + this.addStyleFromURL('/bundles/client.css') + this.addStyleFromURL(`https://cdn.jsdelivr.net/npm/@mdi/font@${opts.mdiVersion}/css/materialdesignicons.min.css`) + this.addStyleFromURL(`https://cdn.jsdelivr.net/npm/vuetify@${opts.vuetifyVersion}/dist/vuetify.min.css`) await this.addScriptFromURL(`https://cdnjs.cloudflare.com/ajax/libs/vue/${opts.vueVersion}/vue.${opts.useDev ? 'common.dev.' : ''}js`) await Promise.all([ - this.addScriptFromURL(`https://cdnjs.cloudflare.com/ajax/libs/vuetify/${opts.vuetifyVersion}/vuetify.min.js`), - this.addScriptFromURL('/bundles/vue-components.js'), - this.addStyleFromURL(`https://cdnjs.cloudflare.com/ajax/libs/vuetify/${opts.vuetifyVersion}/vuetify.min.css`), - this.addStyleFromURL('/bundles/client.css') + this.addScriptFromURL(`https://cdn.jsdelivr.net/npm/vuetify@${opts.vuetifyVersion}/dist/vuetify.js`), + this.addScriptFromURL('/bundles/vue-components.js') ]) const Vue = window.Vue @@ -224,7 +227,11 @@ export class BreadboardClass extends Emitter implements BreadboardMessages { const Vue = window.Vue const Vuetify = window.Vuetify return new Vue({ - vuetify: new Vuetify(), + vuetify: new Vuetify({ + icons: { + iconfont: 'mdi' + } + }), mixins: [DefaultView], template: template }).$mount('#app') diff --git a/frontend/core/breadboard.types.ts b/frontend/core/breadboard.types.ts index c29856b..6d88421 100644 --- a/frontend/core/breadboard.types.ts +++ b/frontend/core/breadboard.types.ts @@ -9,6 +9,7 @@ export interface BreadboardConfig extends SimpleMap { export interface VueLoadOpts { vueVersion?: string vuetifyVersion?: string + mdiVersion?: string useDev?: boolean } diff --git a/frontend/package.json b/frontend/package.json index 4ad0ff4..174c628 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -70,7 +70,7 @@ "vue-loader": "^15.7.1", "vue-styleguidist": "^3.24.2", "vue-template-compiler": "^2.6.10", - "vuetify": "^2.0.19", + "vuetify": "^2.1.0", "webpack": "^4.0.0", "webpack-cli": "^3.3.9", "webpack-dev-server": "^3.8.2", diff --git a/frontend/webpack/webpack.base.js b/frontend/webpack/webpack.base.js index 6cb587c..a127f64 100644 --- a/frontend/webpack/webpack.base.js +++ b/frontend/webpack/webpack.base.js @@ -41,11 +41,11 @@ module.exports = { indentedSyntax: true } }], - exclude: /node_modules/, + // exclude: /node_modules/, }, { test: /\.css$/, use: ['style-loader','css-loader?url=false'], - exclude: /node_modules/, + // exclude: /node_modules/, }, { test: /\.tsx?$/, use: [{ diff --git a/frontend/webpack/webpack.client.js b/frontend/webpack/webpack.client.js index 1e8fb7e..54ed051 100644 --- a/frontend/webpack/webpack.client.js +++ b/frontend/webpack/webpack.client.js @@ -1,44 +1,49 @@ -const merge = require('webpack-merge') -const config = require('./webpack.base.js') +const merge = require('webpack-merge'); +const config = require('./webpack.base.js'); function recursiveIssuer(m) { if (m.issuer) { - return recursiveIssuer(m.issuer) + return recursiveIssuer(m.issuer); } else if (m.name) { - return m.name + return m.name; } else { - return false + return false; } } -const cacheGroups = ['client', 'vue-components', 'breadboard', 'design'].reduce((map, entry) => { - map[entry + 'Styles'] = { - name: entry, - test: (m, c) => m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry, - chunks: 'all', - enforce: false - } - return map -}, {}) +const cacheGroups = ['client', 'vue-components', 'breadboard', 'design'].reduce( + (map, entry) => { + map[entry + 'Styles'] = { + name: entry, + test: (m, c) => + m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry, + chunks: 'all', + enforce: false + }; + return map; + }, + {} +); module.exports = merge(Object.create(config), { entry: { client: './client/client.ts', 'vue-components': './client/vue-components.ts', breadboard: './core/breadboard.ts', - design: './design/design.js' + design: './design/design.js', + 'client-angular': './design/client.js' }, output: { - path: config.output.path, - publicPath: config.output.publicPath, + path: config.output.path, + publicPath: config.output.publicPath, filename: '[name].js' }, externals: { vue: 'Vue' } - /*optimization: { - splitChunks: { - cacheGroups: cacheGroups - } - },*/ -}) + // optimization: { + // splitChunks: { + // cacheGroups: cacheGroups + // } + // } +}); From da5906f8e4b88f125feb99c8fe5db34e5f8d3368 Mon Sep 17 00:00:00 2001 From: wyattis Date: Wed, 23 Oct 2019 16:45:12 -0400 Subject: [PATCH 011/234] update frontend TODO --- frontend/client/TODO.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/frontend/client/TODO.md b/frontend/client/TODO.md index 308691b..57e6805 100644 --- a/frontend/client/TODO.md +++ b/frontend/client/TODO.md @@ -9,10 +9,14 @@ - [x] click - [x] optional centering of the ego node - [x] filter ignored props from binding to SVG - - [ ] ~~throttle graph updates to avoid multiple, rapid resets of the force-directed graph simulation???~~ + - [ ] ~~throttle graph updates to avoid multiple, rapid resets of the force-directed graph simulation???~~ Not necessary - [ ] Component slots + - [ ] Timer label via PlayerTimers component + - [ ] Custom choice label + - [ ] Custom choice label via PlayerChoices component + - [x] Custom choice slot - [x] Timer label - - [ ] Button contents + - [x] Button contents - [ ] Documentation - [ ] SVGGraph properties - [ ] Events From 2a738e31732655868d48618ed8feabd4e34f6e36 Mon Sep 17 00:00:00 2001 From: wyattis Date: Mon, 28 Oct 2019 13:36:20 -0400 Subject: [PATCH 012/234] Added simple EventBus interface to ScriptBoard and global CustomEvent and scoped CustomPlayerEvent action types. --- app/models/EventBus.java | 65 +++++++++++++++++++++++++++++++++++++ app/models/ScriptBoard.java | 14 ++++++++ groovy/events.groovy | 12 +++++++ 3 files changed, 91 insertions(+) create mode 100644 app/models/EventBus.java create mode 100644 groovy/events.groovy diff --git a/app/models/EventBus.java b/app/models/EventBus.java new file mode 100644 index 0000000..a9c1fc6 --- /dev/null +++ b/app/models/EventBus.java @@ -0,0 +1,65 @@ +package models; + +import groovy.lang.Closure; +import java.util.ArrayList; +import java.util.HashMap; + +class EventHandler { + public ArrayList> closures = new ArrayList(); + + public void addClosure (Closure closure) { + this.closures.add(closure); + } + + public void removeClosure (Closure closure) { + this.closures.remove(closure); + } + + public void emit (A... data) { + for (Closure closure : this.closures) { + closure.call(data); + } + } + +} + +public class EventBus { + + private HashMap> events = new HashMap(); + + public void register (String eventName) { + this.events.put(eventName, new EventHandler()); + } + + public void unregister (String eventName) { + this.events.remove(eventName); + } + + public void on (String eventName, Closure closure) throws Exception { + EventHandler event = getEvent(eventName); + event.addClosure(closure); + } + + private EventHandler getEvent (String eventName) throws Exception { + EventHandler event = this.events.get(eventName); + if (event == null) { + throw new Exception("Event " + eventName + " must be registered before it can be used"); + } + return event; + } + + public void off (String eventName, Closure closure) throws Exception { + EventHandler event = getEvent(eventName); + event.removeClosure(closure); + } + + public void emit (String eventName, T... payload) throws Exception { + EventHandler event = getEvent(eventName); + event.emit(payload); + } + + public void clear () { + events.clear(); + } + +} \ No newline at end of file diff --git a/app/models/ScriptBoard.java b/app/models/ScriptBoard.java index d264a31..1a62531 100644 --- a/app/models/ScriptBoard.java +++ b/app/models/ScriptBoard.java @@ -37,6 +37,7 @@ public class ScriptBoard extends UntypedActor { private static BreadboardGraphInterface graphInterface; private static BreadboardGraphChangedListener graphChangedListener; private static EventTracker eventTracker = new EventTracker(); + private static EventBus eventBus = new EventBus(); private static Random rand = new Random(); @@ -68,6 +69,7 @@ private void init() { clients = new HashMap<>(); eventTracker = new EventTracker(); manager = new ScriptEngineManager(); + eventBus.clear(); } private void resetEngine(Experiment experiment) throws IOException, ScriptException { @@ -87,12 +89,15 @@ private void resetEngine(Experiment experiment) throws IOException, ScriptExcept processScript("g.empty()", null, null); } + eventBus.clear(); + engine = manager.getEngineByName("gremlin-groovy"); engine.getBindings(ScriptContext.ENGINE_SCOPE).put("r", rand); engine.getBindings(ScriptContext.ENGINE_SCOPE).put("results", results); engine.getBindings(ScriptContext.ENGINE_SCOPE).put("eventTracker", eventTracker); engine.getBindings(ScriptContext.ENGINE_SCOPE).put("gameListener", gameListener); + engine.getBindings(ScriptContext.ENGINE_SCOPE).put("events", eventBus); if (experiment != null) { engine.getBindings(ScriptContext.ENGINE_SCOPE).put("c", experiment.contentFetcher); @@ -123,6 +128,10 @@ private void resetEngine(Experiment experiment) throws IOException, ScriptExcept String testString = FileUtils.readFileToString(testFile, "UTF-8"); engine.eval(testString); + File eventsFile = new File(Play.application().path().toString() + "/groovy/events.groovy"); + String eventsString = FileUtils.readFileToString(eventsFile, "UTF-8"); + engine.eval(eventsString); + // get script object on which we want to implement the interface with Object a = engine.get("a"); Invocable inv = (Invocable) engine; @@ -256,9 +265,14 @@ public void invoke(JsonNode event) { String choiceUID = jsonInput.get("choiceUID").toString(); String params = (jsonInput.containsKey("params")) ? jsonInput.get("params").toString() : null; makeChoice(choiceUID, params, out); + } else if (action.equals("CustomEvent")) { + // TODO: Is is possible for this to be emitted before the event has been registered? I think it is.. + eventBus.emit("CustomEvent", jsonInput); } } catch (java.io.IOException ignored) { Logger.debug("java.io.IOException"); + } catch (Exception e) { + Logger.error(e.getMessage()); } } }); diff --git a/groovy/events.groovy b/groovy/events.groovy new file mode 100644 index 0000000..3ad0ac7 --- /dev/null +++ b/groovy/events.groovy @@ -0,0 +1,12 @@ +def CUSTOM_PLAYER_EVENT = "CustomPlayerEvent" +def CUSTOM_EVENT = "CustomEvent" +events.register(CUSTOM_EVENT) +events.register(CUSTOM_PLAYER_EVENT) +events.on(CUSTOM_EVENT, { params -> + if ("playerId" in params) { + def player = g.getVertex(params["playerId"]) + if (player) { + events.emit(CUSTOM_PLAYER_EVENT, player, params) + } + } +}) \ No newline at end of file From 87b1cdd2d93cd2a975ffeb37d403790e5bb6eba3 Mon Sep 17 00:00:00 2001 From: Mark McKnight Date: Tue, 5 Nov 2019 11:10:09 -0500 Subject: [PATCH 013/234] Added database schema changes for v2.4.0. Added file_mode field to experiments table. --- app/Global.java | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/app/Global.java b/app/Global.java index c5db673..0f422d3 100644 --- a/app/Global.java +++ b/app/Global.java @@ -27,6 +27,7 @@ public class Global extends GlobalSettings { static Process process = null; + public static String VERSION = "v2.4.0"; @Override public void onStart(Application app) { @@ -35,13 +36,14 @@ public void onStart(Application app) { SqlRow versionTableCount = Ebean.createSqlQuery(sql).findUnique(); String count = versionTableCount.getString("table_count"); + // If the breadboard_version table doesn't exist we're < v2.3 if (count.equals("0")) { // Create the breadboard_version table sql = "create table breadboard_version ( version varchar(255) ); "; Ebean.createSqlUpdate(sql).execute(); // Update the version - sql = "insert into breadboard_version values ('v2.3.1'); "; + sql = "insert into breadboard_version values ('" + VERSION + "'); "; Ebean.createSqlUpdate(sql).execute(); // Create the languages table @@ -155,6 +157,17 @@ public void onStart(Application app) { // TODO: Add message telling user what was done // TODO: Load v2.3 version notes as message from file system + // Upgrade to version 2.4.0 + version2Point4Upgrade(); + } else { + // The breadboard_version table exists, let's check if we're v2.3 or v2.4 + sql = "select version from breadboard_version limit 1;"; + SqlRow versionString = Ebean.createSqlQuery(sql).findUnique(); + String version = versionString.getString("version"); + if (version.equals("v2.3.0") || version.equals("v2.3.1")) { + // Add v2.4.0 fields + version2Point4Upgrade(); + } // Otherwise, no upgrade needed } //InitialData.insert(app); @@ -176,6 +189,12 @@ public void onStart(Application app) { // TODO: We could build the production resources when the framework starts instead of having to build them manually } + private void version2Point4Upgrade() { + // Changes to support Experiment fileMode + String sql = "alter table experiments add column if not exists file_mode bit default 0;"; + Ebean.createSqlUpdate(sql).execute(); + } + @Override public void onStop(Application app){ if(process != null){ From 1a0abb4efd17a667965389781c6833300a01d0a9 Mon Sep 17 00:00:00 2001 From: Mark McKnight Date: Tue, 5 Nov 2019 11:11:29 -0500 Subject: [PATCH 014/234] Added update method to Admin to manually trigger admin client update. --- app/models/Admin.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/models/Admin.java b/app/models/Admin.java index 7fbe7f6..08a18ef 100644 --- a/app/models/Admin.java +++ b/app/models/Admin.java @@ -27,6 +27,10 @@ public Admin(User user, ActorRef scriptBoardController, ThrottledWebSocketOut ou this.out = out; } + public void update() { + this.out.write(this.user.toJson()); + } + public void graphChanged(Graph wholeGraph) { ObjectNode jsonOutput = Json.newObject(); @@ -185,4 +189,8 @@ public void setOut(ThrottledWebSocketOut out) { public ThrottledWebSocketOut getOut() { return this.out; } + + public User getUser() { + return this.user; + } } From 1fa1304012c4fe42ebc7d335b715ac36e2a7da59 Mon Sep 17 00:00:00 2001 From: Mark McKnight Date: Tue, 5 Nov 2019 11:15:17 -0500 Subject: [PATCH 015/234] Added action to toggle file mode for the currently selected experiment. Updated experiment model to include file mode, toggle file mode, and to get steps from file when file mode is true. --- app/models/Breadboard.java | 13 +++ app/models/Experiment.java | 177 ++++++++++++++++++++++++++++++++----- 2 files changed, 170 insertions(+), 20 deletions(-) diff --git a/app/models/Breadboard.java b/app/models/Breadboard.java index 250a125..6b57f9e 100644 --- a/app/models/Breadboard.java +++ b/app/models/Breadboard.java @@ -205,6 +205,8 @@ public void invoke(JsonNode event) { } else if (action.equals("DeleteImage")) { Long imageId = Long.parseLong(jsonInput.get("imageId").toString()); breadboardController.tell(new DeleteImage(user, imageId, out), null); + } else if (action.equals("ToggleFileMode")) { + breadboardController.tell(new ToggleFileMode(user, out), null); } } else { // END if (user != null) Logger.error("user not found with UID: " + user.uid); @@ -729,6 +731,11 @@ public int compare(Event o1, Event o2) { DeleteImage deleteImage = (DeleteImage) message; Long imageId = deleteImage.imageId; Image.findById(imageId).delete(); + } else if (message instanceof ToggleFileMode) { + Experiment selectedExperiment = breadboardMessage.user.getExperiment(); + if (selectedExperiment != null) { + selectedExperiment.toggleFileMode(); + } } breadboardMessage.out.write(breadboardMessage.user.toJson()); @@ -1077,6 +1084,12 @@ public ReloadEngine(User user, ThrottledWebSocketOut out) { } } + public static class ToggleFileMode extends BreadboardMessage { + public ToggleFileMode(User user, ThrottledWebSocketOut out) { + super(user, out); + } + } + public static class DeleteImage extends BreadboardMessage { final Long imageId; diff --git a/app/models/Experiment.java b/app/models/Experiment.java index f492670..0ef01ae 100644 --- a/app/models/Experiment.java +++ b/app/models/Experiment.java @@ -72,8 +72,7 @@ public class Experiment extends Model { public static final String ON_JOIN_STEP_NAME = "OnJoinStep"; public static final String ON_LEAVE_STEP_NAME = "OnLeaveStep"; - @Transient - public boolean fileMode = true; + public Boolean fileMode = false; /* * The CSS Style for the experiment @@ -157,8 +156,36 @@ public Experiment(Experiment experiment) { } } + public Boolean getFileMode() { + return this.fileMode; + } + + public void setFileMode(Boolean fileMode) { + this.fileMode = fileMode; + } + + public List getContent() { + // TODO: return content from file when filemode is true + return this.content; + } + + public String getStyle() { + // TODO: return style from file when filemode is true + return this.style; + } + + public String getClientHtml() { + // TODO: return clientHtml from file when filemode is true + return this.clientHtml; + } + + public String getClientGraph() { + // TODO: return clientGraph from file when filemode is true + return this.clientGraph; + } + public List getSteps() { - if (fileMode) { + if (getFileMode()) { ArrayList returnSteps = new ArrayList<>(); File devDirectory = new File(Play.application().path().toString() + "/dev"); String[] extensions = {"groovy"}; @@ -187,7 +214,8 @@ public List getSteps() { } public void addStep(Step step) { - if (fileMode) { + /* + if (getFileMode()) { File devDirectory = new File(Play.application().path().toString() + "/dev"); try { FileUtils.writeStringToFile(new File(devDirectory, step.name.concat(".groovy")), step.source); @@ -195,15 +223,92 @@ public void addStep(Step step) { Logger.error("Error writing step to the dev directory, check your permissions."); } } else { + */ this.steps.add(step); - } + //} } - public void setFileMode(boolean mode) { - this.fileMode = mode; - if (mode) { - // TODO: watch files here + public void toggleFileMode() { + this.setFileMode(!this.getFileMode()); + this.save(); + /* + Logger.debug("fileMode:"); + Logger.debug(this.getFileMode().toString()); + if (this.getFileMode()) { + // Start watching the dev directory in a new thread + this.fileWatcherActor = Akka.system().actorOf(new Props(FileWatcherActor.class)); + Long fileWatcherRate = play.Play.application().configuration().getMilliseconds("breadboard.fileWatcherRate"); + if (fileWatcherRate == null) { + Logger.debug("fileWatcherRate = null"); + fileWatcherRate = 1000L; + } + Scheduler scheduler = Akka.system().scheduler(); + this.cancellableFileWatcher = scheduler.schedule( + Duration.create(0, TimeUnit.MILLISECONDS), + Duration.create(fileWatcherRate, TimeUnit.MILLISECONDS), + this.fileWatcherActor, + new FileWatcherActorProtocol.FileWatch(), + Akka.system().dispatcher(), + null + ); + + Logger.debug((this.cancellableFileWatcher == null) ? "NULL" : this.cancellableFileWatcher.toString()); + + Logger.debug("Experiment:"); + Logger.debug(this.hashCode() + ""); + + F.Promise promise = F.Promise.promise( + new F.Function0() { + public Boolean apply() { + Path devPath = FileSystems.getDefault().getPath("dev"); + try { + watcher = FileSystems.getDefault().newWatchService(); + watchKey = devPath.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); + while (Experiment.this.getFileMode()) { + try { + watchKey = watcher.take(); + } catch (InterruptedException x) { + return false; + } + + for (WatchEvent event: watchKey.pollEvents()) { + WatchEvent ev = (WatchEvent) event; + if (ev.kind() == ENTRY_CREATE) { + Logger.debug("ENTRY_CREATE"); + } else if (ev.kind() == ENTRY_MODIFY) { + Logger.debug("ENTRY_MODIFY"); + } else if (ev.kind() == ENTRY_DELETE) { + Logger.debug("ENTRY_DELETE"); + } + } + + boolean valid = watchKey.reset(); + if (!valid) { + Logger.error("Can no longer watch the dev directory, was it deleted?"); + return false; + } + } + Logger.debug("Experiment.this.getFileMode():"); + Logger.debug(Experiment.this.getFileMode().toString()); + return true; + } catch (IOException ioe) { + Logger.error("Error watching dev directory for changes, check your permissions."); + return false; + } + } + } + ); + } else { + Logger.debug("Toggling file mode to false."); + Logger.debug("Experiment:"); + Logger.debug(this.hashCode() + ""); + Logger.debug(this.cancellableFileWatcher.toString()); + if (this.cancellableFileWatcher != null && !this.cancellableFileWatcher.isCancelled()) { + Logger.debug("Got here."); + this.cancellableFileWatcher.cancel(); + } } + */ } public void export() throws IOException { @@ -373,14 +478,6 @@ public Content getContentByName(String name) { return null; } - public Step getStep(Long id) { - for (Step s : steps) { - if (s.id.equals(id)) - return s; - } - return null; - } - public Parameter getParameterByName(String name) { for (Parameter p : parameters) { if (p.name.equals(name)) @@ -402,7 +499,7 @@ public boolean hasOnLeaveStep() { } public Step getOnJoinStep() { - for (Step step : steps) { + for (Step step : this.getSteps()) { if (ON_JOIN_STEP_NAME.equalsIgnoreCase(step.name)) { return step; } @@ -411,7 +508,7 @@ public Step getOnJoinStep() { } public Step getOnLeaveStep() { - for (Step step : steps) { + for (Step step : this.getSteps()) { if (ON_LEAVE_STEP_NAME.equalsIgnoreCase(step.name)) { return step; } @@ -427,9 +524,10 @@ public ObjectNode toJson() { experiment.put("id", id); experiment.put("name", name); experiment.put("uid", uid); + experiment.put("fileMode", getFileMode()); ArrayNode jsonSteps = experiment.putArray("steps"); - for (Step s : steps) { + for (Step s : getSteps()) { jsonSteps.add(s.toJson()); } @@ -472,4 +570,43 @@ public ObjectNode toJson() { public String toString() { return "Experiment(" + id + ")"; } + + /* + class WatchDevDirectory extends Thread { + public void run() { + Path devPath = FileSystems.getDefault().getPath("dev"); + try { + watcher = FileSystems.getDefault().newWatchService(); + watchKey = devPath.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); + while (true) { + try { + watchKey = watcher.take(); + } catch (InterruptedException x) { + return; + } + + for (WatchEvent event: watchKey.pollEvents()) { + WatchEvent ev = (WatchEvent) event; + if (ev.kind() == ENTRY_CREATE) { + Logger.debug("ENTRY_CREATE"); + } else if (ev.kind() == ENTRY_MODIFY) { + Logger.debug("ENTRY_MODIFY"); + } else if (ev.kind() == ENTRY_DELETE) { + Logger.debug("ENTRY_DELETE"); + } + } + + boolean valid = watchKey.reset(); + if (!valid) { + Logger.error("Can no longer watch the dev directory, was it deleted?"); + return; + } + } + } catch (IOException ioe) { + Logger.error("Error watching dev directory for changes, check your permissions."); + } + } + } + */ } + From 6947cbebda62b6494453dfb8cd9c06057cb75893 Mon Sep 17 00:00:00 2001 From: Mark McKnight Date: Tue, 5 Nov 2019 11:19:34 -0500 Subject: [PATCH 016/234] Instantiate FileWatcher when script engine is started. --- app/actors/FileWatcherActor.java | 83 ++++++++++++++++++++++++ app/actors/FileWatcherActorProtocol.java | 13 ++++ app/models/FileWatcher.java | 52 +++++++++++++++ app/models/ScriptBoard.java | 7 +- 4 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 app/actors/FileWatcherActor.java create mode 100644 app/actors/FileWatcherActorProtocol.java create mode 100644 app/models/FileWatcher.java diff --git a/app/actors/FileWatcherActor.java b/app/actors/FileWatcherActor.java new file mode 100644 index 0000000..aae3216 --- /dev/null +++ b/app/actors/FileWatcherActor.java @@ -0,0 +1,83 @@ +package actors; + +import actors.FileWatcherActorProtocol.FileWatch; +import akka.actor.UntypedActor; +import models.Admin; +import models.FileWatcher; +import play.Logger; + +import java.io.IOException; +import java.nio.file.*; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; +import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; +import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; + +public class FileWatcherActor extends UntypedActor { + private static DateFormat dateFormat; + private WatchService watcher; + private WatchKey watchKey; + + public FileWatcherActor() { + dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + } + + @Override + public void onReceive(Object message) { + if (message instanceof FileWatch) { + FileWatcher fileWatcher = ((FileWatch) message).fileWatcher; + // If fileMode for the selected experiment is false, do nothing + /* TODO: if there are multiple admins listening, they could each be watching different experiments which is weird in the context of a single file watcher */ + if ( fileWatcher.getAdminListeners().isEmpty() || fileWatcher.getAdminListeners().get(0).getUser().selectedExperiment == null || (! fileWatcher.getAdminListeners().get(0).getUser().selectedExperiment.getFileMode()) ) { + return; + } + fileWatcher.incrementUpdateIteration(); + Long updateIteration = fileWatcher.getUpdateIteration(); + if (updateIteration % 10 == 0) { + Logger.debug(dateFormat.format(new Date()) + " - FileWatch:" + updateIteration); + } + Path devPath = FileSystems.getDefault().getPath("dev"); + try { + boolean changed = false; + watcher = FileSystems.getDefault().newWatchService(); + watchKey = devPath.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); + try { + watchKey = watcher.take(); + } catch (InterruptedException x) { + return; + } + + // TODO: Reload step in script engine on change + for (WatchEvent event: watchKey.pollEvents()) { + changed = true; + WatchEvent ev = (WatchEvent) event; + if (ev.kind() == ENTRY_CREATE) { + Logger.debug("ENTRY_CREATE"); + } else if (ev.kind() == ENTRY_MODIFY) { + Logger.debug("ENTRY_MODIFY"); + } else if (ev.kind() == ENTRY_DELETE) { + Logger.debug("ENTRY_DELETE"); + } + } + + if (changed) { + // Something was changed, let's update all admin listeners + for(Admin a : fileWatcher.getAdminListeners()) { + a.update(); + } + } + + boolean valid = watchKey.reset(); + if (!valid) { + Logger.error("Can no longer watch the dev directory, was it deleted?"); + } + } catch (IOException ioe) { + Logger.error("Error watching dev directory for changes, check your permissions."); + } + } + } +} + diff --git a/app/actors/FileWatcherActorProtocol.java b/app/actors/FileWatcherActorProtocol.java new file mode 100644 index 0000000..7f7cecf --- /dev/null +++ b/app/actors/FileWatcherActorProtocol.java @@ -0,0 +1,13 @@ +package actors; + +import models.FileWatcher; + +public class FileWatcherActorProtocol { + public static class FileWatch { + final FileWatcher fileWatcher; + public FileWatch(FileWatcher fileWatcher) { + this.fileWatcher = fileWatcher; + } + } +} + diff --git a/app/models/FileWatcher.java b/app/models/FileWatcher.java new file mode 100644 index 0000000..87c5394 --- /dev/null +++ b/app/models/FileWatcher.java @@ -0,0 +1,52 @@ +package models; + +import actors.FileWatcherActor; +import actors.FileWatcherActorProtocol; +import akka.actor.ActorRef; +import akka.actor.Props; +import play.Logger; +import play.libs.Akka; +import scala.concurrent.duration.Duration; + +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; + +public class FileWatcher { + private Long updateIteration = 0L; + private ArrayList adminListeners = new ArrayList<>(); + static ActorRef fileWatcherActor; + + public FileWatcher(ArrayList adminListeners) { + this.adminListeners = adminListeners; + fileWatcherActor = Akka.system().actorOf(new Props(FileWatcherActor.class)); + Long fileWatchRate = play.Play.application().configuration().getMilliseconds("breadboard.fileWatchRate"); + if (fileWatchRate == null) { + Logger.debug("fileWatchRate = null"); + fileWatchRate = 100L; + } + Akka.system().scheduler().schedule( + Duration.create(0, TimeUnit.MILLISECONDS), + Duration.create(fileWatchRate, TimeUnit.MILLISECONDS), + fileWatcherActor, + new FileWatcherActorProtocol.FileWatch(this), + Akka.system().dispatcher(), + null + ); + } + + public ArrayList getAdminListeners() { + return this.adminListeners; + } + + public Experiment getExperiment() { + return this.getExperiment(); + } + + public void incrementUpdateIteration() { + this.updateIteration++; + } + + public Long getUpdateIteration() { + return this.updateIteration; + } +} diff --git a/app/models/ScriptBoard.java b/app/models/ScriptBoard.java index 88cbcac..7075b9e 100644 --- a/app/models/ScriptBoard.java +++ b/app/models/ScriptBoard.java @@ -1,6 +1,6 @@ package models; -import akka.actor.UntypedActor; +import akka.actor.*; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -36,6 +36,7 @@ public class ScriptBoard extends UntypedActor { private static PlayerActionsInterface playerActions; private static BreadboardGraphInterface graphInterface; private static BreadboardGraphChangedListener graphChangedListener; + private static FileWatcher fileWatcher; private static EventTracker eventTracker = new EventTracker(); private static Random rand = new Random(); @@ -152,6 +153,10 @@ private void resetEngine(Experiment experiment) throws IOException, ScriptExcept graphInterface.addListener(graphChangedListener); + if (fileWatcher == null) { + fileWatcher = new FileWatcher(admins); + } + gameListener.engine = engine; // When done, send a message to each Admin From 88c49478904a14760e01cdfb0d981895c83ca87e Mon Sep 17 00:00:00 2001 From: Mark McKnight Date: Tue, 5 Nov 2019 11:25:25 -0500 Subject: [PATCH 017/234] Design console changes to toggle file mode, disable step editing when file mode is true, and refresh steps when changed via file. --- frontend/app/design/controllers.js | 33 ++++++++++++++++++++++---- frontend/app/design/design.sass | 3 +++ frontend/app/steps/steps.controller.js | 23 ++++++++++++++++++ frontend/app/steps/steps.directive.js | 4 +++- frontend/app/steps/steps.template.html | 5 ++-- frontend/app/templates/home.html | 13 ++++++++++ 6 files changed, 73 insertions(+), 8 deletions(-) diff --git a/frontend/app/design/controllers.js b/frontend/app/design/controllers.js index d002c88..34e4edd 100644 --- a/frontend/app/design/controllers.js +++ b/frontend/app/design/controllers.js @@ -332,7 +332,7 @@ function ($scope, $breadboardFactory, $timeout, $http, $state, csvService, confi }); }; - $scope.openImportDialog = function(){ + $scope.openImportDialog = function() { $('#importExperimentDialog').dialog({ title: "Import experiment", @@ -341,6 +341,13 @@ function ($scope, $breadboardFactory, $timeout, $http, $state, csvService, confi }; + $scope.toggleDevMode = function() { + $breadboardFactory.send( + { + "action": "ToggleFileMode" + }); + } + $scope.createExperiment = function () { $('#newExperimentDialog').dialog('close'); $breadboardFactory.send( @@ -656,13 +663,29 @@ function ($scope, $breadboardFactory, $timeout, $http, $state, csvService, confi position: [margin, topDivHeight], autoOpen: false, dialogClass: 'steps-dialog', - buttons: { - 'Save': function () { - saveSteps(); + buttons: [ + { + text: 'Save', + disabled: false, + click: function () { + saveSteps(); + } } - } + ] }; + $scope.$watch('breadboard.experiment.fileMode', function(newValue) { + $('#stepsDiv').dialog('option', 'buttons', [ + { + text: 'Save', + disabled: newValue, + click: function () { + saveSteps(); + } + } + ]); + }); + $scope.customizeDialogOptions = { title: 'Customize', autoOpen: false, diff --git a/frontend/app/design/design.sass b/frontend/app/design/design.sass index f37d0a5..dbb5331 100644 --- a/frontend/app/design/design.sass +++ b/frontend/app/design/design.sass @@ -359,6 +359,9 @@ label.fixed-width height: 100% width: 100% +div.read-only > .CodeMirror + background-color: #d9edf7 + #outputDiv white-space: pre-wrap diff --git a/frontend/app/steps/steps.controller.js b/frontend/app/steps/steps.controller.js index b907d97..99a96cb 100644 --- a/frontend/app/steps/steps.controller.js +++ b/frontend/app/steps/steps.controller.js @@ -15,6 +15,7 @@ export default function StepsCtrl($scope, StepsSrv, STATUS, $timeout, orderBy, a vm.createStatus = STATUS.UNLOADED; vm.error = ''; vm.codeMirrorOptions = { + readOnly: ($scope.readOnly) ? 'nocursor' : false, lineNumbers: true, matchBrackets: true, mode: 'text/x-groovy', @@ -28,6 +29,14 @@ export default function StepsCtrl($scope, StepsSrv, STATUS, $timeout, orderBy, a showCursorWhenSelecting: true }; + $scope.$watch('readOnly', function(newValue) { + let codeMirrorInstances = document.getElementById('stepTab').getElementsByClassName('CodeMirror'); + for (let i = 0; i < codeMirrorInstances.length; i++) { + let cm = codeMirrorInstances[i].CodeMirror; + cm.setOption('readOnly', ((newValue) ? 'nocursor' : false)); + } + }); + // Any reason we can't just pass the experiment steps array into the directive directly? Maybe because this will eventually be a separate AJAX request? function updateSteps(){ StepsSrv.getSteps($scope.experimentId) @@ -43,6 +52,20 @@ export default function StepsCtrl($scope, StepsSrv, STATUS, $timeout, orderBy, a updateSteps(); $scope.$watch('experimentId', updateSteps); + // In the case that fileMode = true, we can safely watch the Steps and update when they change. + $scope.$watch('experiment.steps', updateFromFile, true); + + function updateFromFile() { + if ($scope.readOnly) { + vm.steps = orderBy($scope.experiment.steps, 'name', false); + angular.forEach(vm.steps, function(step) { + // TODO: Comparing by name is necessary because steps read from file have no ID; if that changes, compare by ID. + if (step.name === vm.selectedStep.name) { + vm.selectedStep = step; + } + }); + } + } function selectStep(step) { if (step === vm.selectedStep) return; diff --git a/frontend/app/steps/steps.directive.js b/frontend/app/steps/steps.directive.js index b25e6eb..83eebe1 100644 --- a/frontend/app/steps/steps.directive.js +++ b/frontend/app/steps/steps.directive.js @@ -9,7 +9,9 @@ angular.module('breadboard.steps').directive('steps', function(){ restrict: 'E', scope: { experimentId: '=', - actions: '=' + experiment: '=', + actions: '=', + readOnly: '=' }, link: function(scope){ angular.extend(scope.actions, { diff --git a/frontend/app/steps/steps.template.html b/frontend/app/steps/steps.template.html index b20a1a4..7c32091 100644 --- a/frontend/app/steps/steps.template.html +++ b/frontend/app/steps/steps.template.html @@ -7,8 +7,9 @@ select-step="vm.selectStep" delete-step="vm.deleteStep" selected-step="vm.selectedStep"> -