diff --git a/.gitignore b/.gitignore index 5d31208f..30c2eac1 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ stats.json lib docs/code/* docs/js/planner* +distances diff --git a/README.md b/README.md index 5d352d5d..b300deee 100644 --- a/README.md +++ b/README.md @@ -9,37 +9,41 @@ $ npm install plannerjs Include it in the browser: ```html + +... + + ``` Include it in your JavaScript project: ```javascript -const Planner = require('plannerjs').default; +const { BasicTrainPlanner, Units } = require('plannerjs'); // or -import Planner from 'plannerjs'; +import { BasicTrainPlanner, Units } from 'plannerjs'; ``` Use it in both environments: ```javascript -const planner = new Planner(); +const planner = new BasicTrainPlanner(); planner.query({ from: "http://irail.be/stations/NMBS/008812005", // Brussels North to: "http://irail.be/stations/NMBS/008892007", // Ghent-Sint-Pieters - minimumDepartureTime: new Date("Mon Feb 11 2019 16:00:00"), - maximumArrivalTime: new Date("Mon Feb 11 2019 19:00:00"), - publicTransportOnly: true, + minimumDepartureTime: new Date(), walkingSpeed: 3, // KmH minimumWalkingSpeed: 3, // KmH maximumWalkingDistance: 200, // meters - minimumTransferDuration: Planner.Units.fromMinutes(1), - maximumTransferDuration: Planner.Units.fromMinutes(30), + minimumTransferDuration: Units.fromMinutes(1), + maximumTransferDuration: Units.fromMinutes(30), - maximumTravelDuration: Planner.Units.fromHours(1.5), + maximumTravelDuration: Units.fromHours(1.5), maximumTransfers: 4, }) diff --git a/docs/css/style.css b/docs/css/style.css index dfb84dd0..fdec3144 100644 --- a/docs/css/style.css +++ b/docs/css/style.css @@ -1,10 +1,86 @@ -html, -body { +html, body { margin: 0; height: 100%; width: 100%; } +#optionsBar { + position: absolute; + text-align: center; + width: 100%; + background-color: white; + z-index: 900; +} + +#optionsBar .optionLabel { + font-size: 19px; + font-family: sans-serif; + vertical-align: middle; + top: 6px; + position: relative; +} + +.switch { + position: relative; + display: inline-block; + width: 60px; + height: 34px; +} + +.switch input { + opacity: 0; + width: 0; + height: 0; +} + +.slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #ccc; + -webkit-transition: .4s; + transition: .4s; +} + +.slider:before { + position: absolute; + content: ""; + height: 26px; + width: 26px; + left: 4px; + bottom: 4px; + background-color: white; + -webkit-transition: .4s; + transition: .4s; +} + +input:checked+.slider { + background-color: #2196F3; +} + +input:focus+.slider { + box-shadow: 0 0 1px #2196F3; +} + +input:checked+.slider:before { + -webkit-transform: translateX(26px); + -ms-transform: translateX(26px); + transform: translateX(26px); +} + +/* Rounded sliders */ + +.slider.round { + border-radius: 34px; +} + +.slider.round:before { + border-radius: 50%; +} + #mapid { height: 100%; } @@ -23,7 +99,7 @@ body { width: 500px; } -#results > .path { +#results>.path { margin: 10px; background: rgba(255, 255, 255, .8); border: 1px solid #ccc; @@ -33,14 +109,14 @@ body { flex-wrap: wrap; } -#results > .path > .header { +#results>.path>.header { padding: 10px; - background: rgba(0, 0, 0, .25); + background: rgba(0, 0, 0, .7); color: #fff; text-shadow: 0 0 1px black; } -#results > .path > .step { +#results>.path>.step { display: flex; flex-direction: row; margin: 10px; @@ -53,7 +129,10 @@ body { background-repeat: no-repeat; } -.details { +.details {} + +.travelMode.profile { + background-image: url(data:image/svg+xml;base64,PHN2ZyBhcmlhLWhpZGRlbj0idHJ1ZSIgZGF0YS1wcmVmaXg9ImZhcyIgZGF0YS1pY29uPSJ3YWxraW5nIiBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtd2Fsa2luZyBmYS13LTEwIiByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDMyMCA1MTIiPjxwYXRoIGZpbGw9ImN1cnJlbnRDb2xvciIgZD0iTTIwOCA5NmMyNi41IDAgNDgtMjEuNSA0OC00OFMyMzQuNSAwIDIwOCAwcy00OCAyMS41LTQ4IDQ4IDIxLjUgNDggNDggNDh6bTk0LjUgMTQ5LjFsLTIzLjMtMTEuOC05LjctMjkuNGMtMTQuNy00NC42LTU1LjctNzUuOC0xMDIuMi03NS45LTM2LS4xLTU1LjkgMTAuMS05My4zIDI1LjItMjEuNiA4LjctMzkuMyAyNS4yLTQ5LjcgNDYuMkwxNy42IDIxM2MtNy44IDE1LjgtMS41IDM1IDE0LjIgNDIuOSAxNS42IDcuOSAzNC42IDEuNSA0Mi41LTE0LjNMODEgMjI4YzMuNS03IDkuMy0xMi41IDE2LjUtMTUuNGwyNi44LTEwLjgtMTUuMiA2MC43Yy01LjIgMjAuOC40IDQyLjkgMTQuOSA1OC44bDU5LjkgNjUuNGM3LjIgNy45IDEyLjMgMTcuNCAxNC45IDI3LjdsMTguMyA3My4zYzQuMyAxNy4xIDIxLjcgMjcuNiAzOC44IDIzLjMgMTcuMS00LjMgMjcuNi0yMS43IDIzLjMtMzguOGwtMjIuMi04OWMtMi42LTEwLjMtNy43LTE5LjktMTQuOS0yNy43bC00NS41LTQ5LjcgMTcuMi02OC43IDUuNSAxNi41YzUuMyAxNi4xIDE2LjcgMjkuNCAzMS43IDM3bDIzLjMgMTEuOGMxNS42IDcuOSAzNC42IDEuNSA0Mi41LTE0LjMgNy43LTE1LjcgMS40LTM1LjEtMTQuMy00M3pNNzMuNiAzODUuOGMtMy4yIDguMS04IDE1LjQtMTQuMiAyMS41bC01MCA1MC4xYy0xMi41IDEyLjUtMTIuNSAzMi44IDAgNDUuM3MzMi43IDEyLjUgNDUuMiAwbDU5LjQtNTkuNGM2LjEtNi4xIDEwLjktMTMuNCAxNC4yLTIxLjVsMTMuNS0zMy44Yy01NS4zLTYwLjMtMzguNy00MS44LTQ3LjQtNTMuN2wtMjAuNyA1MS41eiI+PC9wYXRoPjwvc3ZnPg==); } .travelMode.walking { @@ -68,24 +147,18 @@ body { background-image: url(data:image/svg+xml;base64,PHN2ZyBhcmlhLWhpZGRlbj0idHJ1ZSIgZm9jdXNhYmxlPSJmYWxzZSIgZGF0YS1wcmVmaXg9ImZhcyIgZGF0YS1pY29uPSJidXMiIGNsYXNzPSJzdmctaW5saW5lLS1mYSBmYS1idXMgZmEtdy0xNiIgcm9sZT0iaW1nIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIj48cGF0aCBmaWxsPSJjdXJyZW50Q29sb3IiIGQ9Ik00ODggMTI4aC04VjgwYzAtNDQuOC05OS4yLTgwLTIyNC04MFMzMiAzNS4yIDMyIDgwdjQ4aC04Yy0xMy4yNSAwLTI0IDEwLjc0LTI0IDI0djgwYzAgMTMuMjUgMTAuNzUgMjQgMjQgMjRoOHYxNjBjMCAxNy42NyAxNC4zMyAzMiAzMiAzMnYzMmMwIDE3LjY3IDE0LjMzIDMyIDMyIDMyaDMyYzE3LjY3IDAgMzItMTQuMzMgMzItMzJ2LTMyaDE5MnYzMmMwIDE3LjY3IDE0LjMzIDMyIDMyIDMyaDMyYzE3LjY3IDAgMzItMTQuMzMgMzItMzJ2LTMyaDYuNGMxNiAwIDI1LjYtMTIuOCAyNS42LTI1LjZWMjU2aDhjMTMuMjUgMCAyNC0xMC43NSAyNC0yNHYtODBjMC0xMy4yNi0xMC43NS0yNC0yNC0yNHpNMTEyIDQwMGMtMTcuNjcgMC0zMi0xNC4zMy0zMi0zMnMxNC4zMy0zMiAzMi0zMiAzMiAxNC4zMyAzMiAzMi0xNC4zMyAzMi0zMiAzMnptMTYtMTEyYy0xNy42NyAwLTMyLTE0LjMzLTMyLTMyVjEyOGMwLTE3LjY3IDE0LjMzLTMyIDMyLTMyaDI1NmMxNy42NyAwIDMyIDE0LjMzIDMyIDMydjEyOGMwIDE3LjY3LTE0LjMzIDMyLTMyIDMySDEyOHptMjcyIDExMmMtMTcuNjcgMC0zMi0xNC4zMy0zMi0zMnMxNC4zMy0zMiAzMi0zMiAzMiAxNC4zMyAzMiAzMi0xNC4zMyAzMi0zMiAzMnoiPjwvcGF0aD48L3N2Zz4=); } -.duration { - margin-bottom: 5px; - margin-top: 5px; -} - -.enterConnectionId, -.exitConnectionId { +.enterConnectionId, .exitConnectionId { opacity: 0.5; } #actions { position: absolute; - top: 10px; + top: 41px; right: 10px; z-index: 500; } -#actions > button { +#actions>button { border-radius: 100px; background: rgba(255, 255, 255, .8); font-size: 2em; @@ -94,7 +167,7 @@ body { #prefetch { position: absolute; - top: 10px; + top: 41px; left: 54px; max-width: calc(100% - 225px); z-index: 500; @@ -123,3 +196,16 @@ body { max-width: 100%; overflow: hidden; } + +#loading { + display: none; + position: fixed; + z-index: 900; + left: 89%; + top: 80%; + width: 9%; +} + +.leaflet-touch .leaflet-control-layers, .leaflet-touch .leaflet-bar { + top: 25px; +} \ No newline at end of file diff --git a/docs/example.html b/docs/example.html index 919fae83..092cee32 100644 --- a/docs/example.html +++ b/docs/example.html @@ -1,26 +1,38 @@ + Map + integrity="sha512-puBpdR0798OZvTTbP4A8Ix/l+A4dHDD0DGqYW6RQ+9jxkRFclaxxQb/SJAWZfWAkuyeQUytO7+7N4QKrDh+drA==" + crossorigin="" /> + integrity="sha512-nMMmRyTVoLYqjP9hrbed9S+FzjZHW5gY1TWCHA5ckwXZBadntCNs8kEqAWdrb9O7rxbCaA4lKTIWjDXZxflOcA==" + crossorigin=""> + -
-
-
-
-
-
- -
- - +
+ Use Public Transport: + + +
+ +
+
+
+
+
+
+ +
+ + - + + \ No newline at end of file diff --git a/docs/img/rocket.gif b/docs/img/rocket.gif new file mode 100644 index 00000000..995da077 Binary files /dev/null and b/docs/img/rocket.gif differ diff --git a/docs/index.html b/docs/index.html index f3786b3d..6d150133 100644 --- a/docs/index.html +++ b/docs/index.html @@ -2,9 +2,9 @@ Doc Planner.js – The ultimate JavaScript route planning framework - - - + + + @@ -34,18 +34,12 @@

Getting Started

Demo

-

- See the Pen Using the new JavaScript route - planner on CodePen. -

+

+ See the Pen + Planner.js results NMBS by Julian Rojas (@julianrojas87) + on CodePen. +

+

Architecture

diff --git a/docs/js/example.js b/docs/js/example.js index b64c5f2b..1d59374f 100644 --- a/docs/js/example.js +++ b/docs/js/example.js @@ -12,17 +12,19 @@ L.tileLayer( } ).addTo(map); -const planner = new Planner(); +const planner = new PlannerJS.BasicTrainPlanner(); planner.prefetchStops(); planner.prefetchConnections(); let plannerResult; +const usePublicTransport = document.querySelector('#usePublicTransport'); const resetButton = document.querySelector("#reset"); const results = document.querySelector("#results"); const prefetchWrapper = document.querySelector("#prefetch"); const prefetchBar = document.querySelector("#prefetch-bar"); let prefetchBarWidth = 0; +let roadNetworkOnly = false; let lines = []; let polyLines = []; @@ -33,6 +35,12 @@ let prefetchViews = []; let firstPrefetch; +const removeStops = () => { + for (const stop of allStops) { + stop.remove(); + } +}; + const removeLines = () => { for (const line of polyLines) { line.remove(); @@ -40,7 +48,6 @@ const removeLines = () => { lines = []; polyLines = []; - lines = []; }; const removeResultObjects = () => { @@ -65,14 +72,29 @@ const removePrefetchView = () => { } }; +usePublicTransport.onclick = e => { + if (!usePublicTransport.checked) { + roadNetworkOnly = true; + removeStops(); + } else { + roadNetworkOnly = false; + for (const stop of allStops) { + stop.addTo(map); + } + } +}; + resetButton.onclick = (e) => { + document.getElementById('loading').style.display = 'none'; removeLines(); removeResultObjects(); query = []; results.innerHTML = ""; - for (const stop of allStops) { - stop.addTo(map); + if (usePublicTransport.checked) { + for (const stop of allStops) { + stop.addTo(map); + } } if (plannerResult) { @@ -93,13 +115,19 @@ const getPrefetchViewWidth = (start, stop) => { planner.getAllStops().then(stops => { for (const stop of stops) { - if (stop["http://semweb.mmlab.be/ns/stoptimes#avgStopTimes"] > 100) { + if (stop["avgStopTimes"] > 100000) { const marker = L.marker([stop.latitude, stop.longitude]).addTo(map); marker.bindPopup(stop.name); allStops.push(marker); + marker.on('mouseover', e => { + marker.openPopup(); + }); + marker.on('mouseout', e => { + marker.closePopup(); + }); marker.on("click", e => { selectRoute(e, stop.id); }); @@ -107,11 +135,11 @@ planner.getAllStops().then(stops => { } }); -planner - .on("query", query => { +PlannerJS.EventBus + .on(PlannerJS.EventType.Query, query => { console.log("Query", query); }) - .on("sub-query", query => { + .on(PlannerJS.EventType.SubQuery, query => { const { minimumDepartureTime, maximumArrivalTime, maximumTravelDuration } = query; console.log( @@ -124,7 +152,7 @@ planner removeLines(); }) - .on("initial-reachable-stops", reachableStops => { + .on(PlannerJS.EventType.InitialReachableStops, reachableStops => { console.log("initial", reachableStops); reachableStops.map(({ stop }) => { const startMarker = L.marker([stop.latitude, stop.longitude]).addTo(map); @@ -134,7 +162,7 @@ planner resultObjects.push(startMarker); }); }) - .on("final-reachable-stops", reachableStops => { + .on(PlannerJS.EventType.FinalReachableStops, reachableStops => { console.log("final", reachableStops); reachableStops.map(({ stop }) => { @@ -145,7 +173,7 @@ planner resultObjects.push(startMarker); }); }) - .on("added-new-transfer-profile", ({ departureStop, arrivalStop, amountOfTransfers }) => { + .on(PlannerJS.EventType.AddedNewTransferProfile, ({ departureStop, arrivalStop, amountOfTransfers }) => { const newLine = [ [departureStop.latitude, departureStop.longitude], @@ -173,7 +201,7 @@ planner polyLines.push(polyline); } }) - .on("connection-prefetch", (departureTime) => { + .on(PlannerJS.EventType.ConnectionPrefetch, (departureTime) => { if (!firstPrefetch) { firstPrefetch = departureTime; @@ -193,7 +221,7 @@ planner drawPrefetchViews(); } }) - .on("connection-iterator-view", (lowerBound, upperBound, completed) => { + .on(PlannerJS.EventType.ConnectionIteratorView, (lowerBound, upperBound, completed) => { if (!lowerBound || !upperBound) { return; } @@ -224,7 +252,7 @@ planner elem.style.backgroundColor = "limegreen"; } }) - .on("warning", (warning) => { + .on(PlannerJS.EventType.Warning, (warning) => { console.warn(warning); }); @@ -275,216 +303,217 @@ function selectRoute(e, id) { } } +function appendLeadingZeroes(n) { + if (n <= 9) { + return "0" + n; + } + return n +} + function dateToTimeString(date) { - const hours = date.getHours(); - const minutes = date.getMinutes(); - return `${hours < 10 ? "0" + hours : hours}:${minutes < 10 ? "0" + minutes : minutes}`; + return date.getFullYear() + "-" + + appendLeadingZeroes(date.getMonth() + 1) + "-" + + appendLeadingZeroes(date.getDate()) + " " + + appendLeadingZeroes(date.getHours()) + ":" + + appendLeadingZeroes(date.getMinutes()) + ":" + + appendLeadingZeroes(date.getSeconds() + ) } map.on("click", onMapClick); function getRandomColor() { - const letters = "0123456789ABCDEF"; + const letters = "123456789"; let color = "#"; for (let i = 0; i < 6; i++) { - color += letters[Math.floor(Math.random() * 16)]; + color += letters[Math.floor(Math.random() * 9)]; } return color; } -function getTravelTime(path) { - return path.steps.reduce((time, step) => time + step.duration.minimum, 0) / 60000; -} - -function getTransferTime(path) { - let time = 0; - - if (path.steps.length < 2) { - return time; - } - - for (let i = 0; i < path.steps.length - 1; i++) { - let stepX = path.steps[i]; - let stepY = path.steps[i + 1]; - - time += stepY.startTime - stepX.stopTime; - } - - return time / 60000; -} - -function addResultPanel(path, color) { +function addResultPanel(query, path, color) { const pathElement = document.createElement("div"); pathElement.className = "path"; - const firstStep = path.steps[0]; - const lastStep = path.steps[path.steps.length - 1]; + const travelTime = path.getTravelTime(); + const startTime = path.getDepartureTime(query); + const stopTime = path.getArrivalTime(query); + const transferTime = Number.isNaN(path.getTransferTime()) ? 0 : path.getTransferTime(); const headerElement = document.createElement("div"); headerElement.className = "header"; headerElement.innerHTML = ` - Departure: ${dateToTimeString(firstStep.startTime)}
- Arrival: ${dateToTimeString(lastStep.stopTime)}
- Travel time: ${getTravelTime(path)} min
- Transfer time: ${getTransferTime(path)} min + Departure: ${dateToTimeString(startTime)}
+ Arrival: ${dateToTimeString(stopTime)}
+ Travel time: ${Number(travelTime / 60000).toFixed(1)} min
+ Transfer time: ${Number(transferTime / 60000).toFixed(1)} min `; pathElement.appendChild(headerElement); + for (const leg of path.legs) { + drawLeg(leg, pathElement, color); + } - path.steps.forEach(step => { - const stepElement = document.createElement("div"); - stepElement.className = "step"; - - const travelMode = document.createElement("div"); - travelMode.className = "travelMode " + step.travelMode; - stepElement.appendChild(travelMode); - - const details = document.createElement("div"); - details.className = "details"; - stepElement.appendChild(details); - - const startLocation = document.createElement("div"); - startLocation.className = "startLocation"; - startLocation.innerHTML = - "Start location: " + step.startLocation.name; - details.appendChild(startLocation); - - if (step.startTime) { - const startTime = document.createElement("div"); - startTime.className = "startTime"; - startTime.innerHTML = step.startTime; - details.appendChild(startTime); - } + results.appendChild(pathElement); +} - if (step.enterConnectionId) { - const enterConnectionId = document.createElement("div"); - enterConnectionId.className = "enterConnectionId"; - enterConnectionId.innerHTML = - "Enter connection: " + step.enterConnectionId; - details.appendChild(enterConnectionId); - } +function drawLeg(leg, pathElement, color) { + const stepElement = document.createElement("div"); + stepElement.className = "step"; + + const travelMode = document.createElement("div"); + travelMode.className = "travelMode " + leg.travelMode; + stepElement.appendChild(travelMode); + + const details = document.createElement("div"); + details.className = "details"; + stepElement.appendChild(details); + + const startLocation = document.createElement("div"); + startLocation.className = "startLocation"; + let startln; + if (leg.getStartLocation().name) { + startln = `${leg.getStartLocation().name} `; + } else { + startln = `${Number(leg.getStartLocation().latitude).toFixed(4)}, ${Number(leg.getStartLocation().longitude).toFixed(4)}`; + } + startLocation.innerHTML = "Start location: " + startln; + details.appendChild(startLocation); + + if (leg.getStartTime()) { + const startTime = document.createElement("div"); + startTime.className = "startTime"; + startTime.innerHTML = `Departure time: ${dateToTimeString(leg.getStartTime())}`; + details.appendChild(startTime); + } - if (step.duration) { - const duration = document.createElement("div"); - duration.className = "duration"; - duration.innerHTML = - "Duration: minimum " + - step.duration.minimum / (60 * 1000) + - "min"; - details.appendChild(duration); - } + if (leg.getExpectedDuration()) { + const duration = document.createElement("div"); + duration.className = "duration"; + duration.innerHTML = + `Duration: ${Number(leg.getExpectedDuration() / (60 * 1000)).toFixed(1)} min`; + details.appendChild(duration); + } - const stopLocation = document.createElement("div"); - stopLocation.className = "stopLocation"; - stopLocation.innerHTML = "Stop location: " + step.stopLocation.name; - details.appendChild(stopLocation); + const stopLocation = document.createElement("div"); + stopLocation.className = "stopLocation"; + let stopln; + if (leg.getStopLocation().name) { + stopln = `${leg.getStopLocation().name} `; + } else { + stopln = `${Number(leg.getStopLocation().latitude).toFixed(4)}, ${Number(leg.getStopLocation().longitude).toFixed(4)}`; + } + stopLocation.innerHTML = "Stop location: " + stopln; + details.appendChild(stopLocation); + + if (leg.getStopTime()) { + const stopTime = document.createElement("div"); + stopTime.className = "stopTime"; + stopTime.innerHTML = `Arrival time: ${dateToTimeString(leg.getStopTime())}`; + details.appendChild(stopTime); + } - if (step.stopTime) { - const stopTime = document.createElement("div"); - stopTime.className = "stopTime"; - stopTime.innerHTML = step.stopTime; - details.appendChild(stopTime); - } + pathElement.style.borderLeft = "5px solid " + color; - if (step.exitConnectionId) { - const exitConnectionId = document.createElement("div"); - exitConnectionId.className = "exitConnectionId"; - exitConnectionId.innerHTML = - "Exit connection: " + step.exitConnectionId; - details.appendChild(exitConnectionId); - } + pathElement.appendChild(stepElement); +} - pathElement.style.borderLeft = "5px solid " + color; +function addResultToMap(q, path) { + for (const leg of path.legs) { + addConnectionMarkers(leg); + } +} - pathElement.appendChild(stepElement); - }); +function addConnectionMarkers(leg) { + const startLocation = leg.getStartLocation(); + const stopLocation = leg.getStopLocation(); + const travelMode = leg.getTravelMode(); - results.appendChild(pathElement); -} + const startMarker = L.marker([ + startLocation.latitude, + startLocation.longitude + ]).addTo(map); -function addResultToMap(path, color) { - path.steps.forEach(step => { - const { startLocation, stopLocation, travelMode } = step; + startMarker.bindPopup(startLocation.name); - const startMarker = L.marker([ - startLocation.latitude, - startLocation.longitude - ]).addTo(map); + const stopMarker = L.marker([ + stopLocation.latitude, + stopLocation.longitude + ]).addTo(map); - startMarker.bindPopup(startLocation.name); + stopMarker.bindPopup(stopLocation.name); - const stopMarker = L.marker([ - stopLocation.latitude, - stopLocation.longitude - ]).addTo(map); + resultObjects.push(startMarker, stopMarker); - stopMarker.bindPopup(stopLocation.name); + const color = getRandomColor(); + for (const step of leg.steps) { const line = [ - [startLocation.latitude, startLocation.longitude], - [stopLocation.latitude, stopLocation.longitude] + [step.startLocation.latitude, step.startLocation.longitude], + [step.stopLocation.latitude, step.stopLocation.longitude] ]; - const polyline = new L.Polyline(line, { - color, - weight: 5, - smoothFactor: 1, - opacity: 0.7, - dashArray: travelMode === "walking" ? "8 8" : null - }).addTo(map); + drawLineBetweenPoints(line, travelMode, color); + } +} - resultObjects.push(startMarker, stopMarker, polyline); - }); +function drawLineBetweenPoints(line, travelMode, color) { + const polyline = new L.Polyline(line, { + color, + weight: 5, + smoothFactor: 1, + opacity: 0.7, + dashArray: travelMode === "profile" ? "8 8" : null + }).addTo(map); + + resultObjects.push(polyline); } function runQuery(query) { - console.log(query); - - const maximumWalkingDistance = 200; + document.getElementById('loading').style.display = 'block'; const departureCircle = L.circle([query[0].latitude, query[0].longitude], { color: "limegreen", fillColor: "limegreen", fillOpacity: 0.5, - radius: maximumWalkingDistance }).addTo(map); const arrivalCircle = L.circle([query[1].latitude, query[1].longitude], { color: "red", fillColor: "red", fillOpacity: 0.5, - radius: maximumWalkingDistance }).addTo(map); resultObjects.push(departureCircle, arrivalCircle); let i = 0; let amount = 4; + const q = { + roadNetworkOnly: roadNetworkOnly, + from: query[0], + to: query[1], + minimumDepartureTime: new Date(), + maximumTransferDuration: PlannerJS.Units.fromMinutes(30), // 30 minutes + minimumWalkingSpeed: 3 + }; planner - .query({ - publicTransportOnly: true, - from: query[0], - to: query[1], - minimumDepartureTime: new Date(), - maximumWalkingDistance, - maximumTransferDuration: Planner.Units.fromMinutes(30), // 30 minutes - minimumWalkingSpeed: 3 - }) + .query(q) .take(amount) .on("error", (error) => { console.error(error); }) - .on("data", path => { + .on("data", async path => { + const completePath = await planner.completePath(path); + console.log('Path', completePath); i++; - const color = getRandomColor(); - - addResultPanel(path, color); - addResultToMap(path, color); + addResultPanel(q, completePath, color); + addResultToMap(q, completePath); }) .on("end", () => { + document.getElementById('loading').style.display = 'none'; if (i < amount) { const noMore = document.createElement("div"); noMore.className = "path"; diff --git a/jest.config.js b/jest.config.js index 40f0107f..63db69fc 100644 --- a/jest.config.js +++ b/jest.config.js @@ -14,5 +14,5 @@ module.exports = { "json", "node" ], - "setupTestFrameworkScriptFile": "/setup-jest.js" + "setupFilesAfterEnv": ["/setup-jest.js"] }; diff --git a/package-lock.json b/package-lock.json index 60e90144..3d66fe15 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,37 +1,421 @@ { "name": "plannerjs", - "version": "0.0.3-alpha", + "version": "0.2.0", "lockfileVersion": 1, "requires": true, "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==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", "dev": true, "requires": { "@babel/highlight": "^7.0.0" } }, - "@babel/highlight": { + "@babel/core": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.6.2.tgz", + "integrity": "sha512-l8zto/fuoZIbncm+01p8zPSDZu/VuuJhAfA7d/AbzM09WR7iVhavvfNDYCNpo1VvLk6E6xgAoP9P+/EMJHuRkQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.6.2", + "@babel/helpers": "^7.6.2", + "@babel/parser": "^7.6.2", + "@babel/template": "^7.6.0", + "@babel/traverse": "^7.6.2", + "@babel/types": "^7.6.0", + "convert-source-map": "^1.1.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "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 + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.2.tgz", + "integrity": "sha512-j8iHaIW4gGPnViaIHI7e9t/Hl8qLjERI6DcV9kEpAIDJsAOrcnXqRS7t+QbhL76pwbtqP+QCQLL0z1CyVmtjjQ==", + "dev": true, + "requires": { + "@babel/types": "^7.6.0", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-function-name": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", + "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", + "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-plugin-utils": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", - "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", + "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", + "dev": true + }, + "@babel/helper-split-export-declaration": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", + "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", + "dev": true, + "requires": { + "@babel/types": "^7.4.4" + } + }, + "@babel/helpers": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.6.2.tgz", + "integrity": "sha512-3/bAUL8zZxYs1cdX2ilEE0WobqbCmKWr/889lf2SS0PpDcpEIY8pb1CCyz0pEcX3pEb+MCbks1jIokz2xLtGTA==", + "dev": true, + "requires": { + "@babel/template": "^7.6.0", + "@babel/traverse": "^7.6.2", + "@babel/types": "^7.6.0" + } + }, + "@babel/highlight": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", "dev": true, "requires": { "chalk": "^2.0.0", "esutils": "^2.0.2", "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.2.tgz", + "integrity": "sha512-mdFqWrSPCmikBoaBYMuBulzTIKuXVPtEISFbRRVNwMWpCms/hmE2kRq0bblUHaNRKrjRlmVbx1sDHmjmRgD2Xg==", + "dev": true + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", + "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/template": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.6.0.tgz", + "integrity": "sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.0" + } + }, + "@babel/traverse": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.2.tgz", + "integrity": "sha512-8fRE76xNwNttVEF2TwxJDGBLWthUkHWSldmfuBzVRmEDWOtu4XdINTgN7TDWzuLg4bbeIMLvfMFD9we5YcWkRQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.6.2", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/parser": "^7.6.2", + "@babel/types": "^7.6.0", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" }, "dependencies": { - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "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 + } + } + }, + "@babel/types": { + "version": "7.6.1", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.1.tgz", + "integrity": "sha512-X7gdiuaCmA0uRjCmRtYJNAVCc/q+5xSgsfKJHqMN4iNLILX39677fJE1O40arPMh0TTtS9ItH67yre6c7k6t0g==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "@cnakazawa/watch": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.3.tgz", + "integrity": "sha512-r5160ogAvGyHsal38Kux7YYtodEKOj89RGb28ht1jh3SJb08VwRwAKKJL0bGb04Zd/3r9FL3BFIc3bBidYffCA==", + "dev": true, + "requires": { + "exec-sh": "^0.3.2", + "minimist": "^1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "@jest/console": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", + "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", + "dev": true, + "requires": { + "@jest/source-map": "^24.9.0", + "chalk": "^2.0.1", + "slash": "^2.0.0" + } + }, + "@jest/core": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.9.0.tgz", + "integrity": "sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A==", + "dev": true, + "requires": { + "@jest/console": "^24.7.1", + "@jest/reporters": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-changed-files": "^24.9.0", + "jest-config": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-resolve-dependencies": "^24.9.0", + "jest-runner": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "jest-watcher": "^24.9.0", + "micromatch": "^3.1.10", + "p-each-series": "^1.0.0", + "realpath-native": "^1.1.0", + "rimraf": "^2.5.4", + "slash": "^2.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "graceful-fs": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", + "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", + "dev": true + } + } + }, + "@jest/environment": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.9.0.tgz", + "integrity": "sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ==", + "dev": true, + "requires": { + "@jest/fake-timers": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0" + } + }, + "@jest/fake-timers": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", + "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-mock": "^24.9.0" + } + }, + "@jest/reporters": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.9.0.tgz", + "integrity": "sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw==", + "dev": true, + "requires": { + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.2", + "istanbul-lib-coverage": "^2.0.2", + "istanbul-lib-instrument": "^3.0.1", + "istanbul-lib-report": "^2.0.4", + "istanbul-lib-source-maps": "^3.0.1", + "istanbul-reports": "^2.2.6", + "jest-haste-map": "^24.9.0", + "jest-resolve": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.6.0", + "node-notifier": "^5.4.2", + "slash": "^2.0.0", + "source-map": "^0.6.0", + "string-length": "^2.0.0" + } + }, + "@jest/source-map": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", + "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", + "dev": true, + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.1.15", + "source-map": "^0.6.0" + }, + "dependencies": { + "graceful-fs": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", + "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", + "dev": true + } + } + }, + "@jest/test-result": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", + "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", + "dev": true, + "requires": { + "@jest/console": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/istanbul-lib-coverage": "^2.0.0" + } + }, + "@jest/test-sequencer": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz", + "integrity": "sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A==", + "dev": true, + "requires": { + "@jest/test-result": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-runner": "^24.9.0", + "jest-runtime": "^24.9.0" + } + }, + "@jest/transform": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.9.0.tgz", + "integrity": "sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^24.9.0", + "babel-plugin-istanbul": "^5.1.0", + "chalk": "^2.0.1", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.1.15", + "jest-haste-map": "^24.9.0", + "jest-regex-util": "^24.9.0", + "jest-util": "^24.9.0", + "micromatch": "^3.1.10", + "pirates": "^4.0.1", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "2.4.1" + }, + "dependencies": { + "graceful-fs": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", + "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", "dev": true } } }, + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, "@rdfjs/data-model": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@rdfjs/data-model/-/data-model-1.1.1.tgz", @@ -41,30 +425,67 @@ }, "dependencies": { "@types/rdf-js": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/rdf-js/-/rdf-js-2.0.1.tgz", - "integrity": "sha512-x3Qct8TPilUos4znM1gANmtTvjOFdDRItmpEM2Nu9QgAx258FN9k22OvOu2TmPzOlx8a1FLdEW3o33UXHQt5ow==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/rdf-js/-/rdf-js-2.0.2.tgz", + "integrity": "sha512-rHtC0mtRmMc9JzITesWhzmAXqfyJZhY8MygmmWZc3oWS5DPsGsKs+t3RXxGYlM4UKOqlD9Ki4owS1Cx/GPMeqw==", "requires": { "@types/node": "*" } } } }, - "@types/events": { - "version": "1.2.0", - "resolved": "http://registry.npmjs.org/@types/events/-/events-1.2.0.tgz", - "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==", - "dev": true + "@types/babel__core": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz", + "integrity": "sha512-8fBo0UR2CcwWxeX7WIIgJ7lXjasFxoYgRnFHUj+hRvKkpiBJbxhdAPTCY6/ZKM0uxANFVzt4yObSLuTiTnazDA==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } }, - "@types/fs-extra": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-5.0.4.tgz", - "integrity": "sha512-DsknoBvD8s+RFfSGjmERJ7ZOP1HI0UZRA3FSI+Zakhrc/Gy26YQsLI+m5V5DHxroHRJqCDLKJp7Hixn8zyaF7g==", + "@types/babel__generator": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.0.tgz", + "integrity": "sha512-c1mZUu4up5cp9KROs/QAw0gTeHrw/x7m52LcnvMxxOZ03DmLwPV0MlGmlgzV3cnSdjhJOZsj7E7FHeioai+egw==", "dev": true, "requires": { - "@types/node": "*" + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.2.tgz", + "integrity": "sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.7.tgz", + "integrity": "sha512-CeBpmX1J8kWLcDEnI3Cl2Eo6RfbGvzUctA+CjZUhOKDFbLfcr7fc4usEqLNWetrlJd7RhAkyYe2czXop4fICpw==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" } }, + "@types/concaveman": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@types/concaveman/-/concaveman-1.1.3.tgz", + "integrity": "sha512-G6crIs1efR4OV/Nshgh2w7H0GSsUomloz9Hq0iFysLXsIRX5fHbYGLncIo/RyCljgcpBOqsQdS5e+qJ+ZBVNSg==" + }, + "@types/events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", + "dev": true + }, "@types/glob": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", @@ -76,40 +497,41 @@ "@types/node": "*" } }, - "@types/handlebars": { - "version": "4.0.40", - "resolved": "https://registry.npmjs.org/@types/handlebars/-/handlebars-4.0.40.tgz", - "integrity": "sha512-sGWNtsjNrLOdKha2RV1UeF8+UbQnPSG7qbe5wwbni0mw4h2gHXyPFUMOC+xwGirIiiydM/HSqjDO4rk6NFB18w==", - "dev": true - }, "@types/haversine": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@types/haversine/-/haversine-1.1.0.tgz", - "integrity": "sha512-r3czDJZMjF/BpTzpzmehmAml68GMusKuD7es8qjl5kNtrfQAZ8PyARUUZudHq+qEk3VEln1WzSJ8KMQsxQQbPQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@types/haversine/-/haversine-1.1.4.tgz", + "integrity": "sha512-Lcz1bIWVwuLeNVbNwMOSyQwf/F+2qW18lrEgJjp6Xh0iquZQuG25mgogP7RdUELq0uw2TKjZirw27ojybRMnuw==", "dev": true }, - "@types/highlight.js": { - "version": "9.12.3", - "resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-9.12.3.tgz", - "integrity": "sha512-pGF/zvYOACZ/gLGWdQH8zSwteQS1epp68yRcVLJMgUck/MjEn/FBYmPub9pXT8C1e4a8YZfHo1CKyV8q1vKUnQ==", + "@types/istanbul-lib-coverage": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", + "integrity": "sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==", "dev": true }, - "@types/jest": { - "version": "23.3.7", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-23.3.7.tgz", - "integrity": "sha512-N0p6mHrS0RHC3A9hHN4QH1RM2fGSb2E8rt6ONEK5xKSnyKtn/JAhr1VritkCn6cdyDBephVB80THqJGWzK8FAw==", - "dev": true + "@types/istanbul-lib-report": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz", + "integrity": "sha512-3BUTyMzbZa2DtDI2BkERNC6jJw2Mr2Y0oGI7mRxYNBPxppbtEK1F66u3bKwU2g+wxwWI7PAoRpJnOY1grJqzHg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } }, - "@types/lodash": { - "version": "4.14.120", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.120.tgz", - "integrity": "sha512-jQ21kQ120mo+IrDs1nFNVm/AsdFxIx2+vZ347DbogHJPd/JzKNMOqU6HCYin1W6v8l5R9XSO2/e9cxmn7HAnVw==", - "dev": true + "@types/istanbul-reports": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz", + "integrity": "sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*", + "@types/istanbul-lib-report": "*" + } }, - "@types/marked": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@types/marked/-/marked-0.4.2.tgz", - "integrity": "sha512-cDB930/7MbzaGF6U3IwSQp6XBru8xWajF5PV2YZZeV8DyiliTuld11afVztGI9+yJZ29il5E+NpGA6ooV/Cjkg==", + "@types/jest": { + "version": "23.3.14", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-23.3.14.tgz", + "integrity": "sha512-Q5hTcfdudEL2yOmluA1zaSyPbzWPmJ3XfSWeP3RyoYvS9hnje1ZyagrZOuQ6+1nQC1Gw+7gap3pLNL3xL6UBug==", "dev": true }, "@types/minimatch": { @@ -119,9 +541,9 @@ "dev": true }, "@types/node": { - "version": "10.12.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.0.tgz", - "integrity": "sha512-3TUHC3jsBAB7qVRGxT6lWyYo2v96BMmD2PTcl47H25Lu7UXtFH/2qqmKiVrnel6Ne//0TFYf6uvNX+HW2FRkLQ==" + "version": "12.7.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.8.tgz", + "integrity": "sha512-FMdVn84tJJdV+xe+53sYiZS4R5yn1mAIxfj+DVoNiQjTYz1+OYmjwEZr1ev9nU0axXwda0QDbYl06QHanRVH3A==" }, "@types/rdf-js": { "version": "1.0.1", @@ -132,186 +554,201 @@ "@types/node": "*" } }, - "@types/shelljs": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.1.tgz", - "integrity": "sha512-1lQw+48BuVgp6c1+z8EMipp18IdnV2dLh6KQGwOm+kJy9nPjEkaqRKmwbDNEYf//EKBvKcwOC6V2cDrNxVoQeQ==", + "@types/stack-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", + "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", + "dev": true + }, + "@types/yargs": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.3.tgz", + "integrity": "sha512-K8/LfZq2duW33XW/tFwEAfnZlqIfVsoyRB3kfXdPXYhl0nfM8mmh7GS0jg7WrX2Dgq/0Ha/pR1PaR+BvmWwjiQ==", "dev": true, "requires": { - "@types/glob": "*", - "@types/node": "*" + "@types/yargs-parser": "*" } }, + "@types/yargs-parser": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-13.1.0.tgz", + "integrity": "sha512-gCubfBUZ6KxzoibJ+SCUc/57Ms1jz5NjHe4+dI2krNmU5zCPAphyLJYyTOg06ueIyfj+SaCUqmzun7ImlxDcKg==", + "dev": true + }, "@webassemblyjs/ast": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.7.11.tgz", - "integrity": "sha512-ZEzy4vjvTzScC+SH8RBssQUawpaInUdMTYwYYLh54/s8TuT0gBLuyUnppKsVyZEi876VmmStKsUs28UxPgdvrA==", + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", + "integrity": "sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==", "dev": true, "requires": { - "@webassemblyjs/helper-module-context": "1.7.11", - "@webassemblyjs/helper-wasm-bytecode": "1.7.11", - "@webassemblyjs/wast-parser": "1.7.11" + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5" } }, "@webassemblyjs/floating-point-hex-parser": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.11.tgz", - "integrity": "sha512-zY8dSNyYcgzNRNT666/zOoAyImshm3ycKdoLsyDw/Bwo6+/uktb7p4xyApuef1dwEBo/U/SYQzbGBvV+nru2Xg==", + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz", + "integrity": "sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==", "dev": true }, "@webassemblyjs/helper-api-error": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.11.tgz", - "integrity": "sha512-7r1qXLmiglC+wPNkGuXCvkmalyEstKVwcueZRP2GNC2PAvxbLYwLLPr14rcdJaE4UtHxQKfFkuDFuv91ipqvXg==", + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz", + "integrity": "sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==", "dev": true }, "@webassemblyjs/helper-buffer": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.11.tgz", - "integrity": "sha512-MynuervdylPPh3ix+mKZloTcL06P8tenNH3sx6s0qE8SLR6DdwnfgA7Hc9NSYeob2jrW5Vql6GVlsQzKQCa13w==", + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz", + "integrity": "sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==", "dev": true }, "@webassemblyjs/helper-code-frame": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.11.tgz", - "integrity": "sha512-T8ESC9KMXFTXA5urJcyor5cn6qWeZ4/zLPyWeEXZ03hj/x9weSokGNkVCdnhSabKGYWxElSdgJ+sFa9G/RdHNw==", + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz", + "integrity": "sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==", "dev": true, "requires": { - "@webassemblyjs/wast-printer": "1.7.11" + "@webassemblyjs/wast-printer": "1.8.5" } }, "@webassemblyjs/helper-fsm": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.11.tgz", - "integrity": "sha512-nsAQWNP1+8Z6tkzdYlXT0kxfa2Z1tRTARd8wYnc/e3Zv3VydVVnaeePgqUzFrpkGUyhUUxOl5ML7f1NuT+gC0A==", + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz", + "integrity": "sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==", "dev": true }, "@webassemblyjs/helper-module-context": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.11.tgz", - "integrity": "sha512-JxfD5DX8Ygq4PvXDucq0M+sbUFA7BJAv/GGl9ITovqE+idGX+J3QSzJYz+LwQmL7fC3Rs+utvWoJxDb6pmC0qg==", - "dev": true + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz", + "integrity": "sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "mamacro": "^0.0.3" + } }, "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.11.tgz", - "integrity": "sha512-cMXeVS9rhoXsI9LLL4tJxBgVD/KMOKXuFqYb5oCJ/opScWpkCMEz9EJtkonaNcnLv2R3K5jIeS4TRj/drde1JQ==", + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz", + "integrity": "sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==", "dev": true }, "@webassemblyjs/helper-wasm-section": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.11.tgz", - "integrity": "sha512-8ZRY5iZbZdtNFE5UFunB8mmBEAbSI3guwbrsCl4fWdfRiAcvqQpeqd5KHhSWLL5wuxo53zcaGZDBU64qgn4I4Q==", + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz", + "integrity": "sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.7.11", - "@webassemblyjs/helper-buffer": "1.7.11", - "@webassemblyjs/helper-wasm-bytecode": "1.7.11", - "@webassemblyjs/wasm-gen": "1.7.11" + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5" } }, "@webassemblyjs/ieee754": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.7.11.tgz", - "integrity": "sha512-Mmqx/cS68K1tSrvRLtaV/Lp3NZWzXtOHUW2IvDvl2sihAwJh4ACE0eL6A8FvMyDG9abes3saB6dMimLOs+HMoQ==", + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz", + "integrity": "sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==", "dev": true, "requires": { "@xtuc/ieee754": "^1.2.0" } }, "@webassemblyjs/leb128": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.7.11.tgz", - "integrity": "sha512-vuGmgZjjp3zjcerQg+JA+tGOncOnJLWVkt8Aze5eWQLwTQGNgVLcyOTqgSCxWTR4J42ijHbBxnuRaL1Rv7XMdw==", + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.8.5.tgz", + "integrity": "sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==", "dev": true, "requires": { - "@xtuc/long": "4.2.1" + "@xtuc/long": "4.2.2" } }, "@webassemblyjs/utf8": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.7.11.tgz", - "integrity": "sha512-C6GFkc7aErQIAH+BMrIdVSmW+6HSe20wg57HEC1uqJP8E/xpMjXqQUxkQw07MhNDSDcGpxI9G5JSNOQCqJk4sA==", + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.5.tgz", + "integrity": "sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==", "dev": true }, "@webassemblyjs/wasm-edit": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.11.tgz", - "integrity": "sha512-FUd97guNGsCZQgeTPKdgxJhBXkUbMTY6hFPf2Y4OedXd48H97J+sOY2Ltaq6WGVpIH8o/TGOVNiVz/SbpEMJGg==", + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz", + "integrity": "sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.7.11", - "@webassemblyjs/helper-buffer": "1.7.11", - "@webassemblyjs/helper-wasm-bytecode": "1.7.11", - "@webassemblyjs/helper-wasm-section": "1.7.11", - "@webassemblyjs/wasm-gen": "1.7.11", - "@webassemblyjs/wasm-opt": "1.7.11", - "@webassemblyjs/wasm-parser": "1.7.11", - "@webassemblyjs/wast-printer": "1.7.11" + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/helper-wasm-section": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-opt": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "@webassemblyjs/wast-printer": "1.8.5" } }, "@webassemblyjs/wasm-gen": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.11.tgz", - "integrity": "sha512-U/KDYp7fgAZX5KPfq4NOupK/BmhDc5Kjy2GIqstMhvvdJRcER/kUsMThpWeRP8BMn4LXaKhSTggIJPOeYHwISA==", + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz", + "integrity": "sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.7.11", - "@webassemblyjs/helper-wasm-bytecode": "1.7.11", - "@webassemblyjs/ieee754": "1.7.11", - "@webassemblyjs/leb128": "1.7.11", - "@webassemblyjs/utf8": "1.7.11" + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" } }, "@webassemblyjs/wasm-opt": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.11.tgz", - "integrity": "sha512-XynkOwQyiRidh0GLua7SkeHvAPXQV/RxsUeERILmAInZegApOUAIJfRuPYe2F7RcjOC9tW3Cb9juPvAC/sCqvg==", + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz", + "integrity": "sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.7.11", - "@webassemblyjs/helper-buffer": "1.7.11", - "@webassemblyjs/wasm-gen": "1.7.11", - "@webassemblyjs/wasm-parser": "1.7.11" + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5" } }, "@webassemblyjs/wasm-parser": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.11.tgz", - "integrity": "sha512-6lmXRTrrZjYD8Ng8xRyvyXQJYUQKYSXhJqXOBLw24rdiXsHAOlvw5PhesjdcaMadU/pyPQOJ5dHreMjBxwnQKg==", + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz", + "integrity": "sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.7.11", - "@webassemblyjs/helper-api-error": "1.7.11", - "@webassemblyjs/helper-wasm-bytecode": "1.7.11", - "@webassemblyjs/ieee754": "1.7.11", - "@webassemblyjs/leb128": "1.7.11", - "@webassemblyjs/utf8": "1.7.11" + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" } }, "@webassemblyjs/wast-parser": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.7.11.tgz", - "integrity": "sha512-lEyVCg2np15tS+dm7+JJTNhNWq9yTZvi3qEhAIIOaofcYlUp0UR5/tVqOwa/gXYr3gjwSZqw+/lS9dscyLelbQ==", + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz", + "integrity": "sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.7.11", - "@webassemblyjs/floating-point-hex-parser": "1.7.11", - "@webassemblyjs/helper-api-error": "1.7.11", - "@webassemblyjs/helper-code-frame": "1.7.11", - "@webassemblyjs/helper-fsm": "1.7.11", - "@xtuc/long": "4.2.1" + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/floating-point-hex-parser": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-code-frame": "1.8.5", + "@webassemblyjs/helper-fsm": "1.8.5", + "@xtuc/long": "4.2.2" } }, "@webassemblyjs/wast-printer": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.7.11.tgz", - "integrity": "sha512-m5vkAsuJ32QpkdkDOUPGSltrg8Cuk3KBx4YrmAGQwCZPRdUHXxG4phIOuuycLemHFr74sWL9Wthqss4fzdzSwg==", + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz", + "integrity": "sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.7.11", - "@webassemblyjs/wast-parser": "1.7.11", - "@xtuc/long": "4.2.1" + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5", + "@xtuc/long": "4.2.2" } }, "@xtuc/ieee754": { @@ -321,9 +758,9 @@ "dev": true }, "@xtuc/long": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.1.tgz", - "integrity": "sha512-FZdkNBDqBRHKQ2MEbSC17xnPFOhZxeJ2YGSfr2BKf3sujG49Qe3bB+rGCwQfIaA7WHnGeGkSijX4FuBCdrzW/g==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "dev": true }, "abab": { @@ -331,20 +768,38 @@ "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz", "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==" }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dev": true, + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + }, + "dependencies": { + "mime-db": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "dev": true + }, + "mime-types": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "dev": true, + "requires": { + "mime-db": "1.40.0" + } + } + } + }, "acorn": { "version": "5.7.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==" }, - "acorn-dynamic-import": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz", - "integrity": "sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg==", - "dev": true, - "requires": { - "acorn": "^5.0.0" - } - }, "acorn-globals": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.0.tgz", @@ -377,29 +832,50 @@ "json-schema-traverse": "^0.3.0" } }, - "ajv-keywords": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", - "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "dev": true + }, + "ajv-keywords": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", + "dev": true + }, + "ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", "dev": true }, "ansi-escapes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", - "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", + "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", + "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", "dev": true }, "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "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": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true + "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" + } }, "anymatch": { "version": "2.0.0", @@ -696,15 +1172,6 @@ } } }, - "append-transform": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", - "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", - "dev": true, - "requires": { - "default-require-extensions": "^1.0.0" - } - }, "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", @@ -721,13 +1188,10 @@ } }, "arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", - "dev": true, - "requires": { - "arr-flatten": "^1.0.1" - } + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true }, "arr-flatten": { "version": "1.1.0", @@ -746,16 +1210,31 @@ "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=" }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", "dev": true }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", "dev": true }, "asn1": { @@ -778,11 +1257,12 @@ } }, "assert": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", - "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", "dev": true, "requires": { + "object-assign": "^4.1.1", "util": "0.10.3" }, "dependencies": { @@ -821,18 +1301,15 @@ "dev": true }, "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", - "dev": true, - "requires": { - "lodash": "^4.17.10" - } + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true }, "async-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", "dev": true }, "async-limiter": { @@ -874,247 +1351,83 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, - "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-jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.9.0.tgz", + "integrity": "sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw==", + "dev": true, + "requires": { + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/babel__core": "^7.1.0", + "babel-plugin-istanbul": "^5.1.0", + "babel-preset-jest": "^24.9.0", + "chalk": "^2.4.2", + "slash": "^2.0.0" }, "dependencies": { "chalk": { - "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "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": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } - } - } - }, - "babel-core": { - "version": "6.26.3", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", - "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", - "dev": true, - "requires": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.1", - "debug": "^2.6.9", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.8", - "slash": "^1.0.0", - "source-map": "^0.5.7" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + }, + "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": { - "ms": "2.0.0" + "has-flag": "^3.0.0" } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "babel-generator": { - "version": "6.26.1", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", - "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", - "dev": true, - "requires": { - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "detect-indent": "^4.0.0", - "jsesc": "^1.3.0", - "lodash": "^4.17.4", - "source-map": "^0.5.7", - "trim-right": "^1.0.1" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true } } }, - "babel-helpers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", - "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-jest": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-23.6.0.tgz", - "integrity": "sha512-lqKGG6LYXYu+DQh/slrQ8nxXQkEkhugdXsU6St7GmhVS7Ilc/22ArwqXNJrf0QaOBjZB0360qZMwXqDYQHXaew==", - "dev": true, - "requires": { - "babel-plugin-istanbul": "^4.1.6", - "babel-preset-jest": "^23.2.0" - } - }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } - }, "babel-plugin-istanbul": { - "version": "4.1.6", - "resolved": "http://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz", - "integrity": "sha512-PWP9FQ1AhZhS01T/4qLSKoHGY/xvkZdVBGlKM/HuxxS3+sC66HhTNR7+MpbO/so/cz/wY94MeSWJuP1hXIPfwQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz", + "integrity": "sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==", "dev": true, "requires": { - "babel-plugin-syntax-object-rest-spread": "^6.13.0", - "find-up": "^2.1.0", - "istanbul-lib-instrument": "^1.10.1", - "test-exclude": "^4.2.1" + "@babel/helper-plugin-utils": "^7.0.0", + "find-up": "^3.0.0", + "istanbul-lib-instrument": "^3.3.0", + "test-exclude": "^5.2.3" } }, "babel-plugin-jest-hoist": { - "version": "23.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-23.2.0.tgz", - "integrity": "sha1-5h+uBaHKiAGq3uV6bWa4zvr0QWc=", - "dev": true - }, - "babel-plugin-syntax-object-rest-spread": { - "version": "6.13.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", - "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=", - "dev": true - }, - "babel-preset-jest": { - "version": "23.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-23.2.0.tgz", - "integrity": "sha1-jsegOhOPABoaj7HoETZSvxpV2kY=", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^23.2.0", - "babel-plugin-syntax-object-rest-spread": "^6.13.0" - } - }, - "babel-register": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", - "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", - "dev": true, - "requires": { - "babel-core": "^6.26.0", - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "home-or-tmp": "^2.0.0", - "lodash": "^4.17.4", - "mkdirp": "^0.5.1", - "source-map-support": "^0.4.15" - } - }, - "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" - } - }, - "babel-template": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz", + "integrity": "sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw==", "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" + "@types/babel__traverse": "^7.0.6" } }, - "babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "babel-preset-jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz", + "integrity": "sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg==", "dev": true, "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } + "@babel/plugin-syntax-object-rest-spread": "^7.0.0", + "babel-plugin-jest-hoist": "^24.9.0" } }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "backbone": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/backbone/-/backbone-1.4.0.tgz", + "integrity": "sha512-RLmDrRXkVdouTg38jcgHhyQ/2zjg7a8E6sz2zxfz21Hh17xDJYUHBZimVIt5fUyS8vbfpeSmTL3gUjTEvUV3qQ==", "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" + "underscore": ">=1.8.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 - }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -1189,9 +1502,15 @@ } }, "base64-js": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", + "dev": true + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", "dev": true }, "bcrypt-pbkdf": { @@ -1203,21 +1522,21 @@ } }, "big.js": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", - "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", "dev": true }, "binary-extensions": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.12.0.tgz", - "integrity": "sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", "dev": true }, "bluebird": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", - "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==", + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", + "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==", "dev": true }, "bn.js": { @@ -1226,6 +1545,52 @@ "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", "dev": true }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "dependencies": { + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "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 + } + } + }, + "bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "dev": true, + "requires": { + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" + } + }, "boom": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", @@ -1245,14 +1610,32 @@ } }, "braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } } }, "brorand": { @@ -1355,18 +1738,18 @@ } }, "bs-logger": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.5.tgz", - "integrity": "sha512-uFLE0LFMxrH8Z5Hd9QgivvRbrl/NFkOTHzGhlqQxsnmx5JBLrp4bc249afLL+GccyY/8hkcGi2LpVaOzaEY0nQ==", + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", "dev": true, "requires": { - "fast-json-stable-stringify": "^2.0.0" + "fast-json-stable-stringify": "2.x" } }, "bser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz", - "integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.0.tgz", + "integrity": "sha512-8zsjWrQkkBoLK6uxASk1nJ2SKv97ltiGDo6A3wA0/yRPz+CwmEyDo0hUrhIuukG2JHpAl3bvFIixw2/3Hi0DOg==", "dev": true, "requires": { "node-int64": "^0.4.0" @@ -1389,6 +1772,12 @@ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, + "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==", + "dev": true + }, "buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", @@ -1407,31 +1796,68 @@ "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", "dev": true }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, "cacache": { - "version": "10.0.4", - "resolved": "http://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", + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz", + "integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==", + "dev": true, + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.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", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", "y18n": "^4.0.0" }, "dependencies": { - "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==", + "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" + } + }, + "graceful-fs": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", + "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", + "dev": true + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "yallist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", "dev": true } } @@ -1462,9 +1888,9 @@ } }, "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, "camelcase": { @@ -1474,12 +1900,12 @@ "dev": true }, "capture-exit": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-1.2.0.tgz", - "integrity": "sha1-HF/MSJ/QqwDU8ax64QcuMXP7q28=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", + "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", "dev": true, "requires": { - "rsvp": "^3.3.3" + "rsvp": "^4.8.4" } }, "caseless": { @@ -1519,143 +1945,52 @@ } }, "chokidar": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", - "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", "dev": true, "requires": { "anymatch": "^2.0.0", - "async-each": "^1.0.0", - "braces": "^2.3.0", - "fsevents": "^1.2.2", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", "glob-parent": "^3.1.0", - "inherits": "^2.0.1", + "inherits": "^2.0.3", "is-binary-path": "^1.0.0", "is-glob": "^4.0.0", - "lodash.debounce": "^4.0.8", - "normalize-path": "^2.1.1", + "normalize-path": "^3.0.0", "path-is-absolute": "^1.0.0", - "readdirp": "^2.0.0", - "upath": "^1.0.5" + "readdirp": "^2.2.1", + "upath": "^1.1.1" }, "dependencies": { - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-glob": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", - "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true } } }, "chownr": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", - "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", + "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==", "dev": true }, "chrome-trace-event": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz", - "integrity": "sha512-xDbVgyfDTT2piup/h8dK/y4QZfJRSa73bw1WZ8b4XM1o7fsFubUVGYcE+1ANtOzJJELGpYoG2961z0Z6OAld9A==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", + "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", "dev": true, "requires": { "tslib": "^1.9.0" } }, "ci-info": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", - "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "dev": true }, "cipher-base": { @@ -1775,9 +2110,9 @@ } }, "commander": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", - "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==" + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==" }, "commondir": { "version": "1.0.1", @@ -1791,6 +2126,38 @@ "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", "dev": true }, + "compressible": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.17.tgz", + "integrity": "sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw==", + "dev": true, + "requires": { + "mime-db": ">= 1.40.0 < 2" + }, + "dependencies": { + "mime-db": { + "version": "1.41.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.41.0.tgz", + "integrity": "sha512-B5gxBI+2K431XW8C2rcc/lhppbuji67nf9v39eH8pkWoZDxnAL0PxdpH32KYRScniF8qDHBDlI+ipgg5WrCUYw==", + "dev": true + } + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + } + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1809,6 +2176,31 @@ "typedarray": "^0.0.6" } }, + "concaveman": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/concaveman/-/concaveman-1.1.1.tgz", + "integrity": "sha1-bCSCWAslI874L8K+wAoEFebmgWI=", + "requires": { + "monotone-convex-hull-2d": "^1.0.1", + "point-in-polygon": "^1.0.1", + "rbush": "^2.0.1", + "robust-orientation": "^1.1.3", + "tinyqueue": "^1.1.0" + }, + "dependencies": { + "tinyqueue": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-1.2.3.tgz", + "integrity": "sha512-Qz9RgWuO9l8lT+Y9xvbzhPT2efIUIFd69N7eF7tJ9lnQl0iLj1M7peK7IoUGZL9DJHw9XftqLreccfxcQgYLxA==" + } + } + }, + "connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "dev": true + }, "console-browserify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", @@ -1824,6 +2216,21 @@ "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", "dev": true }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dev": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true + }, "convert-source-map": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", @@ -1833,6 +2240,18 @@ "safe-buffer": "~5.1.1" } }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, "copy-concurrently": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", @@ -1853,12 +2272,6 @@ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", "dev": true }, - "core-js": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", - "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==", - "dev": true - }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -1901,6 +2314,15 @@ "sha.js": "^2.4.8" } }, + "cross-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.0.4.tgz", + "integrity": "sha512-MSHgpjQqgbT/94D4CyADeNoYh52zMkCX4pcJvPP5WqPsLFMKjr2TCMg381ox5qI0ii2dPwaLx/00477knXqXVw==", + "requires": { + "node-fetch": "2.6.0", + "whatwg-fetch": "3.0.0" + } + }, "cross-spawn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", @@ -1945,11 +2367,19 @@ } }, "cyclist": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", - "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", "dev": true }, + "d3-delaunay": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-4.1.5.tgz", + "integrity": "sha512-rBKVohmXT9+BrDicH8umAVUwtkfLIydVlWnpIEDUZ4l2e1vXCaKbypByF8tkN8TUUKnzJY0s8ldQEroeBRMO9Q==", + "requires": { + "delaunator": "^2.0.0" + } + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -1987,9 +2417,10 @@ "dev": true }, "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, "requires": { "ms": "2.0.0" } @@ -2006,18 +2437,33 @@ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true }, + "deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.0.tgz", + "integrity": "sha512-ZbfWJq/wN1Z273o7mUSjILYqehAktR2NVoSrOukDkU9kg2v/Uv89yU4Cvz8seJeAmtN5oqiefKq8FPuXOboqLw==", + "dev": true, + "requires": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "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=" }, - "default-require-extensions": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-1.0.0.tgz", - "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", + "default-gateway": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", + "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", "dev": true, "requires": { - "strip-bom": "^2.0.0" + "execa": "^1.0.0", + "ip-regex": "^2.1.0" } }, "define-properties": { @@ -2082,11 +2528,54 @@ } } }, + "del": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "delaunator": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-2.0.5.tgz", + "integrity": "sha512-GSYmkITO56erpQzv5Pw+8Vg769kurM16IVUq/AcMb5ZCJCtV7Z2agx9lJ7EbbLno8L099iH2d+hvAK34ZnsvIQ==" + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, "des.js": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", @@ -2097,14 +2586,17 @@ "minimalistic-assert": "^1.0.0" } }, - "detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", - "dev": true, - "requires": { - "repeating": "^2.0.0" - } + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "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-newline": { "version": "2.1.0", @@ -2112,10 +2604,22 @@ "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", "dev": true }, + "detect-node": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", + "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", + "dev": true + }, "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", + "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", + "dev": true + }, + "diff-sequences": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", + "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==", "dev": true }, "diffie-hellman": { @@ -2129,6 +2633,31 @@ "randombytes": "^2.0.0" } }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", + "dev": true + }, + "dns-packet": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", + "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", + "dev": true, + "requires": { + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, + "dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "dev": true, + "requires": { + "buffer-indexof": "^1.0.0" + } + }, "domain-browser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", @@ -2144,9 +2673,9 @@ } }, "duplexify": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.1.tgz", - "integrity": "sha512-vM58DwdnKmty+FSPzT14K9JXb90H+j5emaR4KYbr2KTIz00WHGbWOe5ghQTx233ZCLZtrGDALzKwcjEtSt35mA==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", "dev": true, "requires": { "end-of-stream": "^1.0.0", @@ -2164,10 +2693,16 @@ "safer-buffer": "^2.1.0" } }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, "elliptic": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", - "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.1.tgz", + "integrity": "sha512-xvJINNLbTeWQjrl6X+7eQCrIy/YPv5XCpKW6kB5mKvtnGILoLDcySuwomfdzt0BMdLNVnuRNTuzKNHj0bva1Cg==", "dev": true, "requires": { "bn.js": "^4.4.0", @@ -2179,12 +2714,24 @@ "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", "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", "dev": true }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true + }, "encoding": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", @@ -2232,16 +2779,21 @@ } }, "es-abstract": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", - "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.14.2.tgz", + "integrity": "sha512-DgoQmbpFNOofkjJtKwr87Ma5EW4Dc8fWhD0R+ndq7Oc456ivUfGOOP6oAZTTKl5/CcNMP+EN+e3/iUzgE0veZg==", "dev": true, "requires": { - "es-to-primitive": "^1.1.1", + "es-to-primitive": "^1.2.0", "function-bind": "^1.1.1", - "has": "^1.0.1", - "is-callable": "^1.1.3", - "is-regex": "^1.0.4" + "has": "^1.0.3", + "has-symbols": "^1.0.0", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-inspect": "^1.6.0", + "object-keys": "^1.1.1", + "string.prototype.trimleft": "^2.0.0", + "string.prototype.trimright": "^2.0.0" } }, "es-to-primitive": { @@ -2255,6 +2807,12 @@ "is-symbol": "^1.0.2" } }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -2281,9 +2839,9 @@ } }, "eslint-scope": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", - "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", "dev": true, "requires": { "esrecurse": "^4.1.0", @@ -2315,12 +2873,33 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true + }, + "eventemitter3": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", + "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==", + "dev": true + }, "events": { - "version": "1.1.1", - "resolved": "http://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", + "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==", "dev": true }, + "eventsource": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz", + "integrity": "sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==", + "dev": true, + "requires": { + "original": "^1.0.0" + } + }, "evp_bytestokey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", @@ -2332,27 +2911,39 @@ } }, "exec-sh": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.2.tgz", - "integrity": "sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw==", - "dev": true, - "requires": { - "merge": "^1.2.0" - } + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.2.tgz", + "integrity": "sha512-9sLAvzhI5nc8TpuQUh4ahMdCrWT00wPWz7j47/emR5+2qEfoZP5zzUXvx+vdx+H6ohhnsYC31iX04QLYJK8zTg==", + "dev": true }, "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "dev": true, "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", "is-stream": "^1.1.0", "npm-run-path": "^2.0.0", "p-finally": "^1.0.0", "signal-exit": "^3.0.0", "strip-eof": "^1.0.0" + }, + "dependencies": { + "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" + } + } } }, "exit": { @@ -2362,45 +2953,112 @@ "dev": true }, "expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "requires": { - "is-posix-bracket": "^0.1.0" + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } } }, - "expand-range": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", - "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "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": { - "fill-range": "^2.1.0" + "homedir-polyfill": "^1.0.1" } }, "expect": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-23.6.0.tgz", - "integrity": "sha512-dgSoOHgmtn/aDGRVFWclQyPDKl2CQRq0hmIEoUAuQs/2rn2NcvCWcSCovm6BLeuB/7EZuLGu2QfnR+qRt5OM4w==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-24.9.0.tgz", + "integrity": "sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==", "dev": true, "requires": { + "@jest/types": "^24.9.0", "ansi-styles": "^3.2.0", - "jest-diff": "^23.6.0", - "jest-get-type": "^22.1.0", - "jest-matcher-utils": "^23.6.0", - "jest-message-util": "^23.4.0", - "jest-regex-util": "^23.3.0" + "jest-get-type": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-regex-util": "^24.9.0" + } + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "dev": true, + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" }, "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" - } + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "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 } } }, @@ -2431,21 +3089,83 @@ } }, "extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "dev": true, "requires": { - "is-extglob": "^1.0.0" - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, - "fast-deep-equal": { - "version": "1.1.0", + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "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 + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "1.1.0", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" }, @@ -2459,6 +3179,15 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" }, + "faye-websocket": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, "fb-watchman": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", @@ -2468,71 +3197,113 @@ "bser": "^2.0.0" } }, - "filename-regex": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", - "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "figgy-pudding": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", + "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==", "dev": true }, - "fileset": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", - "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { - "glob": "^7.0.3", - "minimatch": "^3.0.3" + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } } }, - "fill-range": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", - "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", "dev": true, "requires": { - "is-number": "^2.1.0", - "isobject": "^2.0.0", - "randomatic": "^3.0.0", - "repeat-element": "^1.1.2", - "repeat-string": "^1.5.2" + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" } }, "find-cache-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", - "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", "dev": true, "requires": { "commondir": "^1.0.1", - "make-dir": "^1.0.0", - "pkg-dir": "^2.0.0" + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" } }, "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "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" + } + }, + "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": { - "locate-path": "^2.0.0" + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" } }, "flush-write-stream": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz", - "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", "dev": true, "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.4" + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" } }, "follow-redirects": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.6.1.tgz", - "integrity": "sha512-t2JCjbzxQpWvbhts3l6SH1DKzSrx8a+SsaVf4h6bG4kOXUuPYS/kg2Lr4gQSb7eemaHqJkOThF1BGyjlUkO1GQ==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz", + "integrity": "sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==", "requires": { - "debug": "=3.1.0" + "debug": "^3.2.6" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } } }, "for-in": { @@ -2541,15 +3312,6 @@ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", "dev": true }, - "for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", - "dev": true, - "requires": { - "for-in": "^1.0.1" - } - }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -2565,6 +3327,12 @@ "mime-types": "^2.1.12" } }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true + }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -2574,6 +3342,12 @@ "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", @@ -2585,14 +3359,22 @@ } }, "fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", + "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" + }, + "dependencies": { + "graceful-fs": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", + "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", + "dev": true + } } }, "fs-write-stream-atomic": { @@ -2614,14 +3396,14 @@ "dev": true }, "fsevents": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", - "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", "dev": true, "optional": true, "requires": { - "nan": "^2.9.2", - "node-pre-gyp": "^0.10.0" + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" }, "dependencies": { "abbrev": { @@ -2643,7 +3425,7 @@ "optional": true }, "are-we-there-yet": { - "version": "1.1.4", + "version": "1.1.5", "bundled": true, "dev": true, "optional": true, @@ -2669,7 +3451,7 @@ } }, "chownr": { - "version": "1.0.1", + "version": "1.1.1", "bundled": true, "dev": true, "optional": true @@ -2699,16 +3481,16 @@ "optional": true }, "debug": { - "version": "2.6.9", + "version": "4.1.1", "bundled": true, "dev": true, "optional": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "deep-extend": { - "version": "0.5.1", + "version": "0.6.0", "bundled": true, "dev": true, "optional": true @@ -2757,7 +3539,7 @@ } }, "glob": { - "version": "7.1.2", + "version": "7.1.3", "bundled": true, "dev": true, "optional": true, @@ -2777,12 +3559,12 @@ "optional": true }, "iconv-lite": { - "version": "0.4.21", + "version": "0.4.24", "bundled": true, "dev": true, "optional": true, "requires": { - "safer-buffer": "^2.1.0" + "safer-buffer": ">= 2.1.2 < 3" } }, "ignore-walk": { @@ -2847,17 +3629,17 @@ "optional": true }, "minipass": { - "version": "2.2.4", + "version": "2.3.5", "bundled": true, "dev": true, "optional": true, "requires": { - "safe-buffer": "^5.1.1", + "safe-buffer": "^5.1.2", "yallist": "^3.0.0" } }, "minizlib": { - "version": "1.1.0", + "version": "1.2.1", "bundled": true, "dev": true, "optional": true, @@ -2875,35 +3657,35 @@ } }, "ms": { - "version": "2.0.0", + "version": "2.1.1", "bundled": true, "dev": true, "optional": true }, "needle": { - "version": "2.2.0", + "version": "2.3.0", "bundled": true, "dev": true, "optional": true, "requires": { - "debug": "^2.1.2", + "debug": "^4.1.0", "iconv-lite": "^0.4.4", "sax": "^1.2.4" } }, "node-pre-gyp": { - "version": "0.10.0", + "version": "0.12.0", "bundled": true, "dev": true, "optional": true, "requires": { "detect-libc": "^1.0.2", "mkdirp": "^0.5.1", - "needle": "^2.2.0", + "needle": "^2.2.1", "nopt": "^4.0.1", "npm-packlist": "^1.1.6", "npmlog": "^4.0.2", - "rc": "^1.1.7", + "rc": "^1.2.7", "rimraf": "^2.6.1", "semver": "^5.3.0", "tar": "^4" @@ -2920,13 +3702,13 @@ } }, "npm-bundled": { - "version": "1.0.3", + "version": "1.0.6", "bundled": true, "dev": true, "optional": true }, "npm-packlist": { - "version": "1.1.10", + "version": "1.4.1", "bundled": true, "dev": true, "optional": true, @@ -3003,12 +3785,12 @@ "optional": true }, "rc": { - "version": "1.2.7", + "version": "1.2.8", "bundled": true, "dev": true, "optional": true, "requires": { - "deep-extend": "^0.5.1", + "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" @@ -3038,16 +3820,16 @@ } }, "rimraf": { - "version": "2.6.2", + "version": "2.6.3", "bundled": true, "dev": true, "optional": true, "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" } }, "safe-buffer": { - "version": "5.1.1", + "version": "5.1.2", "bundled": true, "dev": true, "optional": true @@ -3065,7 +3847,7 @@ "optional": true }, "semver": { - "version": "5.5.0", + "version": "5.7.0", "bundled": true, "dev": true, "optional": true @@ -3118,17 +3900,17 @@ "optional": true }, "tar": { - "version": "4.4.1", + "version": "4.4.8", "bundled": true, "dev": true, "optional": true, "requires": { - "chownr": "^1.0.1", + "chownr": "^1.1.1", "fs-minipass": "^1.2.5", - "minipass": "^2.2.4", - "minizlib": "^1.1.0", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.1", + "safe-buffer": "^5.1.2", "yallist": "^3.0.2" } }, @@ -3139,12 +3921,12 @@ "optional": true }, "wide-align": { - "version": "1.1.2", + "version": "1.1.3", "bundled": true, "dev": true, "optional": true, "requires": { - "string-width": "^1.0.2" + "string-width": "^1.0.2 || 2" } }, "wrappy": { @@ -3154,7 +3936,7 @@ "optional": true }, "yallist": { - "version": "3.0.2", + "version": "3.0.3", "bundled": true, "dev": true, "optional": true @@ -3174,10 +3956,13 @@ "dev": true }, "get-stream": { - "version": "3.0.0", - "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } }, "get-value": { "version": "2.0.6", @@ -3207,37 +3992,95 @@ "path-is-absolute": "^1.0.0" } }, - "glob-base": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "dev": true, "requires": { - "glob-parent": "^2.0.0", - "is-glob": "^2.0.0" + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } } }, - "glob-parent": { + "global-modules": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", "dev": true, "requires": { - "is-glob": "^2.0.0" + "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-modules-path": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/global-modules-path/-/global-modules-path-2.3.0.tgz", - "integrity": "sha512-HchvMJNYh9dGSCy8pOQ2O8u/hoXaL+0XhnrwH0RyLiSXMMTl9W3N6KUU73+JFOg5PGjtzl6VZzUQsnrpm7Szag==", - "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" + } }, "globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", @@ -3250,13 +4093,19 @@ "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", "dev": true }, + "handle-thing": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.0.tgz", + "integrity": "sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==", + "dev": true + }, "handlebars": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.12.tgz", - "integrity": "sha512-RhmTekP+FZL+XNhwS1Wf+bTTZpdLougwt5pcgA1tuz6Jcx0fpH/7z0qd71RKnZHBCxIRBHfBOnio4gViPemNzA==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.3.1.tgz", + "integrity": "sha512-c0HoNHzDiHpBt4Kqe99N8tdLPKAnGCQ73gYMPWtAYM4PwGnf7xl8PBUHJqh9ijlzt2uQKaSRxbXRt+rZ7M2/kA==", "dev": true, "requires": { - "async": "^2.5.0", + "neo-async": "^2.6.0", "optimist": "^0.6.1", "source-map": "^0.6.1", "uglify-js": "^3.1.4" @@ -3285,15 +4134,6 @@ "function-bind": "^1.1.1" } }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -3377,9 +4217,9 @@ } }, "hash.js": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.5.tgz", - "integrity": "sha512-eWI5HG9Np+eHV1KQhisXWwM+4EPPYe5dFX1UZZH7k/E3JzDEazVH+VGlZi6R94ZqImq+A3D1mCEtrFIfg/E7sA==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -3387,14 +4227,14 @@ } }, "haversine": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/haversine/-/haversine-1.1.0.tgz", - "integrity": "sha1-CyOAy22cEOnxIk/CtRPMYQGNX/c=" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/haversine/-/haversine-1.1.1.tgz", + "integrity": "sha512-KW4MS8+krLIeiw8bF5z532CptG0ZyGGFj0UbKMxx25lKnnJ1hMUbuzQl+PXQjNiDLnl1bOyz23U6hSK10r4guw==" }, "highlight.js": { - "version": "9.13.1", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.13.1.tgz", - "integrity": "sha512-Sc28JNQNDzaH6PORtRLMvif9RSn1mYuOoX3omVjnb0+HbpPygU2ALBI0R/wsiqCb4/fcp07Gdo8g+fhtFrQl6A==", + "version": "9.15.10", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.10.tgz", + "integrity": "sha512-RoV7OkQm0T3os3Dd2VHLNMoaoDVx77Wygln3n9l5YV172XonWG6rgQD3XnF/BuFFZw9A0TJgmMSO8FEWQgvcXw==", "dev": true }, "hmac-drbg": { @@ -3413,22 +4253,33 @@ "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" }, - "home-or-tmp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", - "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "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": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.1" + "parse-passwd": "^1.0.0" } }, "hosted-git-info": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", - "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.4.tgz", + "integrity": "sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ==", "dev": true }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, "html-encoding-sniffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", @@ -3437,11 +4288,65 @@ "whatwg-encoding": "^1.0.1" } }, + "html-entities": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", + "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=", + "dev": true + }, "http-cache-semantics": { "version": "3.8.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==" }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", + "dev": true + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "http-parser-js": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz", + "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=", + "dev": true + }, + "http-proxy": { + "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": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-middleware": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", + "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", + "dev": true, + "requires": { + "http-proxy": "^1.17.0", + "is-glob": "^4.0.0", + "lodash": "^4.17.11", + "micromatch": "^3.1.10" + } + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -3467,9 +4372,9 @@ } }, "ieee754": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", - "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", "dev": true }, "iferr": { @@ -3479,12 +4384,12 @@ "dev": true }, "import-local": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-1.0.0.tgz", - "integrity": "sha512-vAaZHieK9qjGo58agRBg+bhHX3hoTZU/Oa3GESWLz7t1U62fk63aHuDJJEteXoDeTCcPmUT+z38gkHPZkkmpmQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", "dev": true, "requires": { - "pkg-dir": "^2.0.0", + "pkg-dir": "^3.0.0", "resolve-cwd": "^2.0.0" } }, @@ -3494,10 +4399,10 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, - "indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", "dev": true }, "inflight": { @@ -3516,15 +4421,31 @@ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, - "interpret": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", - "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "internal-ip": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", + "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", + "dev": true, + "requires": { + "default-gateway": "^4.2.0", + "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", "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", "dev": true, "requires": { @@ -3537,9 +4458,33 @@ "integrity": "sha512-Ieh06s48WnEYGcqHepdsJUIJUXpwH5o5vodAX+DK2JA/gjy4EbEcQZxw+uFfzysmKjiLXGYwNG3qDZsKVMcINQ==" }, "invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "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 + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true + }, + "ipaddr.js": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", + "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==", + "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==", "dev": true }, "is-accessor-descriptor": { @@ -3551,6 +4496,12 @@ "kind-of": "^3.0.2" } }, + "is-arguments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", + "dev": true + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -3572,15 +4523,6 @@ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "dev": true, - "requires": { - "builtin-modules": "^1.0.0" - } - }, "is-callable": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", @@ -3588,12 +4530,12 @@ "dev": true }, "is-ci": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", - "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", "dev": true, "requires": { - "ci-info": "^1.5.0" + "ci-info": "^2.0.0" } }, "is-data-descriptor": { @@ -3630,21 +4572,6 @@ } } }, - "is-dotfile": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", - "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", - "dev": true - }, - "is-equal-shallow": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", - "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", - "dev": true, - "requires": { - "is-primitive": "^2.0.0" - } - }, "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", @@ -3652,20 +4579,11 @@ "dev": true }, "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", @@ -3673,29 +4591,53 @@ "dev": true }, "is-generator-fn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-1.0.0.tgz", - "integrity": "sha1-lp1J4bszKfa7fwkIm+JleLLd1Go=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true }, "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", "dev": true, "requires": { - "is-extglob": "^1.0.0" + "is-extglob": "^2.1.1" } }, "is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { "kind-of": "^3.0.2" } }, + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "dev": true + }, + "is-path-in-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", + "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", + "dev": true, + "requires": { + "is-path-inside": "^2.1.0" + } + }, + "is-path-inside": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", + "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", + "dev": true, + "requires": { + "path-is-inside": "^1.0.2" + } + }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -3713,18 +4655,6 @@ } } }, - "is-posix-bracket": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", - "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", - "dev": true - }, - "is-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", - "dev": true - }, "is-regex": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", @@ -3753,18 +4683,18 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "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-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -3778,13 +4708,10 @@ "dev": true }, "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true }, "isomorphic-fetch": { "version": "2.2.1", @@ -3811,528 +4738,722 @@ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, - "istanbul-api": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.3.7.tgz", - "integrity": "sha512-4/ApBnMVeEPG3EkSzcw25wDe4N66wxwn+KKn6b47vyek8Xb3NBAcg4xfuQbS7BqcZuTX4wxfD5lVagdggR3gyA==", - "dev": true, - "requires": { - "async": "^2.1.4", - "fileset": "^2.0.2", - "istanbul-lib-coverage": "^1.2.1", - "istanbul-lib-hook": "^1.2.2", - "istanbul-lib-instrument": "^1.10.2", - "istanbul-lib-report": "^1.1.5", - "istanbul-lib-source-maps": "^1.2.6", - "istanbul-reports": "^1.5.1", - "js-yaml": "^3.7.0", - "mkdirp": "^0.5.1", - "once": "^1.4.0" - } - }, "istanbul-lib-coverage": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.1.tgz", - "integrity": "sha512-PzITeunAgyGbtY1ibVIUiV679EFChHjoMNRibEIobvmrCRaIgwLxNucOSimtNWUhEib/oO7QY2imD75JVgCJWQ==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", "dev": true }, - "istanbul-lib-hook": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.2.2.tgz", - "integrity": "sha512-/Jmq7Y1VeHnZEQ3TL10VHyb564mn6VrQXHchON9Jf/AEcmQ3ZIiyD1BVzNOKTZf/G3gE+kiGK6SmpF9y3qGPLw==", - "dev": true, - "requires": { - "append-transform": "^0.4.0" - } - }, "istanbul-lib-instrument": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.2.tgz", - "integrity": "sha512-aWHxfxDqvh/ZlxR8BBaEPVSWDPUkGD63VjGQn3jcw8jCp7sHEMKcrj4xfJn/ABzdMEHiQNyvDQhqm5o8+SQg7A==", - "dev": true, - "requires": { - "babel-generator": "^6.18.0", - "babel-template": "^6.16.0", - "babel-traverse": "^6.18.0", - "babel-types": "^6.18.0", - "babylon": "^6.18.0", - "istanbul-lib-coverage": "^1.2.1", - "semver": "^5.3.0" + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "dev": true, + "requires": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } } }, "istanbul-lib-report": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.5.tgz", - "integrity": "sha512-UsYfRMoi6QO/doUshYNqcKJqVmFe9w51GZz8BS3WB0lYxAllQYklka2wP9+dGZeHYaWIdcXUx8JGdbqaoXRXzw==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", + "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", "dev": true, "requires": { - "istanbul-lib-coverage": "^1.2.1", - "mkdirp": "^0.5.1", - "path-parse": "^1.0.5", - "supports-color": "^3.1.2" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "^1.0.0" - } - } + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "supports-color": "^6.1.0" } }, "istanbul-lib-source-maps": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.6.tgz", - "integrity": "sha512-TtbsY5GIHgbMsMiRw35YBHGpZ1DVFEO19vxxeiDMYaeOFOCzfnYVxvl6pOUIZR4dtPhAGpSMup8OyF8ubsaqEg==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", "dev": true, "requires": { - "debug": "^3.1.0", - "istanbul-lib-coverage": "^1.2.1", - "mkdirp": "^0.5.1", - "rimraf": "^2.6.1", - "source-map": "^0.5.3" + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" }, "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "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 } } }, "istanbul-reports": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.5.1.tgz", - "integrity": "sha512-+cfoZ0UXzWjhAdzosCPP3AN8vvef8XDkWtTfgaN+7L3YTpNYITnCaEkceo5SEYy644VkHka/P1FvkWvrG/rrJw==", + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", + "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", "dev": true, "requires": { - "handlebars": "^4.0.3" + "handlebars": "^4.1.2" } }, "jest": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-23.6.0.tgz", - "integrity": "sha512-lWzcd+HSiqeuxyhG+EnZds6iO3Y3ZEnMrfZq/OTGvF/C+Z4fPMCdhWTGSAiO2Oym9rbEXfwddHhh6jqrTF3+Lw==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-24.9.0.tgz", + "integrity": "sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw==", "dev": true, "requires": { - "import-local": "^1.0.0", - "jest-cli": "^23.6.0" + "import-local": "^2.0.0", + "jest-cli": "^24.9.0" }, "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "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" + } + }, + "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 }, "jest-cli": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-23.6.0.tgz", - "integrity": "sha512-hgeD1zRUp1E1zsiyOXjEn4LzRLWdJBV//ukAHGlx6s5mfCNJTbhbHjgxnDUXA8fsKWN/HqFFF6X5XcCwC/IvYQ==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.9.0.tgz", + "integrity": "sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg==", "dev": true, "requires": { - "ansi-escapes": "^3.0.0", + "@jest/core": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", "chalk": "^2.0.1", "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.1.11", - "import-local": "^1.0.0", - "is-ci": "^1.0.10", - "istanbul-api": "^1.3.1", - "istanbul-lib-coverage": "^1.2.0", - "istanbul-lib-instrument": "^1.10.1", - "istanbul-lib-source-maps": "^1.2.4", - "jest-changed-files": "^23.4.2", - "jest-config": "^23.6.0", - "jest-environment-jsdom": "^23.4.0", - "jest-get-type": "^22.1.0", - "jest-haste-map": "^23.6.0", - "jest-message-util": "^23.4.0", - "jest-regex-util": "^23.3.0", - "jest-resolve-dependencies": "^23.6.0", - "jest-runner": "^23.6.0", - "jest-runtime": "^23.6.0", - "jest-snapshot": "^23.6.0", - "jest-util": "^23.4.0", - "jest-validate": "^23.6.0", - "jest-watcher": "^23.4.0", - "jest-worker": "^23.2.0", - "micromatch": "^2.3.11", - "node-notifier": "^5.2.1", - "prompts": "^0.1.9", - "realpath-native": "^1.0.0", - "rimraf": "^2.5.4", - "slash": "^1.0.0", - "string-length": "^2.0.0", - "strip-ansi": "^4.0.0", - "which": "^1.2.12", - "yargs": "^11.0.0" + "import-local": "^2.0.0", + "is-ci": "^2.0.0", + "jest-config": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "prompts": "^2.0.1", + "realpath-native": "^1.1.0", + "yargs": "^13.3.0" } }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "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": { - "ansi-regex": "^3.0.0" + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "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" + } + }, + "yargs": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "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.1" + } + }, + "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" } } } }, "jest-changed-files": { - "version": "23.4.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-23.4.2.tgz", - "integrity": "sha512-EyNhTAUWEfwnK0Is/09LxoqNDOn7mU7S3EHskG52djOFS/z+IT0jT3h3Ql61+dklcG7bJJitIWEMB4Sp1piHmA==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.9.0.tgz", + "integrity": "sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg==", "dev": true, "requires": { + "@jest/types": "^24.9.0", + "execa": "^1.0.0", "throat": "^4.0.0" } }, "jest-config": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-23.6.0.tgz", - "integrity": "sha512-i8V7z9BeDXab1+VNo78WM0AtWpBRXJLnkT+lyT+Slx/cbP5sZJ0+NDuLcmBE5hXAoK0aUp7vI+MOxR+R4d8SRQ==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz", + "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", "dev": true, "requires": { - "babel-core": "^6.0.0", - "babel-jest": "^23.6.0", + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^24.9.0", + "@jest/types": "^24.9.0", + "babel-jest": "^24.9.0", "chalk": "^2.0.1", "glob": "^7.1.1", - "jest-environment-jsdom": "^23.4.0", - "jest-environment-node": "^23.4.0", - "jest-get-type": "^22.1.0", - "jest-jasmine2": "^23.6.0", - "jest-regex-util": "^23.3.0", - "jest-resolve": "^23.6.0", - "jest-util": "^23.4.0", - "jest-validate": "^23.6.0", - "micromatch": "^2.3.11", - "pretty-format": "^23.6.0" + "jest-environment-jsdom": "^24.9.0", + "jest-environment-node": "^24.9.0", + "jest-get-type": "^24.9.0", + "jest-jasmine2": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "micromatch": "^3.1.10", + "pretty-format": "^24.9.0", + "realpath-native": "^1.1.0" } }, "jest-diff": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-23.6.0.tgz", - "integrity": "sha512-Gz9l5Ov+X3aL5L37IT+8hoCUsof1CVYBb2QEkOupK64XyRR3h+uRpYIm97K7sY8diFxowR8pIGEdyfMKTixo3g==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", + "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", "dev": true, "requires": { "chalk": "^2.0.1", - "diff": "^3.2.0", - "jest-get-type": "^22.1.0", - "pretty-format": "^23.6.0" + "diff-sequences": "^24.9.0", + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" } }, "jest-docblock": { - "version": "23.2.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-23.2.0.tgz", - "integrity": "sha1-8IXh8YVI2Z/dabICB+b9VdkTg6c=", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.9.0.tgz", + "integrity": "sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA==", "dev": true, "requires": { "detect-newline": "^2.1.0" } }, "jest-each": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-23.6.0.tgz", - "integrity": "sha512-x7V6M/WGJo6/kLoissORuvLIeAoyo2YqLOoCDkohgJ4XOXSqOtyvr8FbInlAWS77ojBsZrafbozWoKVRdtxFCg==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.9.0.tgz", + "integrity": "sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog==", "dev": true, "requires": { + "@jest/types": "^24.9.0", "chalk": "^2.0.1", - "pretty-format": "^23.6.0" + "jest-get-type": "^24.9.0", + "jest-util": "^24.9.0", + "pretty-format": "^24.9.0" } }, "jest-environment-jsdom": { - "version": "23.4.0", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-23.4.0.tgz", - "integrity": "sha1-BWp5UrP+pROsYqFAosNox52eYCM=", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz", + "integrity": "sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA==", "dev": true, "requires": { - "jest-mock": "^23.2.0", - "jest-util": "^23.4.0", + "@jest/environment": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-util": "^24.9.0", "jsdom": "^11.5.1" } }, "jest-environment-node": { - "version": "23.4.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-23.4.0.tgz", - "integrity": "sha1-V+gO0IQd6jAxZ8zozXlSHeuv3hA=", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.9.0.tgz", + "integrity": "sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA==", "dev": true, "requires": { - "jest-mock": "^23.2.0", - "jest-util": "^23.4.0" + "@jest/environment": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-util": "^24.9.0" } }, "jest-get-type": { - "version": "22.4.3", - "resolved": "http://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", - "integrity": "sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", + "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", "dev": true }, "jest-haste-map": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-23.6.0.tgz", - "integrity": "sha512-uyNhMyl6dr6HaXGHp8VF7cK6KpC6G9z9LiMNsst+rJIZ8l7wY0tk8qwjPmEghczojZ2/ZhtEdIabZ0OQRJSGGg==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz", + "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", "dev": true, "requires": { + "@jest/types": "^24.9.0", + "anymatch": "^2.0.0", "fb-watchman": "^2.0.0", - "graceful-fs": "^4.1.11", + "fsevents": "^1.2.7", + "graceful-fs": "^4.1.15", "invariant": "^2.2.4", - "jest-docblock": "^23.2.0", - "jest-serializer": "^23.0.1", - "jest-worker": "^23.2.0", - "micromatch": "^2.3.11", - "sane": "^2.0.0" + "jest-serializer": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.9.0", + "micromatch": "^3.1.10", + "sane": "^4.0.3", + "walker": "^1.0.7" + }, + "dependencies": { + "graceful-fs": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", + "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", + "dev": true + } } }, "jest-jasmine2": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-23.6.0.tgz", - "integrity": "sha512-pe2Ytgs1nyCs8IvsEJRiRTPC0eVYd8L/dXJGU08GFuBwZ4sYH/lmFDdOL3ZmvJR8QKqV9MFuwlsAi/EWkFUbsQ==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz", + "integrity": "sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw==", "dev": true, "requires": { - "babel-traverse": "^6.0.0", + "@babel/traverse": "^7.1.0", + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", "chalk": "^2.0.1", "co": "^4.6.0", - "expect": "^23.6.0", - "is-generator-fn": "^1.0.0", - "jest-diff": "^23.6.0", - "jest-each": "^23.6.0", - "jest-matcher-utils": "^23.6.0", - "jest-message-util": "^23.4.0", - "jest-snapshot": "^23.6.0", - "jest-util": "^23.4.0", - "pretty-format": "^23.6.0" + "expect": "^24.9.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "pretty-format": "^24.9.0", + "throat": "^4.0.0" } }, "jest-leak-detector": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-23.6.0.tgz", - "integrity": "sha512-f/8zA04rsl1Nzj10HIyEsXvYlMpMPcy0QkQilVZDFOaPbv2ur71X5u2+C4ZQJGyV/xvVXtCCZ3wQ99IgQxftCg==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz", + "integrity": "sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA==", "dev": true, "requires": { - "pretty-format": "^23.6.0" + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" } }, "jest-matcher-utils": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-23.6.0.tgz", - "integrity": "sha512-rosyCHQfBcol4NsckTn01cdelzWLU9Cq7aaigDf8VwwpIRvWE/9zLgX2bON+FkEW69/0UuYslUe22SOdEf2nog==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", + "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==", "dev": true, "requires": { "chalk": "^2.0.1", - "jest-get-type": "^22.1.0", - "pretty-format": "^23.6.0" + "jest-diff": "^24.9.0", + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" } }, "jest-message-util": { - "version": "23.4.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-23.4.0.tgz", - "integrity": "sha1-F2EMUJQjSVCNAaPR4L2iwHkIap8=", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", + "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0-beta.35", + "@babel/code-frame": "^7.0.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/stack-utils": "^1.0.1", "chalk": "^2.0.1", - "micromatch": "^2.3.11", - "slash": "^1.0.0", + "micromatch": "^3.1.10", + "slash": "^2.0.0", "stack-utils": "^1.0.1" } }, "jest-mock": { - "version": "23.2.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-23.2.0.tgz", - "integrity": "sha1-rRxg8p6HGdR8JuETgJi20YsmETQ=", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", + "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0" + } + }, + "jest-pnp-resolver": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz", + "integrity": "sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ==", "dev": true }, "jest-regex-util": { - "version": "23.3.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-23.3.0.tgz", - "integrity": "sha1-X4ZylUfCeFxAAs6qj4Sf6MpHG8U=", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", + "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==", "dev": true }, "jest-resolve": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-23.6.0.tgz", - "integrity": "sha512-XyoRxNtO7YGpQDmtQCmZjum1MljDqUCob7XlZ6jy9gsMugHdN2hY4+Acz9Qvjz2mSsOnPSH7skBmDYCHXVZqkA==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", + "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", "dev": true, "requires": { + "@jest/types": "^24.9.0", "browser-resolve": "^1.11.3", "chalk": "^2.0.1", - "realpath-native": "^1.0.0" + "jest-pnp-resolver": "^1.2.1", + "realpath-native": "^1.1.0" } }, "jest-resolve-dependencies": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-23.6.0.tgz", - "integrity": "sha512-EkQWkFWjGKwRtRyIwRwI6rtPAEyPWlUC2MpzHissYnzJeHcyCn1Hc8j7Nn1xUVrS5C6W5+ZL37XTem4D4pLZdA==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz", + "integrity": "sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g==", "dev": true, "requires": { - "jest-regex-util": "^23.3.0", - "jest-snapshot": "^23.6.0" + "@jest/types": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-snapshot": "^24.9.0" } }, "jest-runner": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-23.6.0.tgz", - "integrity": "sha512-kw0+uj710dzSJKU6ygri851CObtCD9cN8aNkg8jWJf4ewFyEa6kwmiH/r/M1Ec5IL/6VFa0wnAk6w+gzUtjJzA==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.9.0.tgz", + "integrity": "sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg==", "dev": true, "requires": { + "@jest/console": "^24.7.1", + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.4.2", "exit": "^0.1.2", - "graceful-fs": "^4.1.11", - "jest-config": "^23.6.0", - "jest-docblock": "^23.2.0", - "jest-haste-map": "^23.6.0", - "jest-jasmine2": "^23.6.0", - "jest-leak-detector": "^23.6.0", - "jest-message-util": "^23.4.0", - "jest-runtime": "^23.6.0", - "jest-util": "^23.4.0", - "jest-worker": "^23.2.0", + "graceful-fs": "^4.1.15", + "jest-config": "^24.9.0", + "jest-docblock": "^24.3.0", + "jest-haste-map": "^24.9.0", + "jest-jasmine2": "^24.9.0", + "jest-leak-detector": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-resolve": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.6.0", "source-map-support": "^0.5.6", "throat": "^4.0.0" }, "dependencies": { - "source-map-support": { - "version": "0.5.9", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz", - "integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==", + "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" + } + }, + "graceful-fs": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", + "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", + "dev": true + }, + "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": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "has-flag": "^3.0.0" } } } }, "jest-runtime": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-23.6.0.tgz", - "integrity": "sha512-ycnLTNPT2Gv+TRhnAYAQ0B3SryEXhhRj1kA6hBPSeZaNQkJ7GbZsxOLUkwg6YmvWGdX3BB3PYKFLDQCAE1zNOw==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.9.0.tgz", + "integrity": "sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw==", "dev": true, "requires": { - "babel-core": "^6.0.0", - "babel-plugin-istanbul": "^4.1.6", + "@jest/console": "^24.7.1", + "@jest/environment": "^24.9.0", + "@jest/source-map": "^24.3.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/yargs": "^13.0.0", "chalk": "^2.0.1", - "convert-source-map": "^1.4.0", "exit": "^0.1.2", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.1.11", - "jest-config": "^23.6.0", - "jest-haste-map": "^23.6.0", - "jest-message-util": "^23.4.0", - "jest-regex-util": "^23.3.0", - "jest-resolve": "^23.6.0", - "jest-snapshot": "^23.6.0", - "jest-util": "^23.4.0", - "jest-validate": "^23.6.0", - "micromatch": "^2.3.11", - "realpath-native": "^1.0.0", - "slash": "^1.0.0", - "strip-bom": "3.0.0", - "write-file-atomic": "^2.1.0", - "yargs": "^11.0.0" + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "jest-config": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "strip-bom": "^3.0.0", + "yargs": "^13.3.0" }, "dependencies": { - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "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" + } + }, + "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 + }, + "graceful-fs": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", + "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", "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" + } + }, + "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" + } + }, + "yargs": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "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.1" + } + }, + "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" + } } } }, "jest-serializer": { - "version": "23.0.1", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-23.0.1.tgz", - "integrity": "sha1-o3dq6zEekP6D+rnlM+hRAr0WQWU=", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", + "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==", "dev": true }, "jest-snapshot": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-23.6.0.tgz", - "integrity": "sha512-tM7/Bprftun6Cvj2Awh/ikS7zV3pVwjRYU2qNYS51VZHgaAMBs5l4o/69AiDHhQrj5+LA2Lq4VIvK7zYk/bswg==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.9.0.tgz", + "integrity": "sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew==", "dev": true, "requires": { - "babel-types": "^6.0.0", + "@babel/types": "^7.0.0", + "@jest/types": "^24.9.0", "chalk": "^2.0.1", - "jest-diff": "^23.6.0", - "jest-matcher-utils": "^23.6.0", - "jest-message-util": "^23.4.0", - "jest-resolve": "^23.6.0", + "expect": "^24.9.0", + "jest-diff": "^24.9.0", + "jest-get-type": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-resolve": "^24.9.0", "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", - "pretty-format": "^23.6.0", - "semver": "^5.5.0" + "pretty-format": "^24.9.0", + "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } } }, "jest-util": { - "version": "23.4.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-23.4.0.tgz", - "integrity": "sha1-TQY8uSe68KI4Mf9hvsLLv0l5NWE=", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", + "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", "dev": true, "requires": { - "callsites": "^2.0.0", + "@jest/console": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/source-map": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "callsites": "^3.0.0", "chalk": "^2.0.1", - "graceful-fs": "^4.1.11", - "is-ci": "^1.0.10", - "jest-message-util": "^23.4.0", + "graceful-fs": "^4.1.15", + "is-ci": "^2.0.0", "mkdirp": "^0.5.1", - "slash": "^1.0.0", + "slash": "^2.0.0", "source-map": "^0.6.0" + }, + "dependencies": { + "graceful-fs": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", + "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", + "dev": true + } } }, "jest-validate": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-23.6.0.tgz", - "integrity": "sha512-OFKapYxe72yz7agrDAWi8v2WL8GIfVqcbKRCLbRG9PAxtzF9b1SEDdTpytNDN12z2fJynoBwpMpvj2R39plI2A==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", + "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", "dev": true, "requires": { + "@jest/types": "^24.9.0", + "camelcase": "^5.3.1", "chalk": "^2.0.1", - "jest-get-type": "^22.1.0", - "leven": "^2.1.0", - "pretty-format": "^23.6.0" + "jest-get-type": "^24.9.0", + "leven": "^3.1.0", + "pretty-format": "^24.9.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + } } }, "jest-watcher": { - "version": "23.4.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-23.4.0.tgz", - "integrity": "sha1-0uKM50+NrWxq/JIrksq+9u0FyRw=", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.9.0.tgz", + "integrity": "sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw==", "dev": true, "requires": { + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/yargs": "^13.0.0", "ansi-escapes": "^3.0.0", "chalk": "^2.0.1", + "jest-util": "^24.9.0", "string-length": "^2.0.0" } }, "jest-worker": { - "version": "23.2.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-23.2.0.tgz", - "integrity": "sha1-+vcGqNo2+uYOsmlXJX+ntdjqArk=", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", + "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", "dev": true, "requires": { - "merge-stream": "^1.0.1" + "merge-stream": "^2.0.0", + "supports-color": "^6.1.0" } }, + "jquery": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.4.1.tgz", + "integrity": "sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw==", + "dev": true + }, "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, "js-yaml": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", - "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "dev": true, "requires": { "argparse": "^1.0.7", @@ -4378,9 +5499,9 @@ } }, "jsesc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, "json-parse-better-errors": { @@ -4404,12 +5525,29 @@ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, - "json5": { - "version": "0.5.1", - "resolved": "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "json3": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", + "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==", "dev": true }, + "json5": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", + "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, "jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", @@ -4420,11 +5558,11 @@ } }, "jsonld": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/jsonld/-/jsonld-1.5.0.tgz", - "integrity": "sha512-7jF9WXK4nuHvhz/qT6A4DEZ58tUYgrV98xBJEgHFhQ6GQaNT+oU1zqkFXKtDZsKsiEs/1K/VShNnat6SISb3jg==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/jsonld/-/jsonld-1.6.2.tgz", + "integrity": "sha512-eMzFHqhF2kPMrMUjw8+Lz9IF1QkrxTOIfVndkP/OpuoZs31VdDtfDs8mLa5EOC/ROdemFTQGLdYPZbRtmMe2Yw==", "requires": { - "rdf-canonize": "^1.0.1", + "rdf-canonize": "^1.0.2", "request": "^2.88.0", "semver": "^5.6.0", "xmldom": "0.1.19" @@ -4448,6 +5586,12 @@ "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", @@ -4458,45 +5602,38 @@ } }, "kleur": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-2.0.2.tgz", - "integrity": "sha512-77XF9iTllATmG9lSlIv0qdQ2BQ/h9t0bJllHlbvsQ0zUWfU7Yi0S8L5JXzPZgkefIiajLmBJJ4BsMJmqcf7oxQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true }, "lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", "dev": true, "requires": { - "invert-kv": "^1.0.0" + "invert-kv": "^2.0.0" } }, "ldfetch": { - "version": "1.1.1-alpha", - "resolved": "https://registry.npmjs.org/ldfetch/-/ldfetch-1.1.1-alpha.tgz", - "integrity": "sha512-9Mao1ltrI/EItYwZEq4W70aBYZ7iLHU+yYgpzSFTYTHGssxNRN8vZNJ/1nf9DHTGwcWmEEyfYeKsEU/SvHoxHg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/ldfetch/-/ldfetch-1.1.2.tgz", + "integrity": "sha512-LLU0GKrI6+LqBNYeL5TenALkECDh01xZ97Ir1rTtxovgXsX037wyVk02c1mmBDzWr6zBvxAo4RlMKYRi1ij8Bg==", "requires": { - "@rdfjs/data-model": "^1.1.0", - "commander": "^2.17.1", - "follow-redirects": "^1.5.5", + "@rdfjs/data-model": "^1.1.1", + "commander": "^2.19.0", + "follow-redirects": "^1.7.0", "http-cache-semantics": "^3.7.3", "jsdom": "^11.12.0", - "jsonld": "^1.0.2", - "n3": "1.0.0-alpha", + "jsonld": "^1.5.4", + "n3": "^1.0.5", "node-cache": "^4.2.0", "q": "^1.5.1", - "rdfa-processor": "^0.0.5", + "rdfa-processor": "^0.0.6", "rdfxmlprocessor": "0.0.3-alpha", "wreck": "^12.5.1", "xmldom": "^0.1.27" - }, - "dependencies": { - "n3": { - "version": "1.0.0-alpha", - "resolved": "https://registry.npmjs.org/n3/-/n3-1.0.0-alpha.tgz", - "integrity": "sha512-JJCef2qbYZCkwWkH6GitR/QwJrQ0VMoeAM1EdTl+xx7m6OLRUI1zUh1afBMRjslIWdkZodROf8gudY2vhXmByA==" - } } }, "left-pad": { @@ -4505,9 +5642,9 @@ "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==" }, "leven": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", - "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "dev": true }, "levn": { @@ -4520,61 +5657,77 @@ } }, "load-json-file": { - "version": "1.1.0", - "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", "dev": true, "requires": { "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" } }, "loader-runner": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.3.1.tgz", - "integrity": "sha512-By6ZFY7ETWOc9RFaAIb23IjJVcM4dvJC/N57nmdz9RSkMXvAXGI7SyVlAw3v8vjtDRlqThgVDVmTnr9fqMlxkw==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", "dev": true }, "loader-utils": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", - "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", + "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": "^3.1.3", + "big.js": "^5.2.2", "emojis-list": "^2.0.0", - "json5": "^0.5.0" + "json5": "^1.0.1" + }, + "dependencies": { + "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" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } } }, "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { - "p-locate": "^2.0.0", + "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" - }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", - "dev": true + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" }, "lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" }, + "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 + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -4594,19 +5747,26 @@ "yallist": "^2.1.2" } }, + "lunr": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.6.tgz", + "integrity": "sha512-swStvEyDqQ85MGpABCMBclZcLI/pBIlu8FFDtmX197+oEgKloJ67QnB+Tidh0340HmLMs39c4GrkPY3cmkXp6Q==", + "dev": true + }, "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "dev": true, "requires": { - "pify": "^3.0.0" + "pify": "^4.0.1", + "semver": "^5.6.0" }, "dependencies": { "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true } } @@ -4626,6 +5786,12 @@ "tmpl": "1.0.x" } }, + "mamacro": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz", + "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==", + "dev": true + }, "map-age-cleaner": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", @@ -4651,15 +5817,9 @@ } }, "marked": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-0.4.0.tgz", - "integrity": "sha512-tMsdNBgOsrUophCAFQl0XPe6Zqk/uy9gnue+jIIKhykO51hxyu6uNx7zBPy0+y/WKYVZZMspV9YeXLNdKk+iYw==", - "dev": true - }, - "math-random": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz", - "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz", + "integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==", "dev": true }, "md5.js": { @@ -4673,13 +5833,21 @@ "safe-buffer": "^5.1.2" } }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, "mem": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", - "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", "dev": true, "requires": { - "mimic-fn": "^1.0.0" + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" } }, "memory-fs": { @@ -4692,40 +5860,51 @@ "readable-stream": "^2.0.1" } }, - "merge": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz", - "integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ==", + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", "dev": true }, "merge-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", - "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", - "dev": true, - "requires": { - "readable-stream": "^2.0.1" - } + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true }, "micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "dev": true, - "requires": { - "arr-diff": "^2.0.0", - "array-unique": "^0.2.1", - "braces": "^1.8.2", - "expand-brackets": "^0.1.4", - "extglob": "^0.3.1", - "filename-regex": "^2.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.1", - "kind-of": "^3.0.2", - "normalize-path": "^2.0.1", - "object.omit": "^2.0.0", - "parse-glob": "^3.0.4", - "regex-cache": "^0.4.2" + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "dependencies": { + "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 + } } }, "miller-rabin": { @@ -4738,6 +5917,12 @@ "brorand": "^1.0.1" } }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, "mime-db": { "version": "1.37.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", @@ -4752,9 +5937,9 @@ } }, "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==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, "minimalistic-assert": { @@ -4785,9 +5970,9 @@ "dev": true }, "mississippi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz", - "integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", "dev": true, "requires": { "concat-stream": "^1.5.0", @@ -4796,16 +5981,16 @@ "flush-write-stream": "^1.0.0", "from2": "^2.1.0", "parallel-transform": "^1.1.0", - "pump": "^2.0.1", + "pump": "^3.0.0", "pumpify": "^1.3.3", "stream-each": "^1.1.0", "through2": "^2.0.0" } }, "mixin-deep": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "dev": true, "requires": { "for-in": "^1.0.2", @@ -4832,6 +6017,14 @@ "minimist": "0.0.8" } }, + "monotone-convex-hull-2d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/monotone-convex-hull-2d/-/monotone-convex-hull-2d-1.0.1.tgz", + "integrity": "sha1-R/Xa6t88Sv03dkuqGqh4ekDu4Iw=", + "requires": { + "robust-orientation": "^1.1.3" + } + }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", @@ -4849,12 +6042,34 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "dev": true, + "requires": { + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" + } + }, + "multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", + "dev": true + }, + "n3": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/n3/-/n3-1.1.1.tgz", + "integrity": "sha512-GEJXn+wc0f4l2noP1N/rMUH9Gei1DQ8IDN03eBsH+uQKkNQUOLgL7ZJVaDjY+pP3LmbLxL1LpUg/AvZ7Kc7KVw==" }, "nan": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.11.1.tgz", - "integrity": "sha512-iji6k87OSXa0CcrLl9z+ZiYSuR2o+c0bGuNmXdrhTQTakxytAFsC56SArGYoiHlJlFoHSnvmhpceZJaXkVuOtA==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", "dev": true, "optional": true }, @@ -4903,6 +6118,12 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "dev": true + }, "neo-async": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz", @@ -4924,10 +6145,20 @@ "lodash": "4.x" } }, + "node-dijkstra": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/node-dijkstra/-/node-dijkstra-2.5.0.tgz", + "integrity": "sha1-D+t2xaBfNbVueG3m300zZK8o1Og=" + }, + "node-fetch": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", + "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" + }, "node-forge": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.6.tgz", - "integrity": "sha512-sol30LUpz1jQFBjOKwbjxijiE3b6pjd74YwfD0fJOKPjF+fONKb2Yg8rYgS6+bK6VDl+/wfr4IYpC7jDzLUIfw==" + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.8.5.tgz", + "integrity": "sha512-vFMQIWt+J/7FLNyKouZ9TazT74PRV3wgv9UT4cRjC8BffxFbKXkgIWR42URCPSnHm/QDz6BOlb2Q0U4+VQT67Q==" }, "node-int64": { "version": "0.4.0", @@ -4936,9 +6167,9 @@ "dev": true }, "node-libs-browser": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.1.0.tgz", - "integrity": "sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", "dev": true, "requires": { "assert": "^1.1.1", @@ -4948,10 +6179,10 @@ "constants-browserify": "^1.0.0", "crypto-browserify": "^3.11.0", "domain-browser": "^1.1.1", - "events": "^1.0.0", + "events": "^3.0.0", "https-browserify": "^1.0.0", "os-browserify": "^0.3.0", - "path-browserify": "0.0.0", + "path-browserify": "0.0.1", "process": "^0.11.10", "punycode": "^1.2.4", "querystring-es3": "^0.2.0", @@ -4962,8 +6193,8 @@ "timers-browserify": "^2.0.4", "tty-browserify": "0.0.0", "url": "^0.11.0", - "util": "^0.10.3", - "vm-browserify": "0.0.4" + "util": "^0.11.0", + "vm-browserify": "^1.0.1" }, "dependencies": { "punycode": { @@ -4974,28 +6205,46 @@ } } }, + "node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true + }, "node-notifier": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.3.0.tgz", - "integrity": "sha512-AhENzCSGZnZJgBARsUjnQ7DnZbzyP+HxlVXuD0xqAnvL8q+OqtSX7lGg9e8nHzwXkMMXNdVeqq4E2M3EUAqX6Q==", + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.3.tgz", + "integrity": "sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q==", "dev": true, "requires": { "growly": "^1.3.0", + "is-wsl": "^1.1.0", "semver": "^5.5.0", "shellwords": "^0.1.1", "which": "^1.3.0" } }, "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, "requires": { "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", + "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + } } }, "normalize-path": { @@ -5060,10 +6309,22 @@ } } }, + "object-inspect": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", + "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", + "dev": true + }, + "object-is": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.1.tgz", + "integrity": "sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY=", + "dev": true + }, "object-keys": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", - "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true }, "object-visit": { @@ -5093,16 +6354,6 @@ "es-abstract": "^1.5.1" } }, - "object.omit": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", - "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", - "dev": true, - "requires": { - "for-own": "^0.1.4", - "is-extendable": "^0.1.1" - } - }, "object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", @@ -5120,6 +6371,27 @@ } } }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -5129,6 +6401,15 @@ "wrappy": "1" } }, + "opn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + } + }, "optimist": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", @@ -5160,27 +6441,30 @@ "wordwrap": "~1.0.0" } }, + "original": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", + "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", + "dev": true, + "requires": { + "url-parse": "^1.4.3" + } + }, "os-browserify": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", "dev": true }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true - }, "os-locale": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", - "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "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": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" } }, "os-shim": { @@ -5189,18 +6473,21 @@ "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=", "dev": true }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, "p-defer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", "dev": true }, + "p-each-series": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", + "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", + "dev": true, + "requires": { + "p-reduce": "^1.0.0" + } + }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -5208,91 +6495,114 @@ "dev": true }, "p-is-promise": { - "version": "1.1.0", - "resolved": "http://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", - "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", "dev": true }, "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", "dev": true, "requires": { - "p-try": "^1.0.0" + "p-try": "^2.0.0" } }, "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "requires": { - "p-limit": "^1.1.0" + "p-limit": "^2.0.0" } }, - "p-try": { + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true + }, + "p-reduce": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", + "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", + "dev": true + }, + "p-retry": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", + "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", + "dev": true, + "requires": { + "retry": "^0.12.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, "pako": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", - "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", + "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==", "dev": true }, "parallel-transform": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz", - "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", "dev": true, "requires": { - "cyclist": "~0.2.2", + "cyclist": "^1.0.1", "inherits": "^2.0.3", "readable-stream": "^2.1.5" } }, "parse-asn1": { - "version": "5.1.1", - "resolved": "http://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz", - "integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", + "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", "dev": true, "requires": { "asn1.js": "^4.0.0", "browserify-aes": "^1.0.0", "create-hash": "^1.1.0", "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3" - } - }, - "parse-glob": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", - "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", - "dev": true, - "requires": { - "glob-base": "^0.3.0", - "is-dotfile": "^1.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.0" + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" } }, "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", "dev": true, "requires": { - "error-ex": "^1.2.0" + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" } }, + "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 + }, "parse5": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==" }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, "pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", @@ -5300,9 +6610,9 @@ "dev": true }, "path-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", - "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", "dev": true }, "path-dirname": { @@ -5323,6 +6633,12 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", @@ -5335,15 +6651,19 @@ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "dev": true + }, "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "pify": "^3.0.0" } }, "pbkdf2": { @@ -5365,9 +6685,9 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "pify": { - "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true }, "pinkie": { @@ -5385,13 +6705,22 @@ "pinkie": "^2.0.0" } }, + "pirates": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "dev": true, + "requires": { + "node-modules-regexp": "^1.0.0" + } + }, "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", "dev": true, "requires": { - "find-up": "^2.1.0" + "find-up": "^3.0.0" } }, "pn": { @@ -5399,6 +6728,22 @@ "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==" }, + "point-in-polygon": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/point-in-polygon/-/point-in-polygon-1.0.1.tgz", + "integrity": "sha1-1Ztk6P7kHElFiqyCtWcYxZV7Kvc=" + }, + "portfinder": { + "version": "1.0.24", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.24.tgz", + "integrity": "sha512-ekRl7zD2qxYndYflwiryJwMioBI7LI7rVXg3EnLK3sjkouT5eOuhS3gS255XxBksa30VG8UPZYZCdgfGOfkSUg==", + "dev": true, + "requires": { + "async": "^1.5.2", + "debug": "^2.2.0", + "mkdirp": "0.5.x" + } + }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -5432,12 +6777,6 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" }, - "preserve": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", - "dev": true - }, "prettier": { "version": "1.14.3", "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.14.3.tgz", @@ -5445,38 +6784,17 @@ "dev": true }, "pretty-format": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", - "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", + "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", "dev": true, "requires": { - "ansi-regex": "^3.0.0", - "ansi-styles": "^3.2.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "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" - } - } + "@jest/types": "^24.9.0", + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0", + "react-is": "^16.8.4" } }, - "private": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", - "dev": true - }, "process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -5502,13 +6820,23 @@ "dev": true }, "prompts": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-0.1.14.tgz", - "integrity": "sha512-rxkyiE9YH6zAz/rZpywySLKkpaj0NMVyNw1qhsubdbjjSgcayjTShDreZGlFMcGSu5sab3bAKPfFk78PB90+8w==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.2.1.tgz", + "integrity": "sha512-VObPvJiWPhpZI6C5m60XOzTfnYg/xc/an+r9VYymj9WJW3B/DIH+REzjpAACPf8brwPeP+7vz3bIim3S+AaMjw==", + "dev": true, + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.3" + } + }, + "proxy-addr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", + "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", "dev": true, "requires": { - "kleur": "^2.0.1", - "sisteransi": "^0.1.1" + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.0" } }, "prr": { @@ -5543,9 +6871,9 @@ } }, "pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "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", @@ -5561,6 +6889,18 @@ "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": { @@ -5590,35 +6930,21 @@ "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", "dev": true }, - "randomatic": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.0.tgz", - "integrity": "sha512-KnGPVE0lo2WoXxIZ7cPR8YBpiol4gsSuOwDSg410oHh80ZMp5EiypNqL2K4Z77vJn6lB5rap7IkAmcUlalcnBQ==", - "dev": true, - "requires": { - "is-number": "^4.0.0", - "kind-of": "^6.0.0", - "math-random": "^1.0.1" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true - }, - "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 - } - } + "querystringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", + "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==", + "dev": true + }, + "quickselect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-1.1.1.tgz", + "integrity": "sha512-qN0Gqdw4c4KGPsBOQafj6yj/PA6c/L63f6CaZ/DCF/xF4Esu3jVmKLUDYxghFx8Kb/O7y9tI7x2RjTSXwdK1iQ==" }, "randombytes": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", - "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", + "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" @@ -5634,28 +6960,55 @@ "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 + } + } + }, + "rbush": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/rbush/-/rbush-2.0.2.tgz", + "integrity": "sha512-XBOuALcTm+O/H8G90b6pzu6nX6v2zCKiFG4BJho8a+bY6AER6t8uQUZdi5bomQc0AprCWhEGa7ncAbbRap0bRA==", + "requires": { + "quickselect": "^1.0.1" + } + }, "rdf-canonize": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/rdf-canonize/-/rdf-canonize-1.0.1.tgz", - "integrity": "sha512-vQq6q7BIUwrVQijKRYdunxlodkn0Btjv2MnJ4S3rOUELsghq7fGuDaWuqBNbXca3KRbcRS6HwTIT2hJbJej2UA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/rdf-canonize/-/rdf-canonize-1.0.3.tgz", + "integrity": "sha512-piLMOB5Q6LJSVx2XzmdpHktYVb8TmVTy8coXJBFtdkcMC96DknZOuzpAYqCWx2ERZX7xEW+mMi8/wDuMJS/95w==", "requires": { - "node-forge": "^0.7.6", + "node-forge": "^0.8.1", "semver": "^5.6.0" } }, "rdfa-processor": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/rdfa-processor/-/rdfa-processor-0.0.5.tgz", - "integrity": "sha512-272KPQ5xrBmTh4DijaBSoS0A1fXMzhqmctbvOl7Ud0R1X+km1aR/CZ3pD7Lbjiko30tNY1CTseysnCvZkW2jLg==", + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/rdfa-processor/-/rdfa-processor-0.0.6.tgz", + "integrity": "sha512-wA0ZyqHRWVvzFG0SESkfbWe2NAmKfZKsMivRlbt+xgxb1CiCEbheZHIJjfPf3YzAjOp9LIvhKN5kMFqmV62yCw==", "requires": { - "n3": "^1.0.0-alpha" - }, - "dependencies": { - "n3": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/n3/-/n3-1.0.3.tgz", - "integrity": "sha512-IdcCNqb/1gj9fX63hoVEn3/Z1u9iLJiYLSpesmqT3+5UrxcYG5YldUP6T2okNRZKzyVdqz+I0PExGkWkz9gcZw==" - } + "n3": "^1.0.x" } }, "rdfxmlprocessor": { @@ -5664,604 +7017,59 @@ "integrity": "sha512-QrA8AQIoQRKrOQ/6hasVVS7zPT80twfAyxmawjhjqYFUacyx2yqz1qOeCKHsYhKPk/VwgF15V7CwddPNvBlDTw==", "requires": { "n3": "^1.0.0-beta.1" - }, - "dependencies": { - "n3": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/n3/-/n3-1.0.3.tgz", - "integrity": "sha512-IdcCNqb/1gj9fX63hoVEn3/Z1u9iLJiYLSpesmqT3+5UrxcYG5YldUP6T2okNRZKzyVdqz+I0PExGkWkz9gcZw==" - } } }, + "react-is": { + "version": "16.9.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.9.0.tgz", + "integrity": "sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw==", + "dev": true + }, "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", "dev": true, "requires": { - "load-json-file": "^1.0.0", + "load-json-file": "^4.0.0", "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - } - }, - "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "dev": true, - "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - }, - "dependencies": { - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } - } - } - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "path-type": "^3.0.0" } - }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "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 - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - } - } - }, - "realpath-native": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.0.2.tgz", - "integrity": "sha512-+S3zTvVt9yTntFrBpm7TQmQ3tzpCrnA1a/y+3cUHAc9ZR6aIjG0WNLR+Rj79QpJktY+VeW/TQtFlQ1bzsehI8g==", - "dev": true, - "requires": { - "util.promisify": "^1.0.0" - } - }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dev": true, - "requires": { - "resolve": "^1.1.6" - } - }, - "reflect-metadata": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.12.tgz", - "integrity": "sha512-n+IyV+nGz3+0q3/Yf1ra12KpCyi001bi4XFxSjbiWWjfqb52iTTtpGXmCCAOWWIAn9KEuFZKGqBERHmrtScZ3A==" - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true - }, - "regex-cache": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", - "dev": true, - "requires": { - "is-equal-shallow": "^0.1.3" - } - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "dev": true, - "requires": { - "is-finite": "^1.0.0" - } - }, - "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - } - }, - "request-promise-core": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", - "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", - "requires": { - "lodash": "^4.13.1" - } - }, - "request-promise-native": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.5.tgz", - "integrity": "sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU=", - "requires": { - "request-promise-core": "1.1.1", - "stealthy-require": "^1.1.0", - "tough-cookie": ">=2.3.3" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", - "dev": true - }, - "resolve": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", - "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", - "dev": true, - "requires": { - "path-parse": "^1.0.5" - } - }, - "resolve-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", - "dev": true, - "requires": { - "resolve-from": "^3.0.0" - } - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, - "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", - "dev": true, - "requires": { - "glob": "^7.0.5" - } - }, - "ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dev": true, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "rsvp": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz", - "integrity": "sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw==", - "dev": true - }, - "run-queue": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", - "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + }, + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", "dev": true, "requires": { - "aproba": "^1.1.1" + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" } }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "ret": "~0.1.10" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "sane": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/sane/-/sane-2.5.2.tgz", - "integrity": "sha1-tNwYYcIbQn6SlQej51HiosuKs/o=", + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", "dev": true, "requires": { - "anymatch": "^2.0.0", - "capture-exit": "^1.2.0", - "exec-sh": "^0.2.0", - "fb-watchman": "^2.0.0", - "fsevents": "^1.2.3", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5", - "watch": "~0.18.0" + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" }, "dependencies": { "arr-diff": { @@ -6546,7 +7354,297 @@ "snapdragon": "^0.8.1", "to-regex": "^3.0.2" } - }, + } + } + }, + "realpath-native": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", + "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", + "dev": true, + "requires": { + "util.promisify": "^1.0.0" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, + "reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regexp.prototype.flags": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz", + "integrity": "sha512-ztaw4M1VqgMwl9HlPpOuiYgItcHlunW0He2fE6eNfT6E/CF2FtYi9ofOYe4mKntstYk0Fyh/rDRBdS3AnxjlrA==", + "dev": true, + "requires": { + "define-properties": "^1.1.2" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "request-promise-core": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", + "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", + "requires": { + "lodash": "^4.13.1" + } + }, + "request-promise-native": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.5.tgz", + "integrity": "sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU=", + "requires": { + "request-promise-core": "1.1.1", + "stealthy-require": "^1.1.0", + "tough-cookie": ">=2.3.3" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "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 + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "resolve": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", + "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "dev": true, + "requires": { + "path-parse": "^1.0.5" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "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", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "robust-orientation": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/robust-orientation/-/robust-orientation-1.1.3.tgz", + "integrity": "sha1-2v9bANO+TmByLw6cAVbvln8cIEk=", + "requires": { + "robust-scale": "^1.0.2", + "robust-subtract": "^1.0.0", + "robust-sum": "^1.0.0", + "two-product": "^1.0.2" + } + }, + "robust-scale": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/robust-scale/-/robust-scale-1.0.2.tgz", + "integrity": "sha1-d1Ey7QlULQKOWLLMecBikLz3jDI=", + "requires": { + "two-product": "^1.0.2", + "two-sum": "^1.0.0" + } + }, + "robust-subtract": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/robust-subtract/-/robust-subtract-1.0.0.tgz", + "integrity": "sha1-4LFk4e2LpOOl3aRaEgODSNvtPpo=" + }, + "robust-sum": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/robust-sum/-/robust-sum-1.0.0.tgz", + "integrity": "sha1-FmRuUlKStNJdgnV6KGlV4Lv6U9k=" + }, + "rsvp": { + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", + "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", + "dev": true + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "dev": true, + "requires": { + "aproba": "^1.1.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sane": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", + "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", + "dev": true, + "requires": { + "@cnakazawa/watch": "^1.0.3", + "anymatch": "^2.0.0", + "capture-exit": "^2.0.0", + "exec-sh": "^0.3.2", + "execa": "^1.0.0", + "fb-watchman": "^2.0.0", + "micromatch": "^3.1.4", + "minimist": "^1.1.1", + "walker": "~1.0.5" + }, + "dependencies": { "minimist": { "version": "1.2.0", "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", @@ -6561,19 +7659,20 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, "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==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "dev": true, "requires": { "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", "ajv-keywords": "^3.1.0" }, "dependencies": { "ajv": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.5.tgz", - "integrity": "sha512-7q7gtRQDJSyuEHjuVgHoUa2VuemFiCMrfQc9Tc08XTAc4Zj/5U1buQJ0HU6i7fKjXU09SVgSmxa4sLvuvS8Iyg==", + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", @@ -6596,17 +7695,116 @@ } } }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "dev": true + }, + "selfsigned": { + "version": "1.10.6", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.6.tgz", + "integrity": "sha512-i3+CeqxL7DpAazgVpAGdKMwHuL63B5nhJMh9NQ7xmChGkA3jNFflq6Jyo1LLJYcr3idWiNOPWHCrm4zMayLG4w==", + "dev": true, + "requires": { + "node-forge": "0.8.2" + }, + "dependencies": { + "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==", + "dev": true + } + } + }, "semver": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, "serialize-javascript": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.5.0.tgz", - "integrity": "sha512-Ga8c8NjAAp46Br4+0oZ2WxJCwIzwP60Gq1YPgU+39PiTVxyed/iKE/zyZI6+UlVYH5Q4PaQdHhcegIFPZTUfoQ==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.9.1.tgz", + "integrity": "sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A==", "dev": true }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -6614,9 +7812,9 @@ "dev": true }, "set-value": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "dev": true, "requires": { "extend-shallow": "^2.0.1", @@ -6642,6 +7840,12 @@ "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", "dev": true }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "dev": true + }, "sha.js": { "version": "2.4.11", "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", @@ -6691,15 +7895,15 @@ "dev": true }, "sisteransi": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-0.1.1.tgz", - "integrity": "sha512-PmGOd02bM9YO5ifxpw36nrNMBTptEtfRl4qUYl9SndkolplkrZZOW7PGHjrZL53QvMVj9nQ+TKqUnRsw4tJa4g==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.3.tgz", + "integrity": "sha512-SbEG75TzH8G7eVXFSN5f9EExILKfly7SUvVY5DhhYLvfhKqhDFY0OzevWa/zwak0RLRfWS5AvfMWpd9gJvr5Yg==", "dev": true }, "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", "dev": true }, "snapdragon": { @@ -6825,6 +8029,56 @@ "kind-of": "^3.2.0" } }, + "sockjs": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz", + "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==", + "dev": true, + "requires": { + "faye-websocket": "^0.10.0", + "uuid": "^3.0.1" + } + }, + "sockjs-client": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.4.0.tgz", + "integrity": "sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g==", + "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" + }, + "dependencies": { + "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" + } + }, + "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" + } + }, + "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 + } + } + }, "source-list-map": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", @@ -6850,20 +8104,13 @@ } }, "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, "requires": { - "source-map": "^0.5.6" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" } }, "source-map-url": { @@ -6883,9 +8130,9 @@ } }, "spdx-correct": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.2.tgz", - "integrity": "sha512-q9hedtzyXHr5S0A1vEPoK/7l8NpfkFYTq6iCY+Pno2ZbdZR6WexZFtqeVGkGxW3TEJMN914Z55EnAGMmenlIQQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", @@ -6909,11 +8156,83 @@ } }, "spdx-license-ids": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.1.tgz", - "integrity": "sha512-TfOfPcYGBB5sDuPn3deByxPhmfegAhpDYKSOXZQN81Oyrrif8ZCodOLzK3AesELnCx03kikhyDwh0pfvvQvF8w==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", "dev": true }, + "spdy": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.1.tgz", + "integrity": "sha512-HeZS3PBdMA+sZSu0qwpCxl3DeALD5ASx8pAX0jZdKXSpPWbQ6SYGnlg3BBmYLx5LtiZrmkAZfErCm2oECBcioA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "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 + } + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "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 + }, + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", @@ -6946,18 +8265,18 @@ } }, "ssri": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.3.0.tgz", - "integrity": "sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", "dev": true, "requires": { - "safe-buffer": "^5.1.1" + "figgy-pudding": "^3.5.1" } }, "stack-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.1.tgz", - "integrity": "sha1-1PM6tU6OOHeLDKXP07OvsS22hiA=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", + "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", "dev": true }, "static-extend": { @@ -6981,15 +8300,21 @@ } } }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + }, "stealthy-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" }, "stream-browserify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", - "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", "dev": true, "requires": { "inherits": "~2.0.1", @@ -7079,6 +8404,26 @@ } } }, + "string.prototype.trimleft": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", + "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", + "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -7089,22 +8434,19 @@ } }, "strip-ansi": { - "version": "3.0.1", - "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "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": "^2.0.0" + "ansi-regex": "^4.1.0" } }, "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true, - "requires": { - "is-utf8": "^0.2.0" - } + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true }, "strip-eof": { "version": "1.0.0", @@ -7113,10 +8455,13 @@ "dev": true }, "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true + "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" + } }, "symbol-tree": { "version": "3.2.2", @@ -7124,22 +8469,49 @@ "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=" }, "tapable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.0.tgz", - "integrity": "sha512-IlqtmLVaZA2qab8epUXbVWRn3aB1imbDMJtjB3nu4X0NqPkcY/JH9ZtCBWKHWPxs8Svi9tyo8w2dBoi07qZbBA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", "dev": true }, + "terser": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.3.2.tgz", + "integrity": "sha512-obxk4x19Zlzj9zY4QeXj9iPCb5W8YGn4v3pn4/fHj0Nw8+R7N02Kvwvz9VpOItCZZD8RC+vnYCDL0gP6FAJ7Xg==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + } + }, + "terser-webpack-plugin": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.1.tgz", + "integrity": "sha512-ZXmmfiwtCLfz8WKZyYUuuHf3dMYEjg8NrjHMb0JqHVHVOSkzp3cW2/XG1fP3tRhqEqSzMwzzRQGtAPbs4Cncxg==", + "dev": true, + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^1.7.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + } + }, "test-exclude": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.2.3.tgz", - "integrity": "sha512-SYbXgY64PT+4GAL2ocI3HwPa4Q4TBKm0cwAVeKOt/Aoc0gSpNRjJX8w0pA1LMKZ3LBmd8pYBqApFNQLII9kavA==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", + "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", "dev": true, "requires": { - "arrify": "^1.0.1", - "micromatch": "^2.3.11", - "object-assign": "^4.1.0", - "read-pkg-up": "^1.0.1", - "require-main-filename": "^1.0.1" + "glob": "^7.1.3", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^2.0.0" } }, "throat": { @@ -7158,15 +8530,31 @@ "xtend": "~4.0.1" } }, + "thunky": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.3.tgz", + "integrity": "sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow==", + "dev": true + }, + "tiles-in-bbox": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tiles-in-bbox/-/tiles-in-bbox-1.0.2.tgz", + "integrity": "sha512-LTV5BK/9yb73DtS6C+2Y0J4fCPfu/hXW5BjH8DR7yeaE+ykWqaZmHVAKjCp7oL8ZkDxrxeLQhoq9FFYDHyyOzA==" + }, "timers-browserify": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz", - "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==", + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz", + "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==", "dev": true, "requires": { "setimmediate": "^1.0.4" } }, + "tinyqueue": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz", + "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==" + }, "tmpl": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", @@ -7180,9 +8568,9 @@ "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=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", "dev": true }, "to-object-path": { @@ -7227,6 +8615,12 @@ } } }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "dev": true + }, "tough-cookie": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", @@ -7251,16 +8645,10 @@ "punycode": "^2.1.0" } }, - "trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", - "dev": true - }, "ts-jest": { - "version": "23.10.4", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-23.10.4.tgz", - "integrity": "sha512-oV/wBwGUS7olSk/9yWMiSIJWbz5xO4zhftnY3gwv6s4SMg6WHF1m8XZNBvQOKQRiTAexZ9754Z13dxBq3Zgssw==", + "version": "23.10.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-23.10.5.tgz", + "integrity": "sha512-MRCs9qnGoyKgFc8adDEntAOP64fWK1vZKnOYU1o2HxaqjdJvGqmkLCPCnVq1/If4zkUmEjKPnCiUisTrlX2p2A==", "dev": true, "requires": { "bs-logger": "0.x", @@ -7269,6 +8657,7 @@ "json5": "2.x", "make-error": "1.x", "mkdirp": "0.x", + "resolve": "1.x", "semver": "^5.5", "yargs-parser": "10.x" }, @@ -7300,9 +8689,9 @@ } }, "ts-loader": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-5.3.0.tgz", - "integrity": "sha512-lGSNs7szRFj/rK9T1EQuayE3QNLg6izDUxt5jpmq0RG1rU2bapAt7E7uLckLCUPeO1jwxCiet2oRaWovc53UAg==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-5.4.5.tgz", + "integrity": "sha512-XYsjfnRQCBum9AMRZpk2rTYSVpdZBpZK+kDh0TeT3kxmQNBDVIeUjdPjY5RZry4eIAb8XHc4gYSUiUWPYvzSRw==", "dev": true, "requires": { "chalk": "^2.3.0", @@ -7598,29 +8987,30 @@ } }, "tslib": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", "dev": true }, "tslint": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.11.0.tgz", - "integrity": "sha1-mPMMAurjzecAYgHkwzywi0hYHu0=", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.0.tgz", + "integrity": "sha512-2vqIvkMHbnx8acMogAERQ/IuINOq6DFqgF8/VDvhEkBqQh/x6SP0Y+OHnKth9/ZcHQSroOZwUQSN18v8KKF0/g==", "dev": true, "requires": { - "babel-code-frame": "^6.22.0", + "@babel/code-frame": "^7.0.0", "builtin-modules": "^1.1.1", "chalk": "^2.3.0", "commander": "^2.12.1", - "diff": "^3.2.0", + "diff": "^4.0.1", "glob": "^7.1.1", - "js-yaml": "^3.7.0", + "js-yaml": "^3.13.1", "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", "resolve": "^1.3.2", "semver": "^5.3.0", "tslib": "^1.8.0", - "tsutils": "^2.27.2" + "tsutils": "^2.29.0" } }, "tsutils": { @@ -7651,6 +9041,16 @@ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, + "two-product": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/two-product/-/two-product-1.0.2.tgz", + "integrity": "sha1-Z9ldSyV6kh4stL16+VEfkIhSLqo=" + }, + "two-sum": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/two-sum/-/two-sum-1.0.0.tgz", + "integrity": "sha1-MdPzIjnk9zHsqd+RVeKyl/AIq2Q=" + }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -7659,6 +9059,33 @@ "prelude-ls": "~1.1.2" } }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "dependencies": { + "mime-db": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "dev": true + }, + "mime-types": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "dev": true, + "requires": { + "mime-db": "1.40.0" + } + } + } + }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -7666,137 +9093,77 @@ "dev": true }, "typedoc": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.14.2.tgz", - "integrity": "sha512-aEbgJXV8/KqaVhcedT7xG6d2r+mOvB5ep3eIz1KuB5sc4fDYXcepEEMdU7XSqLFO5hVPu0nllHi1QxX2h/QlpQ==", + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.15.0.tgz", + "integrity": "sha512-NOtfq5Tis4EFt+J2ozhVq9RCeUnfEYMFKoU6nCXCXUULJz1UQynOM+yH3TkfZCPLzigbqB0tQYGVlktUWweKlw==", "dev": true, "requires": { - "@types/fs-extra": "^5.0.3", - "@types/handlebars": "^4.0.38", - "@types/highlight.js": "^9.12.3", - "@types/lodash": "^4.14.110", - "@types/marked": "^0.4.0", "@types/minimatch": "3.0.3", - "@types/shelljs": "^0.8.0", - "fs-extra": "^7.0.0", - "handlebars": "^4.0.6", - "highlight.js": "^9.13.1", - "lodash": "^4.17.10", - "marked": "^0.4.0", + "fs-extra": "^8.1.0", + "handlebars": "^4.1.2", + "highlight.js": "^9.15.8", + "lodash": "^4.17.15", + "marked": "^0.7.0", "minimatch": "^3.0.0", - "progress": "^2.0.0", - "shelljs": "^0.8.2", - "typedoc-default-themes": "^0.5.0", - "typescript": "3.2.x" + "progress": "^2.0.3", + "shelljs": "^0.8.3", + "typedoc-default-themes": "^0.6.0", + "typescript": "3.5.x" }, "dependencies": { "typescript": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.4.tgz", - "integrity": "sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz", + "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==", "dev": true } } }, "typedoc-default-themes": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.5.0.tgz", - "integrity": "sha1-bcJDPnjti+qOiHo6zeLzF4W9Yic=", - "dev": true - }, - "typescript": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.3.tgz", - "integrity": "sha512-Y21Xqe54TBVp+VDSNbuDYdGw0BpoR/Q6wo/+35M8PAU0vipahnyduJWirxxdxjsAkS7hue53x2zp8gz7F05u0A==", - "dev": true - }, - "uglify-js": { - "version": "3.4.9", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", - "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.6.0.tgz", + "integrity": "sha512-MdTROOojxod78CEv22rIA69o7crMPLnVZPefuDLt/WepXqJwgiSu8Xxq+H36x0Jj3YGc7lOglI2vPJ2GhoOybw==", "dev": true, - "optional": true, "requires": { - "commander": "~2.17.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", - "dev": true, - "optional": true - } + "backbone": "^1.4.0", + "jquery": "^3.4.1", + "lunr": "^2.3.6", + "underscore": "^1.9.1" } }, - "uglifyjs-webpack-plugin": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.3.0.tgz", - "integrity": "sha512-ovHIch0AMlxjD/97j9AYovZxG5wnHOPkL7T1GKochBADp/Zwc44pEWNqpKl1Loupp1WhFg7SlYmHZRUfdAacgw==", - "dev": true, - "requires": { - "cacache": "^10.0.4", - "find-cache-dir": "^1.0.0", - "schema-utils": "^0.4.5", - "serialize-javascript": "^1.4.0", - "source-map": "^0.6.1", - "uglify-es": "^3.3.4", - "webpack-sources": "^1.1.0", - "worker-farm": "^1.5.2" - }, - "dependencies": { - "commander": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", - "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==", - "dev": true - }, - "uglify-es": { - "version": "3.3.9", - "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz", - "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==", - "dev": true, - "requires": { - "commander": "~2.13.0", - "source-map": "~0.6.1" - } - } + "typescript": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.3.tgz", + "integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==", + "dev": true + }, + "uglify-js": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", + "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", + "dev": true, + "optional": true, + "requires": { + "commander": "~2.20.0", + "source-map": "~0.6.1" } }, + "underscore": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", + "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==", + "dev": true + }, "union-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "dev": true, "requires": { "arr-union": "^3.1.0", "get-value": "^2.0.6", "is-extendable": "^0.1.1", - "set-value": "^0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" - } - } + "set-value": "^2.0.1" } }, "unique-filename": { @@ -7809,9 +9176,9 @@ } }, "unique-slug": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.1.tgz", - "integrity": "sha512-n9cU6+gITaVu7VGj1Z8feKMmfAjEAQGhwD9fE3zvpRRa0wEIx8ODYkVGfSc94M2OX00tUFV8wH3zYbm1I8mxFg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", "dev": true, "requires": { "imurmurhash": "^0.1.4" @@ -7823,6 +9190,12 @@ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", @@ -7870,9 +9243,9 @@ } }, "upath": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", - "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", + "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==", "dev": true }, "uri-js": { @@ -7913,6 +9286,16 @@ } } }, + "url-parse": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz", + "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==", + "dev": true, + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", @@ -7920,9 +9303,9 @@ "dev": true }, "util": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", - "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", "dev": true, "requires": { "inherits": "2.0.3" @@ -7944,15 +9327,21 @@ "object.getownpropertydescriptors": "^2.0.3" } }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, "uuid": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" }, "v8-compile-cache": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.2.tgz", - "integrity": "sha512-1wFuMUIM16MDJRCrpbpuEPTUGmM5QMUg0cr3KFwra2XgOgFcPGDQHDh3CszSCD2Zewc/dh/pamNEW8CbfDebUw==", + "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": { @@ -7965,6 +9354,12 @@ "spdx-expression-parse": "^3.0.0" } }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -7976,13 +9371,10 @@ } }, "vm-browserify": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", - "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", - "dev": true, - "requires": { - "indexof": "0.0.1" - } + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.0.tgz", + "integrity": "sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==", + "dev": true }, "w3c-hr-time": { "version": "1.0.1", @@ -8001,24 +9393,6 @@ "makeerror": "1.0.x" } }, - "watch": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/watch/-/watch-0.18.0.tgz", - "integrity": "sha1-KAlUdsbffJDJYxOJkMClQj60uYY=", - "dev": true, - "requires": { - "exec-sh": "^0.2.0", - "minimist": "^1.2.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, "watchpack": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", @@ -8030,231 +9404,67 @@ "neo-async": "^2.5.0" } }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, "webidl-conversions": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" }, "webpack": { - "version": "4.25.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.25.1.tgz", - "integrity": "sha512-T0GU/3NRtO4tMfNzsvpdhUr8HnzA4LTdP2zd+e5zd6CdOH5vNKHnAlO+DvzccfhPdzqRrALOFcjYxx7K5DWmvA==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.7.11", - "@webassemblyjs/helper-module-context": "1.7.11", - "@webassemblyjs/wasm-edit": "1.7.11", - "@webassemblyjs/wasm-parser": "1.7.11", - "acorn": "^5.6.2", - "acorn-dynamic-import": "^3.0.0", - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0", - "chrome-trace-event": "^1.0.0", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.0.tgz", + "integrity": "sha512-yNV98U4r7wX1VJAj5kyMsu36T8RPPQntcb5fJLOsMz/pt/WrKC0Vp1bAlqPLkA1LegSwQwf6P+kAbyhRKVQ72g==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/wasm-edit": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "acorn": "^6.2.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^4.1.0", - "eslint-scope": "^4.0.0", + "eslint-scope": "^4.0.3", "json-parse-better-errors": "^1.0.2", - "loader-runner": "^2.3.0", - "loader-utils": "^1.1.0", - "memory-fs": "~0.4.1", - "micromatch": "^3.1.8", - "mkdirp": "~0.5.0", - "neo-async": "^2.5.0", - "node-libs-browser": "^2.0.0", - "schema-utils": "^0.4.4", - "tapable": "^1.1.0", - "uglifyjs-webpack-plugin": "^1.2.4", - "watchpack": "^1.5.0", - "webpack-sources": "^1.3.0" + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.1", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.1", + "watchpack": "^1.6.0", + "webpack-sources": "^1.4.1" }, "dependencies": { - "ajv": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.5.tgz", - "integrity": "sha512-7q7gtRQDJSyuEHjuVgHoUa2VuemFiCMrfQc9Tc08XTAc4Zj/5U1buQJ0HU6i7fKjXU09SVgSmxa4sLvuvS8Iyg==", - "dev": true, - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "acorn": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", + "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==", "dev": true }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", "dev": true, "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, "fast-deep-equal": { @@ -8263,137 +9473,78 @@ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", "dev": true }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "dev": true + } + } + }, + "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": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "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": { - "kind-of": "^3.0.2" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "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": { - "is-buffer": "^1.1.5" + "has-flag": "^3.0.0" } } } }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "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 - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", "dev": true, "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" } - } - } - }, - "webpack-cli": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.1.2.tgz", - "integrity": "sha512-Cnqo7CeqeSvC6PTdts+dywNi5CRlIPbLx1AoUPK2T6vC1YAugMG3IOoO9DmEscd+Dghw7uRlnzV1KwOe5IrtgQ==", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "enhanced-resolve": "^4.1.0", - "global-modules-path": "^2.3.0", - "import-local": "^2.0.0", - "interpret": "^1.1.0", - "loader-utils": "^1.1.0", - "supports-color": "^5.5.0", - "v8-compile-cache": "^2.0.2", - "yargs": "^12.0.2" - }, - "dependencies": { + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -8407,179 +9558,237 @@ "which": "^1.2.9" } }, - "decamelize": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-2.0.0.tgz", - "integrity": "sha512-Ikpp5scV3MSYxY39ymh45ZLEecsTdv/Xj2CaQfI8RLMuwi7XvjX9H/fhraiSuU+C5w5NTDu4ZU72xNiZnurBPg==", - "dev": true, - "requires": { - "xregexp": "4.0.0" - } - }, - "execa": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", - "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "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" - } - }, - "import-local": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", - "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", - "dev": true, - "requires": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" - } - }, - "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==", + "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 }, - "lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "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": { - "invert-kv": "^2.0.0" + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" } }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "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": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" } }, - "mem": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.0.0.tgz", - "integrity": "sha512-WQxG/5xYc3tMbYLXoXPm81ET2WDULiU5FxbuIoNbJqLOOI8zehXFdZuiUEgfdrU2mVB1pxBZUGlYORSrpuJreA==", + "yargs": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz", + "integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==", "dev": true, "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^1.0.0", - "p-is-promise": "^1.1.0" + "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" } }, - "os-locale": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.0.1.tgz", - "integrity": "sha512-7g5e7dmXPtzcP4bgsZ8ixDVqA7oWYuEz4lOSujeWyliPai4gfVDiFIcwBg3aGCPnmSGfzOKTK3ccPn0CKv3DBw==", + "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": { - "execa": "^0.10.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" + "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", + "integrity": "sha512-5MWu9SH1z3hY7oHOV6Kbkz5x7hXbxK56mGHNqHTe6d+ewxOwKUxoUJBs7QIaJb33lPjl9bJZ3X0vCoooUzC36A==", + "dev": true, + "requires": { + "memory-fs": "^0.4.1", + "mime": "^2.4.4", + "mkdirp": "^0.5.1", + "range-parser": "^1.2.1", + "webpack-log": "^2.0.0" + }, + "dependencies": { + "mime": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", + "dev": true + } + } + }, + "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==", + "dev": true, + "requires": { + "ansi-html": "0.0.7", + "bonjour": "^3.5.0", + "chokidar": "^2.1.8", + "compression": "^1.7.4", + "connect-history-api-fallback": "^1.6.0", + "debug": "^4.1.1", + "del": "^4.1.1", + "express": "^4.17.1", + "html-entities": "^1.2.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", + "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", + "semver": "^6.3.0", + "serve-index": "^1.9.1", + "sockjs": "0.3.19", + "sockjs-client": "1.4.0", + "spdy": "^4.0.1", + "strip-ansi": "^3.0.1", + "supports-color": "^6.1.0", + "url": "^0.11.0", + "webpack-dev-middleware": "^3.7.1", + "webpack-log": "^2.0.0", + "ws": "^6.2.1", + "yargs": "12.0.5" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true }, - "p-limit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", - "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", "dev": true, "requires": { - "p-try": "^2.0.0" + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" } }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { - "p-limit": "^2.0.0" + "ms": "^2.1.1" } }, - "p-try": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", - "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "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 }, - "pkg-dir": { + "normalize-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true }, - "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" - } + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true }, - "yargs": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.2.tgz", - "integrity": "sha512-e7SkEx6N6SIZ5c5H22RTZae61qtn3PYUE8JYbBFlK9sYmh3DMQ6E5ygtaG/2BW0JZi4WGgTR2IV5ChqlqrDGVQ==", + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "cliui": "^4.0.0", - "decamelize": "^2.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^10.1.0" + "ansi-regex": "^2.0.0" } }, - "yargs-parser": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", - "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", "dev": true, "requires": { - "camelcase": "^4.1.0" + "async-limiter": "~1.0.0" } } } }, + "webpack-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", + "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", + "dev": true, + "requires": { + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" + } + }, "webpack-sources": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.3.0.tgz", - "integrity": "sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", "dev": true, "requires": { "source-list-map": "^2.0.0", "source-map": "~0.6.1" } }, + "websocket-driver": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz", + "integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==", + "dev": true, + "requires": { + "http-parser-js": ">=0.4.0 <0.4.11", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", + "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", + "dev": true + }, "whatwg-encoding": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", @@ -8629,9 +9838,9 @@ "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" }, "worker-farm": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.6.0.tgz", - "integrity": "sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", "dev": true, "requires": { "errno": "~0.1.7" @@ -8647,6 +9856,12 @@ "strip-ansi": "^3.0.1" }, "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", @@ -8666,6 +9881,15 @@ "is-fullwidth-code-point": "^1.0.0", "strip-ansi": "^3.0.0" } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } } } }, @@ -8685,9 +9909,9 @@ } }, "write-file-atomic": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz", - "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", + "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", "dev": true, "requires": { "graceful-fs": "^4.1.11", @@ -8713,22 +9937,16 @@ "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz", "integrity": "sha1-1QH5ezvbQDr4757MIFcxh6rawOk=" }, - "xregexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.0.0.tgz", - "integrity": "sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg==", - "dev": true - }, "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "dev": true }, "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "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 }, "yallist": { @@ -8738,32 +9956,49 @@ "dev": true }, "yargs": { - "version": "11.1.0", - "resolved": "http://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", - "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", "dev": true, "requires": { "cliui": "^4.0.0", - "decamelize": "^1.1.1", - "find-up": "^2.1.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", + "os-locale": "^3.0.0", "require-directory": "^2.1.1", "require-main-filename": "^1.0.1", "set-blocking": "^2.0.0", "string-width": "^2.0.0", "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^9.0.2" + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" + }, + "dependencies": { + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + } } }, "yargs-parser": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", - "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", "dev": true, "requires": { - "camelcase": "^4.1.0" + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + } } } } diff --git a/package.json b/package.json index bbcce882..6c8fd6c1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "plannerjs", - "version": "0.0.3-alpha", + "version": "0.2.0", "description": "The JavaScript framework for journey planning.", "main": "lib/index.js", "license": "MIT", @@ -17,40 +17,53 @@ "test": "jest", "debug": "ndb node lib/demo.cli.js --debug", "build": "tsc", + "prepublish": "npm run build", "browser": "npm run webpack", "lint": "./node_modules/tslint/bin/tslint --project .", "webpack": "webpack --config webpack.config.js --mode=production", "webpack-stats": "npm run webpack -- --display-modules --json > stats.json", "typedoc": "typedoc --options typedoc.config.js", "doc-bundle": "npm run browser && cp dist/bundle.js docs/js/planner-latest.js && cp dist/bundle.js.map docs/js/bundle.js.map", - "doc": "npm run typedoc && npm run doc-bundle" + "doc": "npm run typedoc && npm run doc-bundle", + "start": "webpack-dev-server --open" }, "dependencies": { + "@types/concaveman": "^1.1.3", + "@types/node": "^12.7.8", "asynciterator": "^2.0.1", "asynciterator-promiseproxy": "^2.0.0", - "haversine": "^1.1.0", + "concaveman": "^1.1.1", + "cross-fetch": "^3.0.4", + "d3-delaunay": "^4.1.5", + "haversine": "^1.1.1", "inversify": "^5.0.1", "isomorphic-fetch": "^2.2.1", - "ldfetch": "^1.1.1-alpha", - "reflect-metadata": "^0.1.12", + "ldfetch": "^1.1.2", + "node-dijkstra": "^2.5.0", + "reflect-metadata": "^0.1.13", + "tiles-in-bbox": "^1.0.2", + "tinyqueue": "^2.0.2", "uritemplate": "^0.3.4" }, "pre-commit": [ "lint" ], "devDependencies": { - "@types/haversine": "^1.1.0", - "@types/jest": "^23.3.7", + "@types/haversine": "^1.1.4", + "@types/jest": "^23.3.14", "@types/rdf-js": "^1.0.1", - "jest": "^23.6.0", + "jest": "^24.9.0", "pre-commit": "^1.2.2", "prettier": "1.14.3", - "ts-jest": "^23.10.4", - "ts-loader": "^5.3.0", - "tslint": "^5.11.0", - "typedoc": "^0.14.2", - "typescript": "^3.3.3", - "webpack": "^4.25.1", - "webpack-cli": "^3.1.2" - } + "source-map-support": "^0.5.13", + "ts-jest": "^23.10.5", + "ts-loader": "^5.4.5", + "tslint": "^5.20.0", + "typedoc": "^0.15.0", + "typescript": "^3.6.3", + "webpack": "^4.41.0", + "webpack-cli": "^3.3.9", + "webpack-dev-server": "^3.8.1" + }, + "sideEffects": false } diff --git a/src/Context.ts b/src/Context.ts index 38a6a079..1eb31998 100644 --- a/src/Context.ts +++ b/src/Context.ts @@ -1,7 +1,4 @@ -// @ts-ignore -import { EventEmitter, Listener } from "events"; import { Container, injectable } from "inversify"; -import EventType from "./enums/EventType"; /** * The Context serves as event pass through and holder of the inversify container object. @@ -10,15 +7,9 @@ import EventType from "./enums/EventType"; * ´decorate(injectable(), EventEmitter)´ causes errors when running tests in Jest */ @injectable() -// @ts-ignore -export default class Context implements EventEmitter { - private emitter: EventEmitter; +export default class Context { private container: Container; - constructor() { - this.emitter = new EventEmitter(); - } - public setContainer(container: Container) { this.container = container; } @@ -26,56 +17,4 @@ export default class Context implements EventEmitter { public getContainer() { return this.container; } - - public addListener(type: string | symbol, listener: Listener): this { - this.emitter.addListener(type, listener); - - return this; - } - - public emit(type: string | symbol, ...args: any[]): boolean { - return this.emitter.emit(type, ...args); - } - - public emitWarning(...args: any[]): boolean { - return this.emit(EventType.Warning, ...args); - } - - public listenerCount(type: string | symbol): number { - return this.emitter.listenerCount(type); - } - - public listeners(type: string | symbol): Listener[] { - return this.emitter.listeners(type); - } - - public on(type: string | symbol, listener: Listener): this { - this.emitter.on(type, listener); - - return this; - } - - public once(type: string | symbol, listener: Listener): this { - this.emitter.once(type, listener); - - return this; - } - - public removeAllListeners(type?: string | symbol): this { - this.emitter.removeAllListeners(type); - - return this; - } - - public removeListener(type: string | symbol, listener: Listener): this { - this.emitter.removeListener(type, listener); - - return this; - } - - public setMaxListeners(n: number): this { - this.emitter.setMaxListeners(n); - - return this; - } } diff --git a/src/Planner.ts b/src/Planner.ts deleted file mode 100644 index f3cfaa36..00000000 --- a/src/Planner.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { AsyncIterator } from "asynciterator"; -import { PromiseProxyIterator } from "asynciterator-promiseproxy"; -// @ts-ignore -import { EventEmitter, Listener } from "events"; -import Context from "./Context"; -import EventType from "./enums/EventType"; -import IConnectionsProvider from "./fetcher/connections/IConnectionsProvider"; -import IStop from "./fetcher/stops/IStop"; -import IStopsProvider from "./fetcher/stops/IStopsProvider"; -import IPath from "./interfaces/IPath"; -import IQuery from "./interfaces/IQuery"; -import defaultContainer from "./inversify.config"; -import IQueryRunner from "./query-runner/IQueryRunner"; -import TYPES from "./types"; -import Units from "./util/Units"; - -/** - * Allows to ask route planning queries. Emits events defined in [[EventType]] - */ -// @ts-ignore -export default class Planner implements EventEmitter { - public static Units = Units; - - private context: Context; - private queryRunner: IQueryRunner; - - /** - * Initializes a new Planner - * @param container The container of dependencies we are working with - */ - constructor(container = defaultContainer) { - // Store container on context before doing anything else - this.context = container.get(TYPES.Context); - this.context.setContainer(container); - - this.queryRunner = container.get(TYPES.QueryRunner); - } - - /** - * Given an [[IQuery]], it will evaluate the query and return a promise for an AsyncIterator of [[IPath]] instances - * @param query An [[IQuery]] specifying a route planning query - * @returns An [[AsyncIterator]] of [[IPath]] instances - */ - public query(query: IQuery): AsyncIterator { - this.emit(EventType.Query, query); - - const iterator = new PromiseProxyIterator(() => this.queryRunner.run(query)); - - this.once(EventType.AbortQuery, () => { - iterator.close(); - }); - - iterator.on("error", (e) => { - if (e && e.eventType) { - this.emit(e.eventType, e.message); - } - }); - - return iterator; - } - - public addListener(type: string | symbol, listener: Listener): this { - this.context.addListener(type, listener); - - return this; - } - - public emit(type: string | symbol, ...args: any[]): boolean { - return this.context.emit(type, ...args); - } - - public listenerCount(type: string | symbol): number { - return this.context.listenerCount(type); - } - - public listeners(type: string | symbol): Listener[] { - return this.context.listeners(type); - } - - public on(type: string | symbol, listener: Listener): this { - this.context.on(type, listener); - - return this; - } - - public once(type: string | symbol, listener: Listener): this { - this.context.once(type, listener); - - return this; - } - - public removeAllListeners(type?: string | symbol): this { - this.context.removeAllListeners(type); - - return this; - } - - public removeListener(type: string | symbol, listener: Listener): this { - this.context.removeListener(type, listener); - - return this; - } - - public setMaxListeners(n: number): this { - this.context.setMaxListeners(n); - - return this; - } - - public prefetchStops(): void { - const container = this.context.getContainer(); - const stopsProvider = container.get(TYPES.StopsProvider); - - if (stopsProvider) { - stopsProvider.prefetchStops(); - } - } - - public prefetchConnections(): void { - const container = this.context.getContainer(); - const connectionsProvider = container.get(TYPES.ConnectionsProvider); - - if (connectionsProvider) { - connectionsProvider.prefetchConnections(); - } - } - - public getAllStops(): Promise { - const container = this.context.getContainer(); - const stopsProvider = container.get(TYPES.StopsProvider); - - if (stopsProvider) { - return stopsProvider.getAllStops(); - } - - return Promise.reject(); - } - -} diff --git a/src/analytics/footpaths/main.ts b/src/analytics/footpaths/main.ts new file mode 100644 index 00000000..a7181bfc --- /dev/null +++ b/src/analytics/footpaths/main.ts @@ -0,0 +1,135 @@ +import { AsyncIterator } from "asynciterator"; +import { Delaunay } from "d3-delaunay"; +import fs = require("fs"); +import "isomorphic-fetch"; +import "reflect-metadata"; + +import IStopsProvider from "../../fetcher/stops/IStopsProvider"; +import ILocation from "../../interfaces/ILocation"; +import IPath from "../../interfaces/IPath"; +import { DistanceM } from "../../interfaces/units"; +import defaultContainer from "../../inversify.config"; +import IRoadPlanner from "../../planner/road/IRoadPlanner"; +import TYPES from "../../types"; +import Geo from "../../util/Geo"; +import Iterators from "../../util/Iterators"; + +export default class FootpathGenerator { + public async generatePaths() { + const stopsProvider = defaultContainer.get(TYPES.StopsProvider); + const planner = defaultContainer.get(TYPES.RoadPlanner); + + const dict = await this.getPairs(stopsProvider); + const locations = Object.keys(dict).sort((a, b) => a > b ? -1 : 1); + + let done = 0; + + for (const fromId of locations) { + done += 1; + + let fileId = fromId.split("//")[1]; + fileId = fileId.replace(/\./g, "_"); + fileId = fileId.replace(/\//g, "_"); + const fileName = `distances/${fileId}.json`; + + if (fs.existsSync(fileName)) { + continue; + } + + if ((locations.length - done) % 10 === 0) { + console.log("To do:", locations.length - done); + } + + const footpathDistances = {}; + for (const toId of dict[fromId]) { + try { + const [to, from] = await Promise.all([ + stopsProvider.getStopById(fromId), + stopsProvider.getStopById(toId), + ]); + const query = { + profileID: "https://hdelva.be/profile/pedestrian", + from: [from], + to: [to], + minimumWalkingSpeed: 4.5, + maximumWalkingSpeed: 4.5, + }; + + const pathIterator = await planner.plan(query); + + const distanceIterator: AsyncIterator = pathIterator.map((path: IPath) => + path.legs.reduce((totalDistance: DistanceM, leg) => totalDistance + leg.getDistance(), 0), + ); + + const distances = await Iterators.toArray(distanceIterator); + if (distances.length) { + const shortest = Math.min(...distances); + if (shortest) { + footpathDistances[toId] = Math.round(shortest); + } + } + } catch (err) { + throw err; + console.log(err); + } + } + + await fs.writeFile(fileName, JSON.stringify(footpathDistances), "utf-8", (err) => { + if (err) { + throw err; + } + }); + } + } + + private async getPairs(stopsProvider) { + const stops = await stopsProvider.getAllStops(); + // using the WGS84 coordinates as-is + function getX(p: ILocation) { + return p.longitude; + } + + function getY(p: ILocation) { + return p.latitude; + } + + function nextHalfedge(e: number) { + // from https://mapbox.github.io/delaunator/ + return (e % 3 === 2) ? e - 2 : e + 1; + } + + const delaunay = Delaunay.from(stops, getX, getY); + let pairs = []; + for (let e = 0; e < delaunay.triangles.length; e++) { + if (e > delaunay.halfedges[e]) { + // this will create a single triangulation + // extra checks can be added here to calculate edges between different operators + const p = stops[delaunay.triangles[e]]; + const q = stops[delaunay.triangles[nextHalfedge(e)]]; + + pairs.push([p, q]); // in both directions of course + pairs.push([q, p]); + // todo, replace with yielding dicts instead of pairs + } + } + + // because of practical reasons, shortest distances require less data + pairs = pairs.sort((a, b) => Geo.getDistanceBetweenLocations(a[0], a[1]) - + Geo.getDistanceBetweenLocations(b[0], b[1])); + + pairs = pairs.filter((edge) => Geo.getDistanceBetweenLocations(edge[0], edge[1]) < 5000); + + // pairs = pairs.sort((a, b) => a[0].longitude - b[0].longitude); + + const dict = {}; + for (const [first, second] of pairs) { + if (first.id === "https://data.delijn.be/stops/201657") { + if (!dict[first.id]) { + dict[first.id] = []; + } + dict[first.id].push(second.id); + } + } + return dict; + } +} diff --git a/src/analytics/isochrones/demo.html b/src/analytics/isochrones/demo.html new file mode 100644 index 00000000..8448453f --- /dev/null +++ b/src/analytics/isochrones/demo.html @@ -0,0 +1,229 @@ + + + + + Isochrone demo + + + + + + + +

+
+

+

+ +

+

+ Latitude:
+
+ Longitude:
+

+ +

+

+ Time (s):
+

+ +

+
+
+
+ +
+
+ + + + + + \ No newline at end of file diff --git a/src/analytics/isochrones/img/circle.png b/src/analytics/isochrones/img/circle.png new file mode 100644 index 00000000..7c2064e8 Binary files /dev/null and b/src/analytics/isochrones/img/circle.png differ diff --git a/src/analytics/isochrones/main.ts b/src/analytics/isochrones/main.ts new file mode 100644 index 00000000..d9999d0e --- /dev/null +++ b/src/analytics/isochrones/main.ts @@ -0,0 +1,183 @@ +import { EventEmitter } from "events"; +import "isomorphic-fetch"; +import "reflect-metadata"; +import inBBox from "tiles-in-bbox"; +import Profile from "../../entities/profile/Profile"; +import { RoutableTileCoordinate } from "../../entities/tiles/coordinate"; +import RoutableTileRegistry from "../../entities/tiles/registry"; +import RoutingPhase from "../../enums/RoutingPhase"; +import EventBus from "../../events/EventBus"; +import EventType from "../../events/EventType"; +import ProfileProvider from "../../fetcher/profiles/ProfileProviderDefault"; +import IRoutableTileProvider from "../../fetcher/tiles/IRoutableTileProvider"; +import ILocation from "../../interfaces/ILocation"; +import defaultContainer from "../../inversify.config"; +import { IPathTree } from "../../pathfinding/pathfinder"; +import PathfinderProvider from "../../pathfinding/PathfinderProvider"; +import TYPES from "../../types"; +import Geo from "../../util/Geo"; +import { toTileCoordinate } from "../../util/Tiles"; +import { visualizeConcaveIsochrone, visualizeIsochrone } from "./visualize"; + +export default class IsochroneGenerator { + private pathfinderProvider: PathfinderProvider; + private tileProvider: IRoutableTileProvider; + private reachedTiles: Set; + private startPoint: ILocation; + private registry: RoutableTileRegistry; + private profileProvider: ProfileProvider; + private eventBus: EventEmitter; + + private activeProfile: Promise; + private loaded: Promise; + private embedded: boolean; + private showIncremental: boolean; + private showDebugLogs: boolean; + + constructor(point: ILocation, container = defaultContainer) { + this.tileProvider = container.getTagged( + TYPES.RoutableTileProvider, + "phase", + RoutingPhase.Base, + ); + this.pathfinderProvider = container.get(TYPES.PathfinderProvider); + this.registry = container.get(TYPES.RoutableTileRegistry); + this.profileProvider = container.get(TYPES.ProfileProvider); + this.eventBus = EventBus.getInstance(); + this.reachedTiles = new Set(); + this.startPoint = point; + this.showIncremental = false; + this.showDebugLogs = false; + this.embedded = false; + + this.setProfileID("http://hdelva.be/profile/car"); + } + + public enableIncrementalResults() { + this.showIncremental = true; + } + + public enableDebugLogs() { + this.showDebugLogs = true; + } + + public async setDevelopmentProfile(blob: object) { + const id = await this.profileProvider.parseDevelopmentProfile(blob); + this.setProfileID(id); + } + + public async setProfileID(profileID: string) { + this.activeProfile = this.profileProvider.getProfile(profileID); + this.embedded = false; + } + + public async getIsochrone(maxDuration: number, reset = true) { + if (this.showDebugLogs) { + console.time(Geo.getId(this.startPoint)); + console.log(`Generating the ${maxDuration / 1000}s isochrone ` + + `from ${this.startPoint.latitude}, ${this.startPoint.longitude}`); + } + + if (!this.embedded) { + await this.embedBeginPoint(this.startPoint); + this.embedded = true; + } + + await this.loaded; + const profile = await this.activeProfile; + + if (this.showDebugLogs) { + console.log(`Using the ${profile.getID()} profile`); + } + + const pathfinder = this.pathfinderProvider.getShortestPathTreeAlgorithm(profile); + + // wait for all data to arrive + await this.tileProvider.wait(); + + let pathTree: IPathTree; + pathfinder.setUseWeightedCost(false); // we want the raw durations + if (reset) { + pathTree = await pathfinder.start(Geo.getId(this.startPoint), maxDuration); + } else { + pathTree = await pathfinder.continue(maxDuration); + } + + if (this.showDebugLogs) { + console.log(`Path tree computed using ${this.reachedTiles.size} tiles.`); + console.timeEnd(Geo.getId(this.startPoint)); + console.time(Geo.getId(this.startPoint)); + } + + const result = await visualizeConcaveIsochrone(pathTree, maxDuration, this.registry); + + if (this.showDebugLogs) { + console.timeEnd(Geo.getId(this.startPoint)); + } + + return result; + } + + private async fetchTile(coordinate: RoutableTileCoordinate) { + const tileId = this.tileProvider.getIdForTileCoords(coordinate); + if (!this.reachedTiles.has(tileId)) { + this.eventBus.emit(EventType.FetchTile, coordinate); + + const profile = await this.activeProfile; + const pathfinder = this.pathfinderProvider.getShortestPathTreeAlgorithm(profile); + const tile = await this.tileProvider.getByTileCoords(coordinate); + this.reachedTiles.add(tileId); + const boundaryNodes: Set = new Set(); + + for (const nodeId of tile.getNodes()) { + pathfinder.removeBreakPoint(nodeId); + const node = this.registry.getNode(nodeId); + if (!tile.contains(node)) { + boundaryNodes.add(nodeId); + } + + if (this.showIncremental) { + pathfinder.setBreakPoint(nodeId, async (on: string) => { + const innerNode = self.registry.getNode(on); + if (innerNode) { + self.eventBus.emit(EventType.PointReached, innerNode); + } + }); + } + } + + const self = this; + for (const nodeId of boundaryNodes) { + const node = self.registry.getNode(nodeId); + const boundaryTileCoordinate = toTileCoordinate(node.latitude, node.longitude); + + pathfinder.setBreakPoint(nodeId, async (on: string) => { + await self.fetchTile(boundaryTileCoordinate); + }); + } + } + } + + private async embedBeginPoint(from: ILocation) { + const zoom = 14; + const padding = 0.005; + + const fromBBox = { + top: from.latitude + padding, + bottom: from.latitude - padding, + left: from.longitude - padding, + right: from.longitude + padding, + }; + + const fromTileCoords = inBBox.tilesInBbox(fromBBox, zoom).map((obj) => { + const coordinate = new RoutableTileCoordinate(zoom, obj.x, obj.y); + this.fetchTile(coordinate); + return coordinate; + }); + + // this won't download anything new + // but we need the tile data to embed the starting location + const fromTileset = await this.tileProvider.getMultipleByTileCoords(fromTileCoords); + await this.pathfinderProvider.embedLocation(from, fromTileset); + } +} diff --git a/src/analytics/isochrones/util.ts b/src/analytics/isochrones/util.ts new file mode 100644 index 00000000..e27a2a57 --- /dev/null +++ b/src/analytics/isochrones/util.ts @@ -0,0 +1,31 @@ +import { RoutableTileCoordinate } from "../../entities/tiles/coordinate"; + +export function edgesOfTriangle(t) { + // from https://mapbox.github.io/delaunator + return [3 * t, 3 * t + 1, 3 * t + 2]; +} + +export function pointsOfTriangle(delaunay, t) { + // from https://mapbox.github.io/delaunator + return edgesOfTriangle(t) + .map((e) => delaunay.triangles[e]); +} + +export function getNeighborTiles(coordinate: RoutableTileCoordinate): RoutableTileCoordinate[] { + const result = []; + + for (const xDelta of [-1, 0, 1]) { + for (const yDelta of [-1, 0, 1]) { + if (xDelta || yDelta) { + const neighbor = { + zoom: coordinate.zoom, + y: coordinate.y + yDelta, + x: coordinate.x + xDelta, + }; + result.push(neighbor); + } + } + } + + return result; +} diff --git a/src/analytics/isochrones/visualize.ts b/src/analytics/isochrones/visualize.ts new file mode 100644 index 00000000..9d4eda28 --- /dev/null +++ b/src/analytics/isochrones/visualize.ts @@ -0,0 +1,222 @@ +import concaveman = require("concaveman"); +import { Delaunay } from "d3-delaunay"; +import { RoutableTileNode } from "../../entities/tiles/node"; +import RoutableTileRegistry from "../../entities/tiles/registry"; +import ILocation from "../../interfaces/ILocation"; +import { IPathTree } from "../../pathfinding/pathfinder"; +import ILocationResolver from "../../query-runner/ILocationResolver"; +import Geo from "../../util/Geo"; +import UnionFind from "../../util/UnionFind"; +import { pointsOfTriangle } from "./util"; + +// we make extensive use of the Delaunator library which uses indexes for everything +// we'll need this to get the corresponding RoutableTileNode for a given index +type NodeList = RoutableTileNode[]; + +// a list of boolean values, indicating whether or not the node with a given index has a specific label +type NodeLabelList = boolean[]; + +// A cluster of routable tile nodes +type NodeCluster = Set; + +// A ring is a list of connected geographical points. +type Ring = ILocation[]; + +// A polygon is represented as a list of rings. +// The first being the outer ring, the others being holes. +type Polygon = Ring[]; + +export async function visualizeConcaveIsochrone( + pathTree: IPathTree, + maxCost: number, + registry: RoutableTileRegistry, +) { + const locations = []; + for (const node of registry.getNodes()) { + const branch = pathTree[node.id]; + if (branch) { + const { duration } = branch; + if (duration < maxCost) { + locations.push([node.longitude, node.latitude]); + } + } + } + + let isochrones = []; + if (locations.length > 0) { + const shell = concaveman(locations, 2); + isochrones = [[shell.map((point) => { + return { longitude: point[0], latitude: point[1] }; + })]]; + } + + return { + isochrones, + }; +} + +export function visualizeIsochrone(registry: RoutableTileRegistry, pathTree: IPathTree, maxCost: number) { + /** + * Isochrones are generated by applying a delaunay triangulisation to the road network nodes, + * Union-Find (= disjoint set) is used to find clusters of external/internal nodes. + * Each cluster will form one ring in the isochrone. + */ + + const nodes: NodeList = []; + const costs = {}; + for (const [id, branch] of Object.entries(pathTree)) { + const { duration } = branch; + const node = registry.getNode(id); + if (node && duration !== Infinity) { + nodes.push(node); + costs[node.id] = duration; + } + } + + nodes.push({ latitude: 90, longitude: 180, id: "1" }); + nodes.push({ latitude: -90, longitude: 180, id: "2" }); + nodes.push({ latitude: 90, longitude: -180, id: "3" }); + nodes.push({ latitude: -90, longitude: -180, id: "4" }); + + costs["1"] = Infinity; + costs["2"] = Infinity; + costs["3"] = Infinity; + costs["4"] = Infinity; + + const delaunay = createTriangulation(nodes); + const internalNodes: NodeLabelList = nodes.map((node) => costs[node.id] < maxCost); + const externalNodes: NodeLabelList = internalNodes.map((v) => !v); + + const internalClusters = clusterNodes(nodes, internalNodes, delaunay); + const externalClusters = clusterNodes(nodes, externalNodes, delaunay); + + const polygons: Polygon[] = internalClusters + .filter((cluster) => cluster.size > 1) + .map((internalCluster) => + createPolygon(costs, maxCost, nodes, internalCluster, externalClusters, delaunay), + ); + + return { + isochrones: polygons.filter((p) => p.length > 0), + }; +} + +function createTriangulation(nodes: ILocation[]): Delaunay { + function getX(p: ILocation) { + return p.longitude; + } + + function getY(p: ILocation) { + return p.latitude; + } + + return Delaunay.from(nodes, getX, getY); +} + +function clusterNodes(allNodes: NodeList, relevantNodes: NodeLabelList, delaunay: Delaunay): NodeCluster[] { + /** + * Uses Union-Find to cluster the given (relevant) nodes based on the Delaunay triangulisation of all nodes. + * Returns an array of clusters. + */ + const forest = new UnionFind(allNodes.length); + + for (const nodeIndex of Array(allNodes.length).keys()) { + if (relevantNodes[nodeIndex]) { + const neighbors = delaunay.neighbors(nodeIndex); + for (const neighbor of neighbors) { + if (relevantNodes[neighbor]) { + forest.union(nodeIndex, neighbor); + } + } + } + } + + const clusters = forest.getClusters(); + + for (const key of Object.keys(clusters)) { + if (!relevantNodes[key]) { + delete clusters[key]; + } + } + + return Object.values(clusters); +} + +function createPolygon( + costs, + maxCost: number, + nodes: NodeList, + internalNodes: NodeCluster, + externalClusters: NodeCluster[], + delaunay: Delaunay, +): Polygon { + /** + * Creates a polygon for the given cluster of nodes that lie in an isochrone. + */ + const rings = []; + + // each cluster of external nodes yields a single ring. + // there's exactly one on the outside of the internal nodes cluster (because union-find) + // the others will form holes + for (const externalNodes of externalClusters) { + const borderLocations: ILocation[] = []; + const borderNodeIds = new Set(); + for (const nodeIndex of Array(nodes.length).keys()) { + if (!externalNodes.has(nodeIndex) && internalNodes.has(nodeIndex)) { + for (const neighbor of delaunay.neighbors(nodeIndex)) { + if (externalNodes.has(neighbor)) { + const point = pointBetween(nodes[nodeIndex], nodes[neighbor], costs, maxCost); + if (point) { + borderLocations.push(point); + } + } + } + } + } + + if (borderLocations.length > 0) { + const triangulation = createTriangulation(borderLocations); + const firstNode = triangulation.hull; + const ring = [borderLocations[firstNode.i]]; + let currentNode = firstNode.next; + while (currentNode.i !== firstNode.i) { + ring.push(borderLocations[currentNode.i]); + currentNode = currentNode.next; + } + rings.push(ring); + } + } + + // FIXME, the ring with the most nodes might not always be the outer ring + return rings + .filter((r) => r.length > 0) + .sort((a, b) => b.length - a.length); +} + +function pointBetween(node1: RoutableTileNode, node2: RoutableTileNode, costs, maxCost): ILocation { + const nodeCost1 = costs[node1.id]; + const nodeCost2 = costs[node2.id]; + + if (nodeCost1 === Infinity && nodeCost2 === Infinity) { + return null; + } else if (nodeCost1 === Infinity) { + return node2; + } else if (nodeCost2 === Infinity) { + return node1; + } + + const costDifference1 = Math.abs(nodeCost1 - maxCost); + const costDifference2 = Math.abs(nodeCost2 - maxCost); + const relDifference1 = 1 - costDifference1 / (costDifference1 + costDifference2); + const relDifference2 = 1 - costDifference2 / (costDifference1 + costDifference2); + + const weight = relDifference1 + relDifference2; + const latitude = (node1.latitude * relDifference1 + node2.latitude * relDifference2) / weight; + const longitude = (node1.longitude * relDifference1 + node2.longitude * relDifference2) / weight; + + if (isNaN(latitude) || isNaN(longitude)) { + return null; + } + + return { latitude, longitude }; +} diff --git a/src/catalog.delijn.oostvlaanderen.ts b/src/catalog.delijn.oostvlaanderen.ts new file mode 100644 index 00000000..391af230 --- /dev/null +++ b/src/catalog.delijn.oostvlaanderen.ts @@ -0,0 +1,16 @@ +import Catalog from "./Catalog"; +import TravelMode from "./enums/TravelMode"; + +/* tslint:disable:max-line-length */ + +const catalogDeLijn = new Catalog(); + +catalogDeLijn.addStopsSource("https://openplanner.ilabt.imec.be/delijn/Antwerpen/stops"); +catalogDeLijn.addStopsSource("https://openplanner.ilabt.imec.be/delijn/Limburg/stops"); +catalogDeLijn.addStopsSource("https://openplanner.ilabt.imec.be/delijn/Oost-Vlaanderen/stops"); +catalogDeLijn.addStopsSource("https://openplanner.ilabt.imec.be/delijn/Vlaams-Brabant/stops"); +catalogDeLijn.addStopsSource("https://openplanner.ilabt.imec.be/delijn/West-Vlaanderen/stops"); + +catalogDeLijn.addConnectionsSource("https://openplanner.ilabt.imec.be/delijn/Oost-Vlaanderen/connections", TravelMode.Bus); + +export default catalogDeLijn; diff --git a/src/catalog.delijn.vlaenderen.ts b/src/catalog.delijn.vlaenderen.ts new file mode 100644 index 00000000..0139a6d0 --- /dev/null +++ b/src/catalog.delijn.vlaenderen.ts @@ -0,0 +1,17 @@ +import Catalog from "./Catalog"; +import TravelMode from "./enums/TravelMode"; + +/* tslint:disable:max-line-length */ + +const catalogDeLijn = new Catalog(); + +catalogDeLijn.addStopsSource("https://openplanner.ilabt.imec.be/delijn/Antwerpen/stops"); +catalogDeLijn.addStopsSource("https://openplanner.ilabt.imec.be/delijn/Limburg/stops"); +catalogDeLijn.addStopsSource("https://openplanner.ilabt.imec.be/delijn/Oost-Vlaanderen/stops"); +catalogDeLijn.addStopsSource("https://openplanner.ilabt.imec.be/delijn/Vlaams-Brabant/stops"); +catalogDeLijn.addStopsSource("https://openplanner.ilabt.imec.be/delijn/West-Vlaanderen/stops"); + +catalogDeLijn.addConnectionsSource("https://openplanner.ilabt.imec.be/delijn/Oost-Vlaanderen/connections", TravelMode.Bus); +catalogDeLijn.addConnectionsSource("https://openplanner.ilabt.imec.be/delijn/West-Vlaanderen/connections", TravelMode.Bus); + +export default catalogDeLijn; diff --git a/src/catalog.mivb.ts b/src/catalog.mivb.ts new file mode 100644 index 00000000..9cfcdf50 --- /dev/null +++ b/src/catalog.mivb.ts @@ -0,0 +1,9 @@ +import Catalog from "./Catalog"; +import TravelMode from "./enums/TravelMode"; + +const catalogMivb = new Catalog(); + +catalogMivb.addStopsSource("https://openplanner.ilabt.imec.be/mivb/stops"); +catalogMivb.addConnectionsSource("https://openplanner.ilabt.imec.be/mivb/connections", TravelMode.Bus); + +export default catalogMivb; diff --git a/src/catalog.tec.ts b/src/catalog.tec.ts new file mode 100644 index 00000000..3e30627a --- /dev/null +++ b/src/catalog.tec.ts @@ -0,0 +1,8 @@ +import Catalog from "./Catalog"; +import TravelMode from "./enums/TravelMode"; + +const catalogTec = new Catalog(); + +catalogTec.addStopsSource("https://openplanner.ilabt.imec.be/tec/stops"); + +export default catalogTec; diff --git a/src/configs/basic_train.ts b/src/configs/basic_train.ts new file mode 100644 index 00000000..97d82ac0 --- /dev/null +++ b/src/configs/basic_train.ts @@ -0,0 +1,119 @@ +import { Container, interfaces } from "inversify"; +import Catalog from "../Catalog"; +import catalogNmbs from "../catalog.nmbs"; +import Context from "../Context"; +import RoutableTileRegistry from "../entities/tiles/registry"; +import ReachableStopsSearchPhase from "../enums/ReachableStopsSearchPhase"; +import RoutingPhase from "../enums/RoutingPhase"; +import TravelMode from "../enums/TravelMode"; +import ConnectionsFetcherRaw from "../fetcher/connections/ConnectionsFetcherRaw"; +import ConnectionsProviderDefault from "../fetcher/connections/ConnectionsProviderDefault"; +import IConnectionsFetcher from "../fetcher/connections/IConnectionsFetcher"; +import IConnectionsProvider from "../fetcher/connections/IConnectionsProvider"; +import LDFetch from "../fetcher/LDFetch"; +import IProfileFetcher from "../fetcher/profiles/IProfileFetcher"; +import IProfileProvider from "../fetcher/profiles/IProfileProvider"; +import ProfileFetcherDefault from "../fetcher/profiles/ProfileFetcherDefault"; +import ProfileProviderDefault from "../fetcher/profiles/ProfileProviderDefault"; +import IStopsFetcher from "../fetcher/stops/IStopsFetcher"; +import IStopsProvider from "../fetcher/stops/IStopsProvider"; +import StopsFetcherRaw from "../fetcher/stops/StopsFetcherRaw"; +import StopsProviderDefault from "../fetcher/stops/StopsProviderDefault"; +import IRoutableTileFetcher from "../fetcher/tiles/IRoutableTileFetcher"; +import IRoutableTileProvider from "../fetcher/tiles/IRoutableTileProvider"; +import RoutableTileFetcherRaw from "../fetcher/tiles/RoutableTileFetcherRaw"; +import RoutableTileProviderDefault from "../fetcher/tiles/RoutableTileProviderDefault"; +import RoutableTileProviderTransit from "../fetcher/tiles/RoutableTileProviderTransit"; + +import { LDLoader } from "../loader/ldloader"; +import { BidirDijkstra } from "../pathfinding/bidirdijkstra/BidirDijkstra"; +import DijkstraTree from "../pathfinding/dijkstra-tree/DijkstraTree"; +import { IShortestPathAlgorithm, IShortestPathTreeAlgorithm } from "../pathfinding/pathfinder"; +import PathfinderProvider from "../pathfinding/PathfinderProvider"; +import CSAEarliestArrival from "../planner/public-transport/CSAEarliestArrival"; +import IJourneyExtractor from "../planner/public-transport/IJourneyExtractor"; +import IPublicTransportPlanner from "../planner/public-transport/IPublicTransportPlanner"; +import JourneyExtractorProfile from "../planner/public-transport/JourneyExtractorProfile"; +import IRoadPlanner from "../planner/road/IRoadPlanner"; +import RoadPlannerPathfinding from "../planner/road/RoadPlannerPathfinding"; +import IReachableStopsFinder from "../planner/stops/IReachableStopsFinder"; +import ReachableStopsFinderDelaunay from "../planner/stops/ReachableStopsFinderDelaunay"; +import ReachableStopsFinderOnlySelf from "../planner/stops/ReachableStopsFinderOnlySelf"; +import ILocationResolver from "../query-runner/ILocationResolver"; +import IQueryRunner from "../query-runner/IQueryRunner"; +import LocationResolverConvenience from "../query-runner/LocationResolverConvenience"; +import QueryRunnerDefault from "../query-runner/QueryRunnerDefault"; +import TYPES from "../types"; + +const container = new Container(); +container.bind(TYPES.Context).to(Context).inSingletonScope(); +container.bind(TYPES.QueryRunner).to(QueryRunnerDefault); +container.bind(TYPES.LocationResolver).to(LocationResolverConvenience); + +// TODO, make this a fixed property of the planner itself +container.bind(TYPES.JourneyExtractor) + .to(JourneyExtractorProfile); + +container.bind(TYPES.PublicTransportPlanner) + .to(CSAEarliestArrival); +container.bind>(TYPES.PublicTransportPlannerFactory) + .toAutoFactory(TYPES.PublicTransportPlanner); + +container.bind(TYPES.RoadPlanner) + .to(RoadPlannerPathfinding); + +container.bind(TYPES.ShortestPathTreeAlgorithm).to(DijkstraTree).inSingletonScope(); +container.bind(TYPES.ShortestPathAlgorithm).to(BidirDijkstra).inSingletonScope(); +container.bind(TYPES.PathfinderProvider).to(PathfinderProvider).inSingletonScope(); +container.bind(TYPES.ProfileFetcher).to(ProfileFetcherDefault).inSingletonScope(); +container.bind(TYPES.ProfileProvider).to(ProfileProviderDefault).inSingletonScope(); + +container.bind(TYPES.ReachableStopsFinder) + .to(ReachableStopsFinderDelaunay).whenTargetTagged("phase", ReachableStopsSearchPhase.Initial); +container.bind(TYPES.ReachableStopsFinder) + .to(ReachableStopsFinderOnlySelf).whenTargetTagged("phase", ReachableStopsSearchPhase.Transfer); +container.bind(TYPES.ReachableStopsFinder) + .to(ReachableStopsFinderDelaunay).whenTargetTagged("phase", ReachableStopsSearchPhase.Final); + +container.bind(TYPES.ConnectionsProvider).to(ConnectionsProviderDefault).inSingletonScope(); +container.bind(TYPES.ConnectionsFetcher).to(ConnectionsFetcherRaw); +container.bind>(TYPES.ConnectionsFetcherFactory) + .toFactory( + (context: interfaces.Context) => + (travelMode: TravelMode) => { + const fetcher = context.container.get(TYPES.ConnectionsFetcher); + + fetcher.setTravelMode(travelMode); + + return fetcher; + }, + ); + +container.bind(TYPES.StopsProvider).to(StopsProviderDefault).inSingletonScope(); +container.bind(TYPES.StopsFetcher).to(StopsFetcherRaw); +container.bind>(TYPES.StopsFetcherFactory) + .toFactory( + (context: interfaces.Context) => + (accessUrl: string) => { + const fetcher = context.container.get(TYPES.StopsFetcher); + fetcher.setAccessUrl(accessUrl); + return fetcher; + }, + ); + +container.bind(TYPES.RoutableTileRegistry).to(RoutableTileRegistry).inSingletonScope(); +container.bind(TYPES.RoutableTileFetcher).to(RoutableTileFetcherRaw).inSingletonScope(); +container.bind(TYPES.RoutableTileProvider) + .to(RoutableTileProviderDefault).inSingletonScope().whenTargetTagged("phase", RoutingPhase.Base); +container.bind(TYPES.RoutableTileProvider) + .to(RoutableTileProviderTransit).inSingletonScope().whenTargetTagged("phase", RoutingPhase.Transit); + +// Bind catalog +container.bind(TYPES.Catalog).toConstantValue(catalogNmbs); + +// Init LDFetch +container.bind(TYPES.LDFetch).to(LDFetch).inSingletonScope(); + +container.bind(TYPES.LDLoader).to(LDLoader); + +export default container; diff --git a/src/configs/dissect.ts b/src/configs/dissect.ts new file mode 100644 index 00000000..4ccdca71 --- /dev/null +++ b/src/configs/dissect.ts @@ -0,0 +1,126 @@ +import { Container, interfaces } from "inversify"; +import Catalog from "../Catalog"; +import catalogOVl from "../catalog.delijn.oostvlaanderen"; +import catalogMivb from "../catalog.mivb"; +import catalogNmbs from "../catalog.nmbs"; +import Context from "../Context"; +import RoutableTileRegistry from "../entities/tiles/registry"; +import ReachableStopsSearchPhase from "../enums/ReachableStopsSearchPhase"; +import RoutingPhase from "../enums/RoutingPhase"; +import TravelMode from "../enums/TravelMode"; +import ConnectionsFetcherRaw from "../fetcher/connections/ConnectionsFetcherRaw"; +import ConnectionsProviderMerge from "../fetcher/connections/ConnectionsProviderMerge"; +import IConnectionsFetcher from "../fetcher/connections/IConnectionsFetcher"; +import IConnectionsProvider from "../fetcher/connections/IConnectionsProvider"; +import FootpathsProviderRaw from "../fetcher/footpaths/FootpathsProviderRaw"; +import IFootpathsFetcher from "../fetcher/footpaths/IFootpathsProvider"; +import LDFetch from "../fetcher/LDFetch"; +import IProfileFetcher from "../fetcher/profiles/IProfileFetcher"; +import IProfileProvider from "../fetcher/profiles/IProfileProvider"; +import ProfileFetcherDefault from "../fetcher/profiles/ProfileFetcherDefault"; +import ProfileProviderDefault from "../fetcher/profiles/ProfileProviderDefault"; +import IStopsFetcher from "../fetcher/stops/IStopsFetcher"; +import IStopsProvider from "../fetcher/stops/IStopsProvider"; +import StopsFetcherRaw from "../fetcher/stops/StopsFetcherRaw"; +import StopsProviderDefault from "../fetcher/stops/StopsProviderDefault"; +import IRoutableTileFetcher from "../fetcher/tiles/IRoutableTileFetcher"; +import IRoutableTileProvider from "../fetcher/tiles/IRoutableTileProvider"; +import RoutableTileFetcherRaw from "../fetcher/tiles/RoutableTileFetcherRaw"; +import RoutableTileProviderDefault from "../fetcher/tiles/RoutableTileProviderDefault"; +import RoutableTileProviderTransit from "../fetcher/tiles/RoutableTileProviderTransit"; + +import { LDLoader } from "../loader/ldloader"; +import { BidirDijkstra } from "../pathfinding/bidirdijkstra/BidirDijkstra"; +import DijkstraTree from "../pathfinding/dijkstra-tree/DijkstraTree"; +import { IShortestPathAlgorithm, IShortestPathTreeAlgorithm } from "../pathfinding/pathfinder"; +import PathfinderProvider from "../pathfinding/PathfinderProvider"; +import CSAEarliestArrival from "../planner/public-transport/CSAEarliestArrival"; +import IJourneyExtractor from "../planner/public-transport/IJourneyExtractor"; +import IPublicTransportPlanner from "../planner/public-transport/IPublicTransportPlanner"; +import JourneyExtractorProfile from "../planner/public-transport/JourneyExtractorProfile"; +import IRoadPlanner from "../planner/road/IRoadPlanner"; +import RoadPlannerPathfinding from "../planner/road/RoadPlannerPathfinding"; +import IReachableStopsFinder from "../planner/stops/IReachableStopsFinder"; +import ReachableStopsFinderDelaunay from "../planner/stops/ReachableStopsFinderDelaunay"; +import ReachableStopsFinderFootpaths from "../planner/stops/ReachableStopsFinderFootpaths"; +import ILocationResolver from "../query-runner/ILocationResolver"; +import IQueryRunner from "../query-runner/IQueryRunner"; +import LocationResolverConvenience from "../query-runner/LocationResolverConvenience"; +import QueryRunnerDefault from "../query-runner/QueryRunnerDefault"; +import TYPES from "../types"; + +const container = new Container(); +container.bind(TYPES.Context).to(Context).inSingletonScope(); +container.bind(TYPES.QueryRunner).to(QueryRunnerDefault); +container.bind(TYPES.LocationResolver).to(LocationResolverConvenience); + +// TODO, make this a fixed property of the planner itself +container.bind(TYPES.JourneyExtractor) + .to(JourneyExtractorProfile); + +container.bind(TYPES.PublicTransportPlanner) + .to(CSAEarliestArrival); +container.bind>(TYPES.PublicTransportPlannerFactory) + .toAutoFactory(TYPES.PublicTransportPlanner); + +container.bind(TYPES.RoadPlanner) + .to(RoadPlannerPathfinding); + +container.bind(TYPES.ShortestPathTreeAlgorithm).to(DijkstraTree).inSingletonScope(); +container.bind(TYPES.ShortestPathAlgorithm).to(BidirDijkstra).inSingletonScope(); +container.bind(TYPES.PathfinderProvider).to(PathfinderProvider).inSingletonScope(); +container.bind(TYPES.ProfileFetcher).to(ProfileFetcherDefault).inSingletonScope(); +container.bind(TYPES.ProfileProvider).to(ProfileProviderDefault).inSingletonScope(); + +container.bind(TYPES.FootpathsProvider).to(FootpathsProviderRaw).inSingletonScope(); + +container.bind(TYPES.ReachableStopsFinder) + .to(ReachableStopsFinderDelaunay).whenTargetTagged("phase", ReachableStopsSearchPhase.Initial); +container.bind(TYPES.ReachableStopsFinder) + .to(ReachableStopsFinderFootpaths).whenTargetTagged("phase", ReachableStopsSearchPhase.Transfer); +container.bind(TYPES.ReachableStopsFinder) + .to(ReachableStopsFinderDelaunay).whenTargetTagged("phase", ReachableStopsSearchPhase.Final); + +container.bind(TYPES.ConnectionsProvider).to(ConnectionsProviderMerge).inSingletonScope(); +container.bind(TYPES.ConnectionsFetcher).to(ConnectionsFetcherRaw); +container.bind>(TYPES.ConnectionsFetcherFactory) + .toFactory( + (context: interfaces.Context) => + (accessUrl: string, travelMode: TravelMode) => { + const fetcher = context.container.get(TYPES.ConnectionsFetcher); + + fetcher.setTravelMode(travelMode); + + return fetcher; + }, + ); + +container.bind(TYPES.StopsProvider).to(StopsProviderDefault).inSingletonScope(); +container.bind(TYPES.StopsFetcher).to(StopsFetcherRaw); +container.bind>(TYPES.StopsFetcherFactory) + .toFactory( + (context: interfaces.Context) => + (accessUrl: string) => { + const fetcher = context.container.get(TYPES.StopsFetcher); + fetcher.setAccessUrl(accessUrl); + return fetcher; + }, + ); + +container.bind(TYPES.RoutableTileRegistry).to(RoutableTileRegistry).inSingletonScope(); +container.bind(TYPES.RoutableTileFetcher).to(RoutableTileFetcherRaw).inSingletonScope(); +container.bind(TYPES.RoutableTileProvider) + .to(RoutableTileProviderDefault).inSingletonScope().whenTargetTagged("phase", RoutingPhase.Base); +container.bind(TYPES.RoutableTileProvider) + .to(RoutableTileProviderTransit).inSingletonScope().whenTargetTagged("phase", RoutingPhase.Transit); + +// Bind catalog +const combined = Catalog.combine(catalogMivb, catalogNmbs, catalogOVl); +container.bind(TYPES.Catalog).toConstantValue(combined); + +// Init LDFetch +container.bind(TYPES.LDFetch).to(LDFetch).inSingletonScope(); + +container.bind(TYPES.LDLoader).to(LDLoader); + +export default container; diff --git a/src/configs/transit_car.ts b/src/configs/transit_car.ts new file mode 100644 index 00000000..3b4a660a --- /dev/null +++ b/src/configs/transit_car.ts @@ -0,0 +1,123 @@ +import { Container, interfaces } from "inversify"; +import Catalog from "../Catalog"; +import catalogNmbs from "../catalog.nmbs"; +import Context from "../Context"; +import RoutableTileRegistry from "../entities/tiles/registry"; +import ReachableStopsSearchPhase from "../enums/ReachableStopsSearchPhase"; +import RoutingPhase from "../enums/RoutingPhase"; +import TravelMode from "../enums/TravelMode"; +import ConnectionsFetcherRaw from "../fetcher/connections/ConnectionsFetcherRaw"; +import ConnectionsProviderDefault from "../fetcher/connections/ConnectionsProviderDefault"; +import IConnectionsFetcher from "../fetcher/connections/IConnectionsFetcher"; +import IConnectionsProvider from "../fetcher/connections/IConnectionsProvider"; +import FootpathsProviderDefault from "../fetcher/footpaths/FootpathsProviderDefault"; +import IFootpathsFetcher from "../fetcher/footpaths/IFootpathsProvider"; +import LDFetch from "../fetcher/LDFetch"; +import IProfileFetcher from "../fetcher/profiles/IProfileFetcher"; +import IProfileProvider from "../fetcher/profiles/IProfileProvider"; +import ProfileFetcherDefault from "../fetcher/profiles/ProfileFetcherDefault"; +import ProfileProviderDefault from "../fetcher/profiles/ProfileProviderDefault"; +import IStopsFetcher from "../fetcher/stops/IStopsFetcher"; +import IStopsProvider from "../fetcher/stops/IStopsProvider"; +import StopsFetcherRaw from "../fetcher/stops/StopsFetcherRaw"; +import StopsProviderDefault from "../fetcher/stops/StopsProviderDefault"; +import IRoutableTileFetcher from "../fetcher/tiles/IRoutableTileFetcher"; +import IRoutableTileProvider from "../fetcher/tiles/IRoutableTileProvider"; +import RoutableTileFetcherRaw from "../fetcher/tiles/RoutableTileFetcherRaw"; +import RoutableTileProviderDefault from "../fetcher/tiles/RoutableTileProviderDefault"; +import RoutableTileProviderTransit from "../fetcher/tiles/RoutableTileProviderTransit"; + +import { LDLoader } from "../loader/ldloader"; +import DijkstraTree from "../pathfinding/dijkstra-tree/DijkstraTree"; +import { Dijkstra } from "../pathfinding/dijkstra/Dijkstra"; +import { IShortestPathAlgorithm, IShortestPathTreeAlgorithm } from "../pathfinding/pathfinder"; +import PathfinderProvider from "../pathfinding/PathfinderProvider"; +import CSAEarliestArrival from "../planner/public-transport/CSAEarliestArrival"; +import IJourneyExtractor from "../planner/public-transport/IJourneyExtractor"; +import IPublicTransportPlanner from "../planner/public-transport/IPublicTransportPlanner"; +import JourneyExtractorProfile from "../planner/public-transport/JourneyExtractorProfile"; +import IRoadPlanner from "../planner/road/IRoadPlanner"; +import RoadPlannerPathfindingExperimental from "../planner/road/RoadPlannerPathfindingExperimental"; +import IReachableStopsFinder from "../planner/stops/IReachableStopsFinder"; +import ReachableStopsFinderDelaunay from "../planner/stops/ReachableStopsFinderDelaunay"; +import ReachableStopsFinderOnlySelf from "../planner/stops/ReachableStopsFinderOnlySelf"; +import QueryRunnerExponential from "../query-runner/exponential/QueryRunnerExponential"; +import ILocationResolver from "../query-runner/ILocationResolver"; +import IQueryRunner from "../query-runner/IQueryRunner"; +import LocationResolverConvenience from "../query-runner/LocationResolverConvenience"; +import TYPES from "../types"; + +const container = new Container(); +container.bind(TYPES.Context).to(Context).inSingletonScope(); +container.bind(TYPES.QueryRunner).to(QueryRunnerExponential); +container.bind(TYPES.LocationResolver).to(LocationResolverConvenience); + +// TODO, make this a fixed property of the planner itself +container.bind(TYPES.JourneyExtractor) + .to(JourneyExtractorProfile); + +container.bind(TYPES.PublicTransportPlanner) + .to(CSAEarliestArrival); +container.bind>(TYPES.PublicTransportPlannerFactory) + .toAutoFactory(TYPES.PublicTransportPlanner); + +container.bind(TYPES.RoadPlanner) + .to(RoadPlannerPathfindingExperimental); + +container.bind(TYPES.ShortestPathTreeAlgorithm).to(DijkstraTree).inSingletonScope(); +container.bind(TYPES.ShortestPathAlgorithm).to(Dijkstra).inSingletonScope(); +container.bind(TYPES.PathfinderProvider).to(PathfinderProvider).inSingletonScope(); +container.bind(TYPES.ProfileFetcher).to(ProfileFetcherDefault).inSingletonScope(); +container.bind(TYPES.ProfileProvider).to(ProfileProviderDefault).inSingletonScope(); + +container.bind(TYPES.FootpathsProvider).to(FootpathsProviderDefault).inSingletonScope(); + +container.bind(TYPES.ReachableStopsFinder) + .to(ReachableStopsFinderDelaunay).whenTargetTagged("phase", ReachableStopsSearchPhase.Initial); +container.bind(TYPES.ReachableStopsFinder) + .to(ReachableStopsFinderOnlySelf).whenTargetTagged("phase", ReachableStopsSearchPhase.Transfer); +container.bind(TYPES.ReachableStopsFinder) + .to(ReachableStopsFinderDelaunay).whenTargetTagged("phase", ReachableStopsSearchPhase.Final); + +container.bind(TYPES.ConnectionsProvider).to(ConnectionsProviderDefault).inSingletonScope(); +container.bind(TYPES.ConnectionsFetcher).to(ConnectionsFetcherRaw); +container.bind>(TYPES.ConnectionsFetcherFactory) + .toFactory( + (context: interfaces.Context) => + (accessUrl: string, travelMode: TravelMode) => { + const fetcher = context.container.get(TYPES.ConnectionsFetcher); + + fetcher.setTravelMode(travelMode); + + return fetcher; + }, + ); + +container.bind(TYPES.StopsProvider).to(StopsProviderDefault).inSingletonScope(); +container.bind(TYPES.StopsFetcher).to(StopsFetcherRaw); +container.bind>(TYPES.StopsFetcherFactory) + .toFactory( + (context: interfaces.Context) => + (accessUrl: string) => { + const fetcher = context.container.get(TYPES.StopsFetcher); + fetcher.setAccessUrl(accessUrl); + return fetcher; + }, + ); + +container.bind(TYPES.RoutableTileRegistry).to(RoutableTileRegistry).inSingletonScope(); +container.bind(TYPES.RoutableTileFetcher).to(RoutableTileFetcherRaw).inSingletonScope(); +container.bind(TYPES.RoutableTileProvider) + .to(RoutableTileProviderDefault).inSingletonScope().whenTargetTagged("phase", RoutingPhase.Base); +container.bind(TYPES.RoutableTileProvider) + .to(RoutableTileProviderTransit).inSingletonScope().whenTargetTagged("phase", RoutingPhase.Transit); + +// Bind catalog +container.bind(TYPES.Catalog).toConstantValue(catalogNmbs); + +// Init LDFetch +container.bind(TYPES.LDFetch).to(LDFetch).inSingletonScope(); + +container.bind(TYPES.LDLoader).to(LDLoader); + +export default container; diff --git a/src/configs/triangle_demo.ts b/src/configs/triangle_demo.ts new file mode 100644 index 00000000..2862e495 --- /dev/null +++ b/src/configs/triangle_demo.ts @@ -0,0 +1,125 @@ +import { Container, interfaces } from "inversify"; +import Catalog from "../Catalog"; +import catalogDeLijn from "../catalog.delijn.vlaenderen"; +import catalogNmbs from "../catalog.nmbs"; +import Context from "../Context"; +import RoutableTileRegistry from "../entities/tiles/registry"; +import ReachableStopsSearchPhase from "../enums/ReachableStopsSearchPhase"; +import RoutingPhase from "../enums/RoutingPhase"; +import TravelMode from "../enums/TravelMode"; +import ConnectionsFetcherRaw from "../fetcher/connections/ConnectionsFetcherRaw"; +import ConnectionsProviderMerge from "../fetcher/connections/ConnectionsProviderMerge"; +import IConnectionsFetcher from "../fetcher/connections/IConnectionsFetcher"; +import IConnectionsProvider from "../fetcher/connections/IConnectionsProvider"; +import FootpathsProviderRaw from "../fetcher/footpaths/FootpathsProviderRaw"; +import IFootpathsFetcher from "../fetcher/footpaths/IFootpathsProvider"; +import LDFetch from "../fetcher/LDFetch"; +import IProfileFetcher from "../fetcher/profiles/IProfileFetcher"; +import IProfileProvider from "../fetcher/profiles/IProfileProvider"; +import ProfileFetcherDefault from "../fetcher/profiles/ProfileFetcherDefault"; +import ProfileProviderDefault from "../fetcher/profiles/ProfileProviderDefault"; +import IStopsFetcher from "../fetcher/stops/IStopsFetcher"; +import IStopsProvider from "../fetcher/stops/IStopsProvider"; +import StopsFetcherRaw from "../fetcher/stops/StopsFetcherRaw"; +import StopsProviderDefault from "../fetcher/stops/StopsProviderDefault"; +import IRoutableTileFetcher from "../fetcher/tiles/IRoutableTileFetcher"; +import IRoutableTileProvider from "../fetcher/tiles/IRoutableTileProvider"; +import RoutableTileFetcherRaw from "../fetcher/tiles/RoutableTileFetcherRaw"; +import RoutableTileProviderDefault from "../fetcher/tiles/RoutableTileProviderDefault"; +import RoutableTileProviderTransit from "../fetcher/tiles/RoutableTileProviderTransit"; + +import { LDLoader } from "../loader/ldloader"; +import { BidirDijkstra } from "../pathfinding/bidirdijkstra/BidirDijkstra"; +import DijkstraTree from "../pathfinding/dijkstra-tree/DijkstraTree"; +import { IShortestPathAlgorithm, IShortestPathTreeAlgorithm } from "../pathfinding/pathfinder"; +import PathfinderProvider from "../pathfinding/PathfinderProvider"; +import CSAEarliestArrivalVerbose from "../planner/public-transport/CSAEarliestArrivalVerbose"; +import IJourneyExtractor from "../planner/public-transport/IJourneyExtractor"; +import IPublicTransportPlanner from "../planner/public-transport/IPublicTransportPlanner"; +import JourneyExtractorProfile from "../planner/public-transport/JourneyExtractorProfile"; +import IRoadPlanner from "../planner/road/IRoadPlanner"; +import RoadPlannerPathfinding from "../planner/road/RoadPlannerPathfinding"; +import IReachableStopsFinder from "../planner/stops/IReachableStopsFinder"; +import ReachableStopsFinderDelaunay from "../planner/stops/ReachableStopsFinderDelaunay"; +import ReachableStopsFinderFootpathsVerbose from "../planner/stops/ReachableStopsFinderFootpathsVerbose"; +import ILocationResolver from "../query-runner/ILocationResolver"; +import IQueryRunner from "../query-runner/IQueryRunner"; +import LocationResolverConvenience from "../query-runner/LocationResolverConvenience"; +import QueryRunnerDefault from "../query-runner/QueryRunnerDefault"; +import TYPES from "../types"; + +const container = new Container(); +container.bind(TYPES.Context).to(Context).inSingletonScope(); +container.bind(TYPES.QueryRunner).to(QueryRunnerDefault); +container.bind(TYPES.LocationResolver).to(LocationResolverConvenience); + +// TODO, make this a fixed property of the planner itself +container.bind(TYPES.JourneyExtractor) + .to(JourneyExtractorProfile); + +container.bind(TYPES.PublicTransportPlanner) + .to(CSAEarliestArrivalVerbose); +container.bind>(TYPES.PublicTransportPlannerFactory) + .toAutoFactory(TYPES.PublicTransportPlanner); + +container.bind(TYPES.RoadPlanner) + .to(RoadPlannerPathfinding); + +container.bind(TYPES.ShortestPathTreeAlgorithm).to(DijkstraTree).inSingletonScope(); +container.bind(TYPES.ShortestPathAlgorithm).to(BidirDijkstra).inSingletonScope(); +container.bind(TYPES.PathfinderProvider).to(PathfinderProvider).inSingletonScope(); +container.bind(TYPES.ProfileFetcher).to(ProfileFetcherDefault).inSingletonScope(); +container.bind(TYPES.ProfileProvider).to(ProfileProviderDefault).inSingletonScope(); + +container.bind(TYPES.FootpathsProvider).to(FootpathsProviderRaw).inSingletonScope(); + +container.bind(TYPES.ReachableStopsFinder) + .to(ReachableStopsFinderDelaunay).whenTargetTagged("phase", ReachableStopsSearchPhase.Initial); +container.bind(TYPES.ReachableStopsFinder) + .to(ReachableStopsFinderFootpathsVerbose).whenTargetTagged("phase", ReachableStopsSearchPhase.Transfer); +container.bind(TYPES.ReachableStopsFinder) + .to(ReachableStopsFinderDelaunay).whenTargetTagged("phase", ReachableStopsSearchPhase.Final); + +container.bind(TYPES.ConnectionsProvider).to(ConnectionsProviderMerge).inSingletonScope(); +container.bind(TYPES.ConnectionsFetcher).to(ConnectionsFetcherRaw); +container.bind>(TYPES.ConnectionsFetcherFactory) + .toFactory( + (context: interfaces.Context) => + (accessUrl: string, travelMode: TravelMode) => { + const fetcher = context.container.get(TYPES.ConnectionsFetcher); + + fetcher.setTravelMode(travelMode); + + return fetcher; + }, + ); + +container.bind(TYPES.StopsProvider).to(StopsProviderDefault).inSingletonScope(); +container.bind(TYPES.StopsFetcher).to(StopsFetcherRaw); +container.bind>(TYPES.StopsFetcherFactory) + .toFactory( + (context: interfaces.Context) => + (accessUrl: string) => { + const fetcher = context.container.get(TYPES.StopsFetcher); + fetcher.setAccessUrl(accessUrl); + return fetcher; + }, + ); + +container.bind(TYPES.RoutableTileRegistry).to(RoutableTileRegistry).inSingletonScope(); +container.bind(TYPES.RoutableTileFetcher).to(RoutableTileFetcherRaw).inSingletonScope(); +container.bind(TYPES.RoutableTileProvider) + .to(RoutableTileProviderDefault).inSingletonScope().whenTargetTagged("phase", RoutingPhase.Base); +container.bind(TYPES.RoutableTileProvider) + .to(RoutableTileProviderTransit).inSingletonScope().whenTargetTagged("phase", RoutingPhase.Transit); + +// Bind catalog +const combined = Catalog.combine(catalogNmbs, catalogDeLijn); +container.bind(TYPES.Catalog).toConstantValue(combined); + +// Init LDFetch +container.bind(TYPES.LDFetch).to(LDFetch).inSingletonScope(); + +container.bind(TYPES.LDLoader).to(LDLoader); + +export default container; diff --git a/src/demo.ts b/src/demo.ts index beb2c7e9..092212f0 100644 --- a/src/demo.ts +++ b/src/demo.ts @@ -1,26 +1,26 @@ -import EventType from "./enums/EventType"; -import Planner from "./index"; +import { BasicTrainPlanner } from "."; +import EventBus from "./events/EventBus"; +import EventType from "./events/EventType"; import IPath from "./interfaces/IPath"; import Units from "./util/Units"; export default async (logResults) => { - const planner = new Planner(); - - planner.prefetchStops(); - planner.prefetchConnections(); + const planner = new BasicTrainPlanner(); if (logResults) { let scannedPages = 0; let scannedConnections = 0; + const eventBus = EventBus.getInstance(); + // let logFetch = true; if (logResults) { - console.log("Start prefetch"); + console.log(`${new Date()} Start prefetch`); } - planner + eventBus .on(EventType.InvalidQuery, (error) => { console.log("InvalidQuery", error); }) @@ -56,28 +56,33 @@ export default async (logResults) => { }); } - return wait(5000) - .then(() => new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { if (logResults) { - console.log("Start query"); + console.log(`${new Date()} Start query`); } - const amount = 3; + const amount = 1; let i = 0; - planner.query({ - publicTransportOnly: true, - // from: "https://data.delijn.be/stops/201657", - // to: "https://data.delijn.be/stops/205910", - // from: "https://data.delijn.be/stops/200455", // Deinze weg op Grammene +456 - // to: "https://data.delijn.be/stops/502481", // Tielt Metaalconstructie Goossens - // from: "https://data.delijn.be/stops/509927", // Tield Rameplein perron 1 - // to: "https://data.delijn.be/stops/200455", // Deinze weg op Grammene +456 - from: "Ingelmunster", // Ingelmunster - to: "http://irail.be/stations/NMBS/008892007", // Ghent-Sint-Pieters - minimumDepartureTime: new Date(), - maximumTransferDuration: Units.fromMinutes(30), - }) + planner + .setProfileID("https://hdelva.be/profile/pedestrian") + .query({ + // roadNetworkOnly: true, + // from: "https://data.delijn.be/stops/201657", + // to: "https://data.delijn.be/stops/205910", + // from: "https://data.delijn.be/stops/200455", // Deinze weg op Grammene +456 + // to: "https://data.delijn.be/stops/502481", // Tielt Metaalconstructie Goossens + // from: "https://data.delijn.be/stops/509927", // Tield Rameplein perron 1 + // to: "https://data.delijn.be/stops/200455", // Deinze weg op Grammene +456 + // from: "Ingelmunster", // Ingelmunster + // to: "http://irail.be/stations/NMBS/008892007", // Ghent-Sint-Pieters + from: { latitude: 50.93278, longitude: 5.32665 }, // Pita Aladin, Hasselt + to: { latitude: 50.7980187, longitude: 3.1877779 }, // Burger Pita Pasta, Menen + // from: "Hasselt", + // to: "Kortrijk", + minimumDepartureTime: new Date(), + maximumTransferDuration: Units.fromMinutes(30), + }) .take(amount) .on("error", (error) => { resolve(false); @@ -86,6 +91,7 @@ export default async (logResults) => { ++i; if (logResults) { + console.log(new Date()); console.log(i); console.log(JSON.stringify(path, null, " ")); console.log("\n"); @@ -98,7 +104,5 @@ export default async (logResults) => { .on("end", () => { resolve(false); }); - })); + }); }; - -const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); diff --git a/src/fetcher/connections/IConnection.ts b/src/entities/connections/connections.ts similarity index 81% rename from src/fetcher/connections/IConnection.ts rename to src/entities/connections/connections.ts index 19c9669c..4e04a460 100644 --- a/src/fetcher/connections/IConnection.ts +++ b/src/entities/connections/connections.ts @@ -10,7 +10,7 @@ import { DurationMs } from "../../interfaces/units"; * for the actual arrival and departureTime. * The arrivalDelay and departureDelay then again contain the duration in which these times deviate * from the planned time. - * @property "gtfs:trip" (optional) an identifier for the trip this vehicle is making with this connection + * @property "tripId" (optional) an identifier for the trip this vehicle is making with this connection * @property nextConnection (optional) an identifier for the next connection the vehicle is going to make * @property TravelMode The type of vehicle that is used, chosen from an enum [[TravelMode]] */ @@ -27,10 +27,10 @@ export default interface IConnection { departureDelay?: DurationMs; nextConnection?: string[]; + tripId?: string; - "gtfs:route"?: string; - "gtfs:trip"?: string; - "gtfs:dropOffType"?: DropOffType; - "gtfs:pickupType"?: PickupType; - "gtfs:headsign"?: string; + route?: string; + dropOffType: DropOffType; + pickupType: PickupType; + headsign: string; } diff --git a/src/entities/connections/page.ts b/src/entities/connections/page.ts new file mode 100644 index 00000000..7ac317cb --- /dev/null +++ b/src/entities/connections/page.ts @@ -0,0 +1,39 @@ +import IConnection from "./connections"; + +export class LinkedConnectionsPage { + public id: string; + private previousPageId: string; + private nextPageId: string; + private connections: IConnection[]; + + constructor(id: string, connections: IConnection[], previousPageId: string, nextPageId: string) { + this.id = id; + this.previousPageId = previousPageId; + this.nextPageId = nextPageId; + this.connections = connections; + } + + public getConnections(): IConnection[] { + return this.connections; + } + + public getPreviousPageId(): string { + return this.previousPageId; + } + + public getNextPageId(): string { + return this.nextPageId; + } + + public getLowerBound(): Date { + return this.connections[0].departureTime; + } + + public getUpperBound(): Date { + return this.connections[this.connections.length - 1].departureTime; + } +} + +export interface ILinkedConnectionsPageIndex { + [id: string]: Promise; +} diff --git a/src/entities/footpaths/footpath.ts b/src/entities/footpaths/footpath.ts new file mode 100644 index 00000000..2d05f45e --- /dev/null +++ b/src/entities/footpaths/footpath.ts @@ -0,0 +1,21 @@ +import IStop from "../../fetcher/stops/IStop"; +import { DistanceM } from "../../interfaces/units"; + +export class Footpath { + public static create(id: string) { + return new Footpath(id); + } + + public from: string; + public to: string; + public distance: DistanceM; + public id: string; + + constructor(id: string) { + this.id = id; + } +} + +export interface IFootpathIndex { + [id: string]: Footpath; +} diff --git a/src/entities/hydra/hydra.ts b/src/entities/hydra/hydra.ts new file mode 100644 index 00000000..999808bc --- /dev/null +++ b/src/entities/hydra/hydra.ts @@ -0,0 +1,11 @@ +export class HydraEntity { + public static create(id) { + return new HydraEntity(id); + } + + public id: string; + + constructor(id: string) { + this.id = id; + } +} diff --git a/src/entities/hydra/mapping.ts b/src/entities/hydra/mapping.ts new file mode 100644 index 00000000..8f7b7e2b --- /dev/null +++ b/src/entities/hydra/mapping.ts @@ -0,0 +1,11 @@ +export class HydraTemplateMapping { + public static create(id?: string) { + return new HydraTemplateMapping(id); + } + + public id?: string; + + constructor(id?: string) { + this.id = id; + } +} diff --git a/src/entities/hydra/search.ts b/src/entities/hydra/search.ts new file mode 100644 index 00000000..cbcf0e54 --- /dev/null +++ b/src/entities/hydra/search.ts @@ -0,0 +1,11 @@ +export class HydraTemplate { + public static create(id?: string) { + return new HydraTemplate(id); + } + + public id?: string; + + constructor(id?: string) { + this.id = id; + } +} diff --git a/src/entities/profile/CharacteresticProfile.ts b/src/entities/profile/CharacteresticProfile.ts new file mode 100644 index 00000000..472fb383 --- /dev/null +++ b/src/entities/profile/CharacteresticProfile.ts @@ -0,0 +1,90 @@ +import { RoutableTileWay } from "../tiles/way"; +import DynamicProfile from "./DynamicProfile"; + +export default class CharacteristicProfile extends DynamicProfile { + public static create(url: string): CharacteristicProfile { + return new CharacteristicProfile(url); + } + + private accessCache: object; + private onewayCache: object; + private speedCache: object; + private priorityCache: object; + + constructor(url: string) { + super(url); + this.accessCache = {}; + this.onewayCache = {}; + this.speedCache = {}; + this.priorityCache = {}; + this.id = url; + } + + public getID(): string { + return this.id; + } + + public isOneWay(way: RoutableTileWay): boolean { + const characteristic = this.getWayCharacteristic(way); + if (this.onewayCache[characteristic] !== undefined) { + return this.onewayCache[characteristic]; + } + + const result = super.isOneWay(way); + this.onewayCache[characteristic] = result; + return result; + } + + public hasAccess(way: RoutableTileWay): boolean { + const characteristic = this.getWayCharacteristic(way); + if (this.accessCache[characteristic] !== undefined) { + return this.accessCache[characteristic]; + } + + const result = super.hasAccess(way); + this.accessCache[characteristic] = result; + return result; + } + + public getSpeed(way: RoutableTileWay): number { + const characteristic = this.getWayCharacteristic(way); + if (this.speedCache[characteristic] !== undefined) { + return this.speedCache[characteristic]; + } + + const result = super.getSpeed(way); + this.speedCache[characteristic] = result; + return result; + } + + public getMultiplier(way: RoutableTileWay): number { + const characteristic = this.getWayCharacteristic(way); + if (this.priorityCache[characteristic] !== undefined) { + return this.priorityCache[characteristic]; + } + + const result = super.getMultiplier(way); + this.priorityCache[characteristic] = result; + return result; + } + + private getWayCharacteristic(way: RoutableTileWay) { + return way.reachable + + way.accessRestrictions + + way.bicycleAccessRestrictions + + way.constructionKind + + way.crossingKind + + way.cyclewayKind + + way.footwayKind + + way.highwayKind + + way.maxSpeed + + way.motorVehicleAccessRestrictions + + way.motorcarAccessRestrictions + + way.onewayBicycleKind + + way.onewayKind + + way.smoothnessKind + + way.surfaceKind + + way.trackType + + way.vehicleAccessRestrictions; + } +} diff --git a/src/entities/profile/DynamicProfile.ts b/src/entities/profile/DynamicProfile.ts new file mode 100644 index 00000000..0e077c45 --- /dev/null +++ b/src/entities/profile/DynamicProfile.ts @@ -0,0 +1,179 @@ +import getOsmTagMapping from "../../enums/OSMTags"; +import { DistanceM, DurationMs } from "../../interfaces/units"; +import Geo from "../../util/Geo"; +import { RoutableTileNode } from "../tiles/node"; +import { RoutableTileWay } from "../tiles/way"; +import Profile from "./Profile"; +import ProfileRule from "./ProfileRule"; + +export default class DynamicProfile extends Profile { + public static create(url: string): DynamicProfile { + return new DynamicProfile(url); + } + + public id: string; + public accessRules: ProfileRule[]; + public onewayRules: ProfileRule[]; + public speedRules: ProfileRule[]; + public priorityRules: ProfileRule[]; + public obstacleRules: ProfileRule[]; + public obstacleTimeRules: ProfileRule[]; + + public maxSpeed: number; + public usePublicTransport: boolean; + + private mapping; + + constructor(url: string) { + super(); + this.id = url; + this.mapping = getOsmTagMapping(); + + this.accessRules = []; + this.onewayRules = []; + this.speedRules = []; + this.priorityRules = []; + this.obstacleRules = []; + this.obstacleTimeRules = []; + + this.maxSpeed = 10; + this.usePublicTransport = true; + } + + public getID(): string { + return this.id; + } + + public isOneWay(way: RoutableTileWay): boolean { + // todo, reversed order + for (const rule of this.onewayRules) { + if (rule.conclusion.isOneway !== undefined) { + // should always be the case, but just in case + if (rule.condition !== undefined) { + const field = this.mapping[rule.condition.predicate]; + if (way[field] === rule.condition.object) { + return rule.conclusion.isOneway; + } + } else { + return rule.conclusion.isOneway; + } + } + } + } + + public hasAccess(way: RoutableTileWay): boolean { + for (const rule of this.accessRules) { + if (rule.conclusion.hasAccess !== undefined) { + // should always be the case, but just in case + if (rule.condition !== undefined) { + const field = this.mapping[rule.condition.predicate]; + if (way[field] === rule.condition.object) { + return rule.conclusion.hasAccess; + } + } else { + return rule.conclusion.hasAccess; + } + } + } + } + + public getDefaultSpeed() { + return 5; + } + + public getMaxSpeed(): number { + return this.maxSpeed || 300; + } + + public getSpeed(way: RoutableTileWay): number { + const speedLimit = Math.min(way.maxSpeed || Infinity, this.getMaxSpeed()); + + for (const rule of this.speedRules) { + if (rule.conclusion.speed !== undefined) { + // should always be the case, but just in case + if (rule.condition !== undefined) { + const field = this.mapping[rule.condition.predicate]; + if (way[field] === rule.condition.object) { + if (typeof (rule.conclusion.speed) === "number") { + return Math.min(rule.conclusion.speed, speedLimit); + } + } else { + if (typeof (rule.conclusion.speed) === "number") { + return Math.min(rule.conclusion.speed, speedLimit); + } + } + } + } + } + + return Math.min(speedLimit, this.getDefaultSpeed()); + } + + public getDistance(from: RoutableTileNode, to: RoutableTileNode, way: RoutableTileWay): DistanceM { + return Geo.getDistanceBetweenLocations(from, to); + } + + public getDuration(from: RoutableTileNode, to: RoutableTileNode, way: RoutableTileWay): DurationMs { + const distance = this.getDistance(from, to, way) / 1000; // km + const speed = this.getSpeed(way); + const time = distance / speed; // h + return time * 60 * 60 * 1000; // ms + } + + public getMultiplier(way: RoutableTileWay): number { + for (const rule of this.priorityRules) { + if (rule.conclusion.priority !== undefined) { + // should always be the case, but just in case + if (rule.condition !== undefined) { + const field = this.mapping[rule.condition.predicate]; + if (way[field] === rule.condition.object) { + return 1 - (rule.conclusion.priority - 1); + } + } else { + return 1 - (rule.conclusion.priority - 1); + } + } + } + } + + public getCost(from: RoutableTileNode, to: RoutableTileNode, way: RoutableTileWay): number { + return this.getMultiplier(way) * (this.getDuration(from, to, way) + this.getObstacleTime(to)); + } + + public isObstacle(node: RoutableTileNode): boolean { + for (const rule of this.obstacleRules) { + if (rule.conclusion.isObstacle !== undefined) { + // should always be the case, but just in case + if (rule.condition !== undefined) { + const field = this.mapping[rule.condition.predicate]; + if (node[field] === rule.condition.object) { + return rule.conclusion.isObstacle; + } + } else { + return rule.conclusion.isObstacle; + } + } + } + } + + public getObstacleTime(node: RoutableTileNode): DurationMs { + for (const rule of this.obstacleTimeRules) { + if (rule.conclusion.obstacleTime !== undefined) { + // should always be the case, but just in case + if (rule.condition !== undefined) { + const field = this.mapping[rule.condition.predicate]; + if (node[field] && rule.condition.object === undefined) { + return rule.conclusion.obstacleTime * 1000; + } + if (node[field] === rule.condition.object && rule.condition.object !== undefined) { + return rule.conclusion.obstacleTime * 1000; + } + } else { + return rule.conclusion.obstacleTime * 1000; + } + } + } + + return 0; + } +} diff --git a/src/entities/profile/PedestrianProfile.ts b/src/entities/profile/PedestrianProfile.ts new file mode 100644 index 00000000..ffc6dfc8 --- /dev/null +++ b/src/entities/profile/PedestrianProfile.ts @@ -0,0 +1,97 @@ +import Highway from "../../enums/Highway"; +import { DistanceM, DurationMs } from "../../interfaces/units"; +import Geo from "../../util/Geo"; +import { RoutableTileNode } from "../tiles/node"; +import { RoutableTileWay } from "../tiles/way"; +import Profile from "./Profile"; + +export default class PedestrianProfile extends Profile { + public getID(): string { + return "PEDESTRIAN"; + } + + public isOneWay(way: RoutableTileWay): boolean { + return false; + } + + public hasAccess(way: RoutableTileWay): boolean { + if (way.highwayKind === Highway.Motorway) { + return false; + } else if (way.highwayKind === Highway.MotorwayLink) { + return false; + } else if (way.highwayKind === Highway.Trunk) { + return false; + } else if (way.highwayKind === Highway.TrunkLink) { + return false; + } + + return true; + } + + public getDefaultSpeed() { + return 5; + } + + public getMaxSpeed() { + return this.getDefaultSpeed(); + } + + public getSpeed(way: RoutableTileWay) { + return this.getDefaultSpeed(); + } + + public getDistance(from: RoutableTileNode, to: RoutableTileNode, way: RoutableTileWay): DistanceM { + return Geo.getDistanceBetweenLocations(from, to); + } + + public getDuration(from: RoutableTileNode, to: RoutableTileNode, way: RoutableTileWay): DurationMs { + const distance = this.getDistance(from, to, way) / 1000; // km + const speed = 5; // km/h + const time = distance / speed; // h + return time * 60 * 60 * 1000; // ms + } + + public getMultiplier(way: RoutableTileWay): number { + if (way.highwayKind === Highway.Motorway) { + return 1.3; + } else if (way.highwayKind === Highway.MotorwayLink) { + return 1.3; + } else if (way.highwayKind === Highway.Trunk) { + return 1.3; + } else if (way.highwayKind === Highway.TrunkLink) { + return 1.3; + } else if (way.highwayKind === Highway.Service) { + return 1.1; + } else if (way.highwayKind === Highway.Tertiary) { + return 1.1; + } else if (way.highwayKind === Highway.TertiaryLink) { + return 1.1; + } else if (way.highwayKind === Highway.Secondary) { + return 1.1; + } else if (way.highwayKind === Highway.SecondaryLink) { + return 1.1; + } else if (way.highwayKind === Highway.Primary) { + return 1.1; + } else if (way.highwayKind === Highway.PrimaryLink) { + return 1.1; + } else if (way.highwayKind === Highway.LivingStreet) { + return 0.8; + } else if (way.highwayKind === Highway.Footway) { + return 0.8; + } + + return 1; + } + + public getCost(from: RoutableTileNode, to: RoutableTileNode, way: RoutableTileWay): number { + return this.getMultiplier(way) * this.getDuration(from, to, way); + } + + public isObstacle(node: RoutableTileNode): boolean { + return false; + } + + public getObstacleTime(node: RoutableTileNode): DurationMs { + return 0; + } +} diff --git a/src/entities/profile/Profile.ts b/src/entities/profile/Profile.ts new file mode 100644 index 00000000..e63447c9 --- /dev/null +++ b/src/entities/profile/Profile.ts @@ -0,0 +1,24 @@ +import ILocation from "../../interfaces/ILocation"; +import { DistanceM, DurationMs } from "../../interfaces/units"; +import { RoutableTileNode } from "../tiles/node"; +import { RoutableTileWay } from "../tiles/way"; + +export default abstract class Profile { + public abstract getID(): string; + + public abstract isOneWay(way: RoutableTileWay): boolean; + public abstract hasAccess(way: RoutableTileWay): boolean; + + public abstract getDefaultSpeed(): number; + public abstract getMaxSpeed(): number; + public abstract getSpeed(way: RoutableTileWay): number; + + public abstract getDistance(from: ILocation, to: ILocation, way: RoutableTileWay): DistanceM; + public abstract getDuration(from: ILocation, to: ILocation, way: RoutableTileWay): DurationMs; + + public abstract getMultiplier(way: RoutableTileWay): number; + public abstract getCost(from: ILocation, to: ILocation, way: RoutableTileWay): number; + + public abstract isObstacle(node: RoutableTileNode): boolean; + public abstract getObstacleTime(node: RoutableTileNode): DurationMs; +} diff --git a/src/entities/profile/ProfileConclusion.ts b/src/entities/profile/ProfileConclusion.ts new file mode 100644 index 00000000..153cc5e4 --- /dev/null +++ b/src/entities/profile/ProfileConclusion.ts @@ -0,0 +1,25 @@ +import { IEntity } from "../../loader/common"; +import ProfileValueReference from "./ProfileValueReference"; + +export default class ProfileConclusion implements IEntity { + public static create(id: string): ProfileConclusion { + return new ProfileConclusion(id); + } + + public id: string; + public hasAccess?: boolean; + public isOneway?: boolean; + public isReversed?: boolean; + public speed?: number | ProfileValueReference; + public isObstacle?: boolean; + public priority?: number; + public obstacleTime?: number; + + constructor(id: string) { + this.id = id; + } + + public getID(): string { + return this.id; + } +} diff --git a/src/entities/profile/ProfileCondition.ts b/src/entities/profile/ProfileCondition.ts new file mode 100644 index 00000000..05c04fea --- /dev/null +++ b/src/entities/profile/ProfileCondition.ts @@ -0,0 +1,19 @@ +import { IEntity } from "../../loader/common"; + +export default class ProfileCondition implements IEntity { + public static create(id: string): ProfileCondition { + return new ProfileCondition(id); + } + + public id: string; + public predicate: string; + public object: string; + + constructor(id: string) { + this.id = id; + } + + public getID(): string { + return this.id; + } +} diff --git a/src/entities/profile/ProfileRule.ts b/src/entities/profile/ProfileRule.ts new file mode 100644 index 00000000..1ef9be37 --- /dev/null +++ b/src/entities/profile/ProfileRule.ts @@ -0,0 +1,22 @@ +import { IEntity } from "../../loader/common"; +import ProfileConclusion from "./ProfileConclusion"; +import ProfileCondition from "./ProfileCondition"; + +export default class ProfileRule implements IEntity { + public static create(id: string): ProfileRule { + return new ProfileRule(id); + } + + public id: string; + public conclusion: ProfileConclusion; + public condition: ProfileCondition; + public order: number; + + constructor(id: string) { + this.id = id; + } + + public getID(): string { + return this.id; + } +} diff --git a/src/entities/profile/ProfileValueReference.ts b/src/entities/profile/ProfileValueReference.ts new file mode 100644 index 00000000..b2ed71c9 --- /dev/null +++ b/src/entities/profile/ProfileValueReference.ts @@ -0,0 +1,24 @@ +import { IEntity } from "../../loader/common"; +import { RoutableTileNode } from "../tiles/node"; +import { RoutableTileWay } from "../tiles/way"; + +export default class ProfileValueReference implements IEntity { + public static create(id: string): ProfileValueReference { + return new ProfileValueReference(id); + } + + public id: string; + public from: string; + + constructor(id: string) { + this.id = id; + } + + public getID(): string { + return this.id; + } + + public resolve(element: RoutableTileNode | RoutableTileWay) { + return element[this.from]; + } +} diff --git a/src/entities/tiles/coordinate.ts b/src/entities/tiles/coordinate.ts new file mode 100644 index 00000000..5580640a --- /dev/null +++ b/src/entities/tiles/coordinate.ts @@ -0,0 +1,22 @@ +export class RoutableTileCoordinate { + public zoom: number; + public x: number; + public y: number; + + constructor(zoom: number, x: number, y: number) { + this.zoom = zoom; + this.x = x; + this.y = y; + } + + public contains(other: RoutableTileCoordinate): boolean { + const n = Math.pow(2, other.zoom - this.zoom); + const otherX = Math.floor(other.x / n); + const otherY = Math.floor(other.y / n); + if (otherX === this.x && otherY === this.y) { + return true; + } else { + return false; + } + } +} diff --git a/src/entities/tiles/edge.ts b/src/entities/tiles/edge.ts new file mode 100644 index 00000000..b1516671 --- /dev/null +++ b/src/entities/tiles/edge.ts @@ -0,0 +1,5 @@ +export default class Edge { + public from: string; + public to: string; + public distance?: number; +} diff --git a/src/entities/tiles/node.ts b/src/entities/tiles/node.ts new file mode 100644 index 00000000..9125ed19 --- /dev/null +++ b/src/entities/tiles/node.ts @@ -0,0 +1,26 @@ +import Barrier from "../../enums/Barrier"; +import Crossing from "../../enums/Crossing"; +import Highway from "../../enums/Highway"; +import ILocation from "../../interfaces/ILocation"; + +export class RoutableTileNode implements ILocation { + public static create(id: string) { + return new RoutableTileNode(id); + } + + public latitude: number; + public longitude: number; + public id: string; + + public barrierKind?: Barrier; + public highwayKind?: Highway; + public crossingKind?: Crossing; + + constructor(id: string) { + this.id = id; + } +} + +export interface IRoutableTileNodeIndex { + [id: string]: RoutableTileNode; +} diff --git a/src/entities/tiles/registry.ts b/src/entities/tiles/registry.ts new file mode 100644 index 00000000..66183169 --- /dev/null +++ b/src/entities/tiles/registry.ts @@ -0,0 +1,45 @@ +import { injectable } from "inversify"; +import { IRoutableTileNodeIndex, RoutableTileNode } from "./node"; +import { IRoutableTileWayIndex, RoutableTileWay } from "./way"; + +@injectable() +export default class RoutableTileRegistry { + private nodes: IRoutableTileNodeIndex; + private ways: IRoutableTileWayIndex; + + constructor() { + this.nodes = {}; + this.ways = {}; + } + + public registerNode(node: RoutableTileNode) { + this.nodes[node.id] = node; + } + + public registerWay(way: RoutableTileWay) { + if (!this.ways[way.id]) { + this.ways[way.id] = way; + } else { + // creates a new Way instance + // avoids overwriting data from the individual tile definitions + // otherwise ways might refer to nodes that aren't in the tile + this.ways[way.id] = way.mergeDefinitions(this.ways[way.id]); + } + } + + public getNode(id: string): RoutableTileNode { + return this.nodes[id]; + } + + public getWay(id: string): RoutableTileWay { + return this.ways[id]; + } + + public getNodes(): RoutableTileNode[] { + return Object.values(this.nodes); + } + + public getWays(): RoutableTileWay[] { + return Object.values(this.ways); + } +} diff --git a/src/entities/tiles/set.ts b/src/entities/tiles/set.ts new file mode 100644 index 00000000..f9c1b93b --- /dev/null +++ b/src/entities/tiles/set.ts @@ -0,0 +1,18 @@ +import { RoutableTile } from "./tile"; + +export class RoutableTileSet extends RoutableTile { + public tiles: RoutableTile[]; + + constructor(tiles: RoutableTile[], id?: string) { + let nodes = new Array(); + let ways = new Array(); + + for (const tile of tiles) { + nodes = nodes.concat(...tile.getNodes()); + ways = ways.concat(...tile.getWays()); + } + + super(id, new Set(nodes), new Set(ways)); + this.tiles = tiles; + } +} diff --git a/src/entities/tiles/tile.ts b/src/entities/tiles/tile.ts new file mode 100644 index 00000000..a1e95cb9 --- /dev/null +++ b/src/entities/tiles/tile.ts @@ -0,0 +1,55 @@ +import ILocation from "../../interfaces/ILocation"; +import { RoutableTileCoordinate } from "./coordinate"; + +function tile_to_lat(coordinate: RoutableTileCoordinate) { + // from https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames + const n = Math.PI - 2 * Math.PI * coordinate.y / Math.pow(2, coordinate.zoom); + return (180 / Math.PI * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)))); +} + +function tile_to_long(coordinate: RoutableTileCoordinate) { + // from https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames + return (coordinate.x / Math.pow(2, coordinate.zoom) * 360 - 180); +} + +export class RoutableTile { + public id: string; + public coordinate?: RoutableTileCoordinate; + protected nodes: Set; + protected ways: Set; + + constructor(id: string, nodes: Set, ways: Set) { + this.id = id; + this.nodes = nodes; + this.ways = ways; + } + + public getWays() { + return this.ways; + } + + public getNodes() { + return this.nodes; + } + + public contains(location: ILocation): boolean { + const top = tile_to_lat(this.coordinate); + const left = tile_to_long(this.coordinate); + + const next = new RoutableTileCoordinate(this.coordinate.zoom, this.coordinate.x + 1, this.coordinate.y + 1); + + const bottom = tile_to_lat(next); + const right = tile_to_long(next); + + if (location.latitude > top || location.latitude < bottom) { + return false; + } else if (location.longitude < left || location.longitude > right) { + return false; + } + return true; + } +} + +export interface IRoutableTileIndex { + [id: string]: Promise; +} diff --git a/src/entities/tiles/way.ts b/src/entities/tiles/way.ts new file mode 100644 index 00000000..4e348113 --- /dev/null +++ b/src/entities/tiles/way.ts @@ -0,0 +1,81 @@ +import Access from "../../enums/Access"; +import Construction from "../../enums/Construction"; +import Crossing from "../../enums/Crossing"; +import Cycleway from "../../enums/Cycleway"; +import Footway from "../../enums/Footway"; +import Highway from "../../enums/Highway"; +import Oneway from "../../enums/Oneway"; +import Smoothness from "../../enums/Smoothness"; +import Surface from "../../enums/Surface"; +import TrackType from "../../enums/TrackType"; +import Edge from "./edge"; + +export class RoutableTileWay { + public static create(id: string) { + return new RoutableTileWay(id); + } + + public id: string; + public segments: string[][]; // ids of nodes that are part of this road + public weights?: number[][]; // distances between the nodes in the segments + public name: string; + public reachable?: boolean; // not part of OSM but a result of preprocessing, do not use this (yet) + + public accessRestrictions?: Access; + public bicycleAccessRestrictions?: Access; + public constructionKind?: Construction; + public crossingKind?: Crossing; + public cyclewayKind?: Cycleway; + public footwayKind?: Footway; + public highwayKind: Highway; + public maxSpeed: number; + public motorVehicleAccessRestrictions?: Access; + public motorcarAccessRestrictions?: Access; + public onewayBicycleKind?: Oneway; + public onewayKind?: Oneway; + public smoothnessKind?: Smoothness; + public surfaceKind?: Surface; + public trackType?: TrackType; + public vehicleAccessRestrictions?: Access; + + constructor(id: string) { + this.id = id; + this.weights = [[]]; + } + + public mergeDefinitions(other: RoutableTileWay): RoutableTileWay { + const result = new RoutableTileWay(this.id); + // copy data fields + Object.assign(result, this); + Object.assign(result, other); + // special cases + if (this.reachable === false || other.reachable === false) { + result.reachable = false; + } + // do not modify the existing objects, copy the lists + result.segments = []; + result.segments = result.segments.concat(this.segments); + result.segments = result.segments.concat(other.segments); + + result.weights = []; + result.weights = result.weights.concat(this.weights); + result.weights = result.weights.concat(other.weights); + return result; + } + + public getParts(): Edge[] { + const result: Edge[] = []; + for (let index = 0; index < this.segments.length; index++) { + const weights = this.weights[index]; + const segment = this.segments[index]; + for (let i = 0; i < segment.length - 1; i++) { + result.push({from: segment[i], to: segment[i + 1], distance: weights[i]}); + } + } + return result; + } +} + +export interface IRoutableTileWayIndex { + [id: string]: RoutableTileWay; +} diff --git a/src/enums/Access.ts b/src/enums/Access.ts new file mode 100644 index 00000000..7e44c5ee --- /dev/null +++ b/src/enums/Access.ts @@ -0,0 +1,19 @@ +enum Access { + Agricultural = "https://w3id.org/openstreetmap/terms#Agricultural", + Customers = "https://w3id.org/openstreetmap/terms#Customers", + Delivery = "https://w3id.org/openstreetmap/terms#Delivery", + Designated = "https://w3id.org/openstreetmap/terms#Designated", + Destination = "https://w3id.org/openstreetmap/terms#Destination", + Discouraged = "https://w3id.org/openstreetmap/terms#Discouraged", + Dismount = "https://w3id.org/openstreetmap/terms#Dismount", + Emergency = "https://w3id.org/openstreetmap/terms#Emergency", + Forestry = "https://w3id.org/openstreetmap/terms#Forestry", + No = "https://w3id.org/openstreetmap/terms#NoAccess", + Official = "https://w3id.org/openstreetmap/terms#Official", + Permissive = "https://w3id.org/openstreetmap/terms#Permissive", + Private = "https://w3id.org/openstreetmap/terms#Private", + UseSidepath = "https://w3id.org/openstreetmap/terms#UseSidepath", + Yes = "https://w3id.org/openstreetmap/terms#FreeAccess", +} + +export default Access; diff --git a/src/enums/Barrier.ts b/src/enums/Barrier.ts new file mode 100644 index 00000000..60edb2ea --- /dev/null +++ b/src/enums/Barrier.ts @@ -0,0 +1,20 @@ +enum Barrier { + Block = "https://w3id.org/openstreetmap/terms#Block", + Bollard = "https://w3id.org/openstreetmap/terms#Bollard", + BorderControl = "https://w3id.org/openstreetmap/terms#BorderControl", + BumpGate = "https://w3id.org/openstreetmap/terms#BumpGate", + BusTrap = "https://w3id.org/openstreetmap/terms#BusTrap", + CattleGrid = "https://w3id.org/openstreetmap/terms#CattleGrid", + Chain = "https://w3id.org/openstreetmap/terms#Chain", + CycleBarrier = "https://w3id.org/openstreetmap/terms#CycleBarrier", + Debris = "https://w3id.org/openstreetmap/terms#Debris", + Entrance = "https://w3id.org/openstreetmap/terms#Entrance", + Gate = "https://w3id.org/openstreetmap/terms#Gate", + LiftGate = "https://w3id.org/openstreetmap/terms#LiftGate", + SallyPort = "https://w3id.org/openstreetmap/terms#SallyPort", + SwingGate = "https://w3id.org/openstreetmap/terms#SwingGate", + TollBooth = "https://w3id.org/openstreetmap/terms#TollBooth", + Turnstile = "https://w3id.org/openstreetmap/terms#Turnstile", +} + +export default Barrier; diff --git a/src/enums/Construction.ts b/src/enums/Construction.ts new file mode 100644 index 00000000..f065c080 --- /dev/null +++ b/src/enums/Construction.ts @@ -0,0 +1,5 @@ +enum Construction { + Yes = "https://w3id.org/openstreetmap/terms#UnderConstruction", +} + +export default Construction; diff --git a/src/enums/Crossing.ts b/src/enums/Crossing.ts new file mode 100644 index 00000000..76bf8529 --- /dev/null +++ b/src/enums/Crossing.ts @@ -0,0 +1,6 @@ +enum Crossing { + Uncontrolled = "https://w3id.org/openstreetmap/terms#Uncontrolled", + Unmarked = "https://w3id.org/openstreetmap/terms#Unmarked", +} + +export default Crossing; diff --git a/src/enums/Cycleway.ts b/src/enums/Cycleway.ts new file mode 100644 index 00000000..126da528 --- /dev/null +++ b/src/enums/Cycleway.ts @@ -0,0 +1,11 @@ +enum Cycleway { + Lane = "https://w3id.org/openstreetmap/terms#Lane", + Opposite = "https://w3id.org/openstreetmap/terms#Opposite", + OppositeLane = "https://w3id.org/openstreetmap/terms#OppositeLane", + OppositeTrack = "https://w3id.org/openstreetmap/terms#OppositeTrack", + ShareBusway = "https://w3id.org/openstreetmap/terms#ShareBusway", + Shared = "https://w3id.org/openstreetmap/terms#Shared", + SharedLane = "https://w3id.org/openstreetmap/terms#SharedLane", +} + +export default Cycleway; diff --git a/src/enums/Footway.ts b/src/enums/Footway.ts new file mode 100644 index 00000000..2a35395e --- /dev/null +++ b/src/enums/Footway.ts @@ -0,0 +1,5 @@ +enum Footway { + Sidewalk = "https://w3id.org/openstreetmap/terms#Sidewalk", +} + +export default Footway; diff --git a/src/enums/Highway.ts b/src/enums/Highway.ts new file mode 100644 index 00000000..8ec64f6a --- /dev/null +++ b/src/enums/Highway.ts @@ -0,0 +1,30 @@ +enum Highway { + BridleWay = "https://w3id.org/openstreetmap/terms#BridleWay", + Crossing = "https://w3id.org/openstreetmap/terms#Crossing", + Cycleway = "https://w3id.org/openstreetmap/terms#CycleHighway", + Footway = "https://w3id.org/openstreetmap/terms#FootHighway", + Giveway = "https://w3id.org/openstreetmap/terms#Giveway", + LivingStreet = "https://w3id.org/openstreetmap/terms#LivingStreet", + Motorway = "https://w3id.org/openstreetmap/terms#Motorway", + MotorwayLink = "https://w3id.org/openstreetmap/terms#MotorwayLink", + Path = "https://w3id.org/openstreetmap/terms#Path", + Primary = "https://w3id.org/openstreetmap/terms#Primary", + PrimaryLink = "https://w3id.org/openstreetmap/terms#PrimaryLink", + Proposed = "https://w3id.org/openstreetmap/terms#Proposed", + Residential = "https://w3id.org/openstreetmap/terms#Residential", + Road = "https://w3id.org/openstreetmap/terms#Road", + Secondary = "https://w3id.org/openstreetmap/terms#Secondary", + SecondaryLink = "https://w3id.org/openstreetmap/terms#SecondaryLink", + Service = "https://w3id.org/openstreetmap/terms#Service", + Steps = "https://w3id.org/openstreetmap/terms#Steps", + Stop = "https://w3id.org/openstreetmap/terms#Stop", + Tertiary = "https://w3id.org/openstreetmap/terms#Tertiary", + TertiaryLink = "https://w3id.org/openstreetmap/terms#TertiaryLink", + Track = "https://w3id.org/openstreetmap/terms#Track", + TrafficSignals = "https://w3id.org/openstreetmap/terms#TrafficSignals", + Trunk = "https://w3id.org/openstreetmap/terms#Trunk", + TrunkLink = "https://w3id.org/openstreetmap/terms#TrunkLink", + Unclassified = "https://w3id.org/openstreetmap/terms#Unclassified", +} + +export default Highway; diff --git a/src/enums/OSMTags.ts b/src/enums/OSMTags.ts new file mode 100644 index 00000000..d9454e13 --- /dev/null +++ b/src/enums/OSMTags.ts @@ -0,0 +1,25 @@ +import { OSM } from "../uri/constants"; +import URI from "../uri/uri"; + +export default function getOsmTagMapping() { + const result = {}; + + result[URI.inNS(OSM, "access")] = "accessRestrictions"; + result[URI.inNS(OSM, "bicycle")] = "bicycleAccessRestrictions"; + result[URI.inNS(OSM, "construction")] = "constructionKind"; + result[URI.inNS(OSM, "crossing")] = "crossingKind"; + result[URI.inNS(OSM, "cycleway")] = "cyclewayKind"; + result[URI.inNS(OSM, "footway")] = "footwayKind"; + result[URI.inNS(OSM, "highway")] = "highwayKind"; + result[URI.inNS(OSM, "maxspeed")] = "maxSpeed"; + result[URI.inNS(OSM, "motor_vehicle")] = "motorVehicleAccessRestrictions"; + result[URI.inNS(OSM, "motorcar")] = "motorcarAccessRestrictions"; + result[URI.inNS(OSM, "oneway_bicycle")] = "onewayBicycleKind"; + result[URI.inNS(OSM, "oneway")] = "onewayKind"; + result[URI.inNS(OSM, "smoothness")] = "smoothnessKind"; + result[URI.inNS(OSM, "surface")] = "surfaceKind"; + result[URI.inNS(OSM, "tracktype")] = "trackType"; + result[URI.inNS(OSM, "vehicle")] = "vehicleAccessRestrictions"; + + return result; +} diff --git a/src/enums/Oneway.ts b/src/enums/Oneway.ts new file mode 100644 index 00000000..cc993d8a --- /dev/null +++ b/src/enums/Oneway.ts @@ -0,0 +1,7 @@ +enum Oneway { + InReverseOrder = "https://w3id.org/openstreetmap/terms#InReverseOrder", + BiDirectional = "https://w3id.org/openstreetmap/terms#BiDirectional", + InOrder = "https://w3id.org/openstreetmap/terms#BiDirectional", +} + +export default Oneway; diff --git a/src/enums/RoutingPhase.ts b/src/enums/RoutingPhase.ts new file mode 100644 index 00000000..fcea3fbc --- /dev/null +++ b/src/enums/RoutingPhase.ts @@ -0,0 +1,6 @@ +enum RoutingPhase { + Base = "base", + Transit = "transit", +} + +export default RoutingPhase; diff --git a/src/enums/Smoothness.ts b/src/enums/Smoothness.ts new file mode 100644 index 00000000..8221004b --- /dev/null +++ b/src/enums/Smoothness.ts @@ -0,0 +1,12 @@ +enum Smoothness { + Bad = "https://w3id.org/openstreetmap/terms#Bad", + Excellent = "https://w3id.org/openstreetmap/terms#Excellent", + Good = "https://w3id.org/openstreetmap/terms#Good", + Horrible = "https://w3id.org/openstreetmap/terms#Horrible", + Impassable = "https://w3id.org/openstreetmap/terms#Impassable", + Intermediate = "https://w3id.org/openstreetmap/terms#Intermediate", + VeryBad = "https://w3id.org/openstreetmap/terms#VeryBad", + VeryHorrible = "https://w3id.org/openstreetmap/terms#VeryHorrible", +} + +export default Smoothness; diff --git a/src/enums/Surface.ts b/src/enums/Surface.ts new file mode 100644 index 00000000..bd408db2 --- /dev/null +++ b/src/enums/Surface.ts @@ -0,0 +1,22 @@ +enum Surface { + Asphalt = "https://w3id.org/openstreetmap/terms#Asphalt", + Cobblestone = "https://w3id.org/openstreetmap/terms#Cobblestone", + Compacted = "https://w3id.org/openstreetmap/terms#Compacted", + Concrete = "https://w3id.org/openstreetmap/terms#Concrete", + Dirt = "https://w3id.org/openstreetmap/terms#Dirt", + FineGravel = "https://w3id.org/openstreetmap/terms#FineGravel", + Grass = "https://w3id.org/openstreetmap/terms#Grass", + Gravel = "https://w3id.org/openstreetmap/terms#Gravel", + Ground = "https://w3id.org/openstreetmap/terms#Ground", + Mud = "https://w3id.org/openstreetmap/terms#Mud", + Paved = "https://w3id.org/openstreetmap/terms#Paved", + PavingStones = "https://w3id.org/openstreetmap/terms#PavingStones", + Pebblestone = "https://w3id.org/openstreetmap/terms#Pebblestone", + Sand = "https://w3id.org/openstreetmap/terms#Sand", + Sett = "https://w3id.org/openstreetmap/terms#Sett", + UnhewnCobblestone = "https://w3id.org/openstreetmap/terms#UnhewnCobblestone", + Unpaved = "https://w3id.org/openstreetmap/terms#Unpaved", + Wood = "https://w3id.org/openstreetmap/terms#Wood", +} + +export default Surface; diff --git a/src/enums/TrackType.ts b/src/enums/TrackType.ts new file mode 100644 index 00000000..0ad67020 --- /dev/null +++ b/src/enums/TrackType.ts @@ -0,0 +1,9 @@ +enum TrackType { + Grade1 = "https://w3id.org/openstreetmap/terms#Grade1", + Grade2 = "https://w3id.org/openstreetmap/terms#Grade2", + Grade3 = "https://w3id.org/openstreetmap/terms#Grade3", + Grade4 = "https://w3id.org/openstreetmap/terms#Grade4", + Grade5 = "https://w3id.org/openstreetmap/terms#Grade5", +} + +export default TrackType; diff --git a/src/enums/TravelMode.ts b/src/enums/TravelMode.ts index eba28087..693825cf 100644 --- a/src/enums/TravelMode.ts +++ b/src/enums/TravelMode.ts @@ -2,6 +2,7 @@ enum TravelMode { Train = "train", Bus = "bus", Walking = "walking", + Profile = "profile", // this could be more specific, maybe replace this enum with a data class } export default TravelMode; diff --git a/src/errors/InvalidQueryError.ts b/src/errors/InvalidQueryError.ts index 13339a13..2a6df36d 100644 --- a/src/errors/InvalidQueryError.ts +++ b/src/errors/InvalidQueryError.ts @@ -1,4 +1,4 @@ -import EventType from "../enums/EventType"; +import EventType from "../events/EventType"; export default class InvalidQueryError extends Error { public eventType = EventType.InvalidQuery; diff --git a/src/events/EventBus.ts b/src/events/EventBus.ts new file mode 100644 index 00000000..e5f462bb --- /dev/null +++ b/src/events/EventBus.ts @@ -0,0 +1,103 @@ +import { EventEmitter } from "events"; +import { injectable } from "inversify"; + +/** + * Proxies an internal EventEmitter (instead of extending EventEmitter) because + * ´decorate(injectable(), EventEmitter)´ causes errors when running tests in Jest + */ +@injectable() +export default class EventBus implements EventEmitter { + public static getInstance(): EventBus { + if (!EventBus.instance) { + EventBus.instance = new EventBus(); + } + + return EventBus.instance; + } + + private static instance: EventBus; + private emitter: EventEmitter; + + private constructor() { + this.emitter = new EventEmitter(); + } + + public eventNames(): Array<(string | symbol)> { + return this.emitter.eventNames(); + } + + // tslint:disable-next-line: ban-types + public rawListeners(event: string | symbol): Function[] { + return this.emitter.rawListeners(event); + } + + public getMaxListeners(): number { + return this.emitter.getMaxListeners(); + } + + public off(event: string | symbol, listener: (...args: any[]) => void): this { + this.emitter.off(event, listener); + + return this; + } + + public prependOnceListener(event: string | symbol, listener: (...args: any[]) => void): this { + this.emitter.prependOnceListener(event, listener); + + return this; + } + + public prependListener(event: string | symbol, listener: (...args: any[]) => void): this { + this.emitter.prependListener(event, listener); + + return this; + } + + public addListener(type: string | symbol, listener: any): this { + this.emitter.addListener(type, listener); + + return this; + } + + public emit(type: string | symbol, ...args: any[]): boolean { + return this.emitter.emit(type, ...args); + } + + public listenerCount(type: string | symbol): number { + return this.emitter.listenerCount(type); + } + + public listeners(type: string | symbol): any[] { + return this.emitter.listeners(type); + } + + public on(type: string | symbol, listener: any): this { + this.emitter.on(type, listener); + + return this; + } + + public once(type: string | symbol, listener: any): this { + this.emitter.once(type, listener); + + return this; + } + + public removeAllListeners(type?: string | symbol): this { + this.emitter.removeAllListeners(type); + + return this; + } + + public removeListener(type: string | symbol, listener: any): this { + this.emitter.removeListener(type, listener); + + return this; + } + + public setMaxListeners(n: number): this { + this.emitter.setMaxListeners(n); + + return this; + } +} diff --git a/src/enums/EventType.ts b/src/events/EventType.ts similarity index 79% rename from src/enums/EventType.ts rename to src/events/EventType.ts index ba92ca51..1b03246a 100644 --- a/src/enums/EventType.ts +++ b/src/events/EventType.ts @@ -11,10 +11,16 @@ enum EventType { ConnectionPrefetch = "connection-prefetch", ConnectionIteratorView = "connection-iterator-view", + FetchTile = "fetch-tile", + PointReached = "point-reached", + ConnectionScan = "connection-scan", FinalReachableStops = "final-reachable-stops", InitialReachableStops = "initial-reachable-stops", AddedNewTransferProfile = "added-new-transfer-profile", + + ReachableStop = "ReachableStop", + ReachableTile = "ReachableTile", } export default EventType; diff --git a/src/fetcher/LDFetch.ts b/src/fetcher/LDFetch.ts index 71ab21d2..4cdd6dbf 100644 --- a/src/fetcher/LDFetch.ts +++ b/src/fetcher/LDFetch.ts @@ -1,9 +1,9 @@ -import { inject, injectable } from "inversify"; +import { EventEmitter } from "events"; +import { injectable } from "inversify"; import LDFetchBase from "ldfetch"; import { Triple } from "rdf-js"; -import Context from "../Context"; -import EventType from "../enums/EventType"; -import TYPES from "../types"; +import EventBus from "../events/EventBus"; +import EventType from "../events/EventType"; export interface ILDFetchResponse { triples: Triple[]; @@ -17,15 +17,13 @@ export interface ILDFetchResponse { */ @injectable() export default class LDFetch implements LDFetchBase { - private context: Context; + private eventBus: EventEmitter; private ldFetchBase: LDFetchBase; private httpStartTimes: { [url: string]: Date }; - constructor( - @inject(TYPES.Context) context: Context, - ) { + constructor() { this.ldFetchBase = new LDFetchBase({ headers: { Accept: "application/ld+json" } }); - this.context = context; + this.eventBus = EventBus.getInstance(); this.setupEvents(); } @@ -42,7 +40,7 @@ export default class LDFetch implements LDFetchBase { this.ldFetchBase.on("response", (url) => { const duration = (new Date()).getTime() - this.httpStartTimes[url].getTime(); - this.context.emit(EventType.LDFetchGet, url, duration); + this.eventBus.emit(EventType.LDFetchGet, url, duration); }); } } diff --git a/src/fetcher/connections/BackwardConnectionIterator.ts b/src/fetcher/connections/BackwardConnectionIterator.ts new file mode 100644 index 00000000..ca257e19 --- /dev/null +++ b/src/fetcher/connections/BackwardConnectionIterator.ts @@ -0,0 +1,74 @@ +import { AsyncIterator } from "asynciterator"; +import IConnection from "../../entities/connections/connections"; +import { LinkedConnectionsPage } from "../../entities/connections/page"; +import IConnectionsIteratorOptions from "./IConnectionsIteratorOptions"; +import IConnectionsProvider from "./IConnectionsProvider"; + +export default class BackwardConnectionIterator extends AsyncIterator { + + private connectionsProvider: IConnectionsProvider; + private options: IConnectionsIteratorOptions; + + private waiting: boolean; + private currentPage: LinkedConnectionsPage; + private currentIndex: number; + + constructor( + provider: IConnectionsProvider, + options: IConnectionsIteratorOptions, + beginUrl: string, + ) { + super(); + + this.connectionsProvider = provider; + this.options = options; + this.waiting = false; + this.fetchPage(beginUrl); + } + + public async fetchPage(url) { + if (!this.waiting) { + // start fetching a page + this.readable = false; + this.waiting = true; + this.currentPage = null; + this.currentPage = await this.connectionsProvider.getByUrl(url); + this.waiting = false; + this.currentIndex = this.currentPage.getConnections().length - 1; + this.readable = true; + + if (this.currentPage.getPreviousPageId()) { + // prefetch the next page to reduce IO + this.connectionsProvider.getByUrl(this.currentPage.getPreviousPageId()); + } + } + } + + public read(): IConnection { + if (this.closed) { + return undefined; + } + + if (this.waiting) { + // waiting for the next page to be fetched + this.readable = false; + return undefined; + } + + if (this.currentIndex < 0) { + // end of this page, fetch the next one + this.fetchPage(this.currentPage.getPreviousPageId()); + return undefined; + } + + const item = this.currentPage.getConnections()[this.currentIndex]; + this.currentIndex -= 1; + + if (this.options.lowerBoundDate && item.departureTime < this.options.lowerBoundDate) { + // no more relevant connections + this.close(); + } + + return item; + } +} diff --git a/src/fetcher/connections/ConnectionsFetcherRaw.ts b/src/fetcher/connections/ConnectionsFetcherRaw.ts new file mode 100644 index 00000000..99224593 --- /dev/null +++ b/src/fetcher/connections/ConnectionsFetcherRaw.ts @@ -0,0 +1,82 @@ +import fetch from "cross-fetch"; +import { injectable } from "inversify"; +import IConnection from "../../entities/connections/connections"; +import { LinkedConnectionsPage } from "../../entities/connections/page"; +import TravelMode from "../../enums/TravelMode"; +import EventBus from "../../events/EventBus"; +import EventType from "../../events/EventType"; +import IConnectionsFetcher from "./IConnectionsFetcher"; + +@injectable() +// tslint:disable: no-string-literal +export default class ConnectionsFetcherRaw implements IConnectionsFetcher { + protected travelMode: TravelMode; + + public setTravelMode(travelMode: TravelMode) { + this.travelMode = travelMode; + } + + public async get(url: string): Promise { + const beginTime = new Date(); + + const response = await fetch(url); + const responseText = await response.text(); + if (response.status !== 200) { + EventBus.getInstance().emit(EventType.Warning, `${url} responded with status code ${response.status}`); + } + if (response.status === 200 && responseText) { + const blob = JSON.parse(responseText); + + const connections: IConnection[] = []; + + for (const entity of blob["@graph"]) { + const connectionId = entity["@id"]; + + const arrivalTime = new Date(entity["arrivalTime"]); + const arrivalStop = entity["arrivalStop"]; + const arrivalDelay = entity["arrivalDelay"] ? parseFloat(entity["arrivalDelay"]) : 0; + + const departureTime = new Date(entity["departureTime"]); + const departureStop = entity["departureStop"]; + const departureDelay = entity["departureDelay"] ? parseFloat(entity["departureDelay"]) : 0; + + const nextConnection = entity["nextConnection"] || []; + const tripId = entity["gtfs:trip"] || null; + + const route = entity["gtfs:route"] || null; + const dropOffType = entity["gtfs:dropOffType"]; + const pickupType = entity["gtfs:pickupType"]; + const headsign = entity["direction"] || null; + const connection: IConnection = { + id: connectionId, + travelMode: this.travelMode, + arrivalTime, + arrivalStop, + arrivalDelay, + departureTime, + departureStop, + departureDelay, + nextConnection, + tripId, + route, + dropOffType, + pickupType, + headsign, + }; + + connections.push(connection); + } + + const pageId = blob["@id"]; + const nextPageUrl = blob["hydra:next"]; + const previousPageUrl = blob["hydra:previous"]; + + const duration = (new Date()).getTime() - beginTime.getTime(); + EventBus.getInstance().emit(EventType.LDFetchGet, url, duration); + + return new LinkedConnectionsPage(pageId, connections, previousPageUrl, nextPageUrl); + } else { + return new LinkedConnectionsPage(url, [], undefined, undefined); + } + } +} diff --git a/src/fetcher/connections/ConnectionsProviderDefault.ts b/src/fetcher/connections/ConnectionsProviderDefault.ts new file mode 100644 index 00000000..7c2abd1b --- /dev/null +++ b/src/fetcher/connections/ConnectionsProviderDefault.ts @@ -0,0 +1,67 @@ +import { AsyncIterator } from "asynciterator"; +import { inject, injectable } from "inversify"; +import Catalog from "../../Catalog"; +import IConnection from "../../entities/connections/connections"; +import { ILinkedConnectionsPageIndex, LinkedConnectionsPage } from "../../entities/connections/page"; +import TYPES, { ConnectionsFetcherFactory } from "../../types"; +import BackwardConnectionIterator from "./BackwardConnectionIterator"; +import ForwardConnectionIterator from "./ForwardConnectionIterator"; +import IConnectionsFetcher from "./IConnectionsFetcher"; +import IConnectionsIteratorOptions from "./IConnectionsIteratorOptions"; +import IConnectionsProvider from "./IConnectionsProvider"; + +@injectable() +export default class ConnectionsProviderDefault implements IConnectionsProvider { + + protected fetcher: IConnectionsFetcher; + protected pages: ILinkedConnectionsPageIndex = {}; + protected accessUrl: string; + + constructor( + @inject(TYPES.ConnectionsFetcherFactory) connectionsFetcherFactory: ConnectionsFetcherFactory, + @inject(TYPES.Catalog) catalog: Catalog, + ) { + if (catalog.connectionsSourceConfigs.length > 1) { + throw (new Error("Use the ConnectionsProviderMerge if you have multiple connections sources")); + } + + const { accessUrl, travelMode } = catalog.connectionsSourceConfigs[0]; + this.accessUrl = accessUrl; + this.fetcher = connectionsFetcherFactory(travelMode); + } + + public async getByUrl(url: string): Promise { + if (!this.pages[url]) { + this.pages[url] = this.fetcher.get(url); + } + + return await this.pages[url]; + } + + public async getByTime(date: Date): Promise { + // TODO, look up in the index -- use lower/upper bounds of each page + const url = this.getIdForTime(date); + return this.getByUrl(url); + } + + public getIdForTime(date: Date): string { + return `${this.accessUrl}?departureTime=${date.toISOString()}`; + } + + public prefetchConnections(lowerBound: Date, upperBound: Date): void { + // TODO + return; + } + + public createIterator(options: IConnectionsIteratorOptions): AsyncIterator { + if (options.backward) { + const beginTime = options.upperBoundDate; + const beginUrl = this.getIdForTime(beginTime); + return new BackwardConnectionIterator(this, options, beginUrl); + } else { + const beginTime = options.lowerBoundDate; + const beginUrl = this.getIdForTime(beginTime); + return new ForwardConnectionIterator(this, options, beginUrl); + } + } +} diff --git a/src/fetcher/connections/ConnectionsProviderMerge.ts b/src/fetcher/connections/ConnectionsProviderMerge.ts index 7e0fb64b..7f10e746 100644 --- a/src/fetcher/connections/ConnectionsProviderMerge.ts +++ b/src/fetcher/connections/ConnectionsProviderMerge.ts @@ -1,16 +1,14 @@ import { AsyncIterator } from "asynciterator"; import { inject, injectable } from "inversify"; import Catalog from "../../Catalog"; +import IConnection from "../../entities/connections/connections"; +import { LinkedConnectionsPage } from "../../entities/connections/page"; import TYPES, { ConnectionsFetcherFactory } from "../../types"; import MergeIterator from "../../util/iterators/MergeIterator"; -import IConnection from "./IConnection"; -import IConnectionsFetcher from "./IConnectionsFetcher"; +import ConnectionsProviderDefault from "./ConnectionsProviderDefault"; import IConnectionsIteratorOptions from "./IConnectionsIteratorOptions"; import IConnectionsProvider from "./IConnectionsProvider"; -/** - * Instantiates and merge sorts all registered connection fetchers - */ @injectable() export default class ConnectionsProviderMerge implements IConnectionsProvider { @@ -52,17 +50,18 @@ export default class ConnectionsProviderMerge implements IConnectionsProvider { return latestIndex; } - private options: IConnectionsIteratorOptions; - private connectionsFetchers: IConnectionsFetcher[]; + private defaultProviders: IConnectionsProvider[]; constructor( @inject(TYPES.ConnectionsFetcherFactory) connectionsFetcherFactory: ConnectionsFetcherFactory, @inject(TYPES.Catalog) catalog: Catalog, ) { - this.connectionsFetchers = []; + this.defaultProviders = []; for (const { accessUrl, travelMode } of catalog.connectionsSourceConfigs) { - this.connectionsFetchers.push(connectionsFetcherFactory(accessUrl, travelMode)); + const subCatalog = new Catalog(); + subCatalog.addConnectionsSource(accessUrl, travelMode); + this.defaultProviders.push(new ConnectionsProviderDefault(connectionsFetcherFactory, subCatalog)); } } @@ -70,12 +69,11 @@ export default class ConnectionsProviderMerge implements IConnectionsProvider { return; } - public createIterator(): AsyncIterator { + public createIterator(options: IConnectionsIteratorOptions): AsyncIterator { + const iterators = this.defaultProviders + .map((provider) => provider.createIterator(options)); - const iterators = this.connectionsFetchers - .map((fetcher) => fetcher.createIterator()); - - const selector = this.options.backward ? + const selector = options.backward ? ConnectionsProviderMerge.backwardsConnectionsSelector : ConnectionsProviderMerge.forwardsConnectionSelector; @@ -83,10 +81,12 @@ export default class ConnectionsProviderMerge implements IConnectionsProvider { return new MergeIterator(iterators, selector, true); } - public setIteratorOptions(options: IConnectionsIteratorOptions): void { - this.options = options; - this.connectionsFetchers.forEach((fetcher) => { - fetcher.setIteratorOptions(options); - }); + public getByUrl(url: string): Promise { + // TODO, if needed this can delegate the call to one of the sub providers + throw new Error("Not implemented yet"); + } + + public getByTime(date: Date): Promise { + throw new Error("Method not implemented because the semantics would be ambiguous."); } } diff --git a/src/fetcher/connections/ConnectionsProviderPassthrough.ts b/src/fetcher/connections/ConnectionsProviderPassthrough.ts deleted file mode 100644 index c6718081..00000000 --- a/src/fetcher/connections/ConnectionsProviderPassthrough.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { AsyncIterator } from "asynciterator"; -import { inject, injectable } from "inversify"; -import Catalog from "../../Catalog"; -import TYPES, { ConnectionsFetcherFactory } from "../../types"; -import IConnection from "./IConnection"; -import IConnectionsFetcher from "./IConnectionsFetcher"; -import IConnectionsIteratorOptions from "./IConnectionsIteratorOptions"; -import IConnectionsProvider from "./IConnectionsProvider"; - -/** - * Passes through any method calls to a *single* [[IConnectionsFetcher]], the first if there are multiple source configs - * This provider is most/only useful if there is only one fetcher - */ -@injectable() -export default class ConnectionsProviderPassthrough implements IConnectionsProvider { - - private readonly connectionsFetcher: IConnectionsFetcher; - - constructor( - @inject(TYPES.ConnectionsFetcherFactory) connectionsFetcherFactory: ConnectionsFetcherFactory, - @inject(TYPES.Catalog) catalog: Catalog, - ) { - const { accessUrl, travelMode } = catalog.connectionsSourceConfigs[0]; - - this.connectionsFetcher = connectionsFetcherFactory(accessUrl, travelMode); - } - - public prefetchConnections(): void { - this.connectionsFetcher.prefetchConnections(); - } - - public createIterator(): AsyncIterator { - return this.connectionsFetcher.createIterator(); - } - - public setIteratorOptions(options: IConnectionsIteratorOptions): void { - this.connectionsFetcher.setIteratorOptions(options); - } -} diff --git a/src/fetcher/connections/ForwardConnectionIterator.ts b/src/fetcher/connections/ForwardConnectionIterator.ts new file mode 100644 index 00000000..0954b3fd --- /dev/null +++ b/src/fetcher/connections/ForwardConnectionIterator.ts @@ -0,0 +1,74 @@ +import { AsyncIterator } from "asynciterator"; +import IConnection from "../../entities/connections/connections"; +import { LinkedConnectionsPage } from "../../entities/connections/page"; +import IConnectionsIteratorOptions from "./IConnectionsIteratorOptions"; +import IConnectionsProvider from "./IConnectionsProvider"; + +export default class ForwardConnectionIterator extends AsyncIterator { + + private connectionsProvider: IConnectionsProvider; + private options: IConnectionsIteratorOptions; + + private waiting: boolean; + private currentPage: LinkedConnectionsPage; + private currentIndex: number; + + constructor( + provider: IConnectionsProvider, + options: IConnectionsIteratorOptions, + beginUrl: string, + ) { + super(); + + this.connectionsProvider = provider; + this.options = options; + this.waiting = false; + this.fetchPage(beginUrl); + } + + public async fetchPage(url) { + if (!this.waiting) { + // start fetching a page + this.readable = false; + this.waiting = true; + this.currentPage = null; + this.currentPage = await this.connectionsProvider.getByUrl(url); + this.waiting = false; + this.currentIndex = 0; + this.readable = true; + + if (this.currentPage.getNextPageId()) { + // prefetch the next page to reduce IO + this.connectionsProvider.getByUrl(this.currentPage.getNextPageId()); + } + } + } + + public read(): IConnection { + if (this.closed) { + return undefined; + } + + if (this.waiting) { + // waiting for the next page to be fetched + this.readable = false; + return undefined; + } + + if (this.currentIndex >= this.currentPage.getConnections().length) { + // end of this page, fetch the next one + this.fetchPage(this.currentPage.getNextPageId()); + return undefined; + } + + const item = this.currentPage.getConnections()[this.currentIndex]; + this.currentIndex += 1; + + if (this.options.upperBoundDate && item.departureTime > this.options.upperBoundDate) { + // no more relevant connections + this.close(); + } + + return item; + } +} diff --git a/src/fetcher/connections/IConnectionsFetcher.ts b/src/fetcher/connections/IConnectionsFetcher.ts index 194b6e8d..08234d3f 100644 --- a/src/fetcher/connections/IConnectionsFetcher.ts +++ b/src/fetcher/connections/IConnectionsFetcher.ts @@ -1,8 +1,7 @@ -import IConnectionsProvider from "./IConnectionsProvider"; +import { LinkedConnectionsPage } from "../../entities/connections/page"; +import TravelMode from "../../enums/TravelMode"; -/** - * Entry point for fetching linked connections ([[IConnection]]s) - * Serves as interface for dependency injection, so all implementations should have @injectable() decorator - */ -export default interface IConnectionsFetcher extends IConnectionsProvider { +export default interface IConnectionsFetcher { + get(url: string): Promise; + setTravelMode(travelMode: TravelMode): void; } diff --git a/src/fetcher/connections/IConnectionsProvider.ts b/src/fetcher/connections/IConnectionsProvider.ts index 054c1c53..d6e7e59b 100644 --- a/src/fetcher/connections/IConnectionsProvider.ts +++ b/src/fetcher/connections/IConnectionsProvider.ts @@ -1,14 +1,12 @@ import { AsyncIterator } from "asynciterator"; -import IConnection from "./IConnection"; +import IConnection from "../../entities/connections/connections"; +import { LinkedConnectionsPage } from "../../entities/connections/page"; import IConnectionsIteratorOptions from "./IConnectionsIteratorOptions"; -/** - * A IConnectionsProvider serves as interface to other classes that want to use [[IConnection]] instances - * It does this by acting as a transparent proxy between the user class and the configured [[IConnectionFetcher]] - * instances - */ export default interface IConnectionsProvider { - prefetchConnections: () => void; - createIterator: () => AsyncIterator; - setIteratorOptions: (options: IConnectionsIteratorOptions) => void; + prefetchConnections(lowerBound: Date, upperBound: Date): void; + createIterator(options: IConnectionsIteratorOptions): AsyncIterator; + + getByUrl(url: string): Promise; + getByTime(date: Date): Promise; } diff --git a/src/fetcher/connections/hydra/ConnectionsPageParser.ts b/src/fetcher/connections/hydra/ConnectionsPageParser.ts deleted file mode 100644 index 084d34f2..00000000 --- a/src/fetcher/connections/hydra/ConnectionsPageParser.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { Triple } from "rdf-js"; -import DropOffType from "../../../enums/DropOffType"; -import PickupType from "../../../enums/PickupType"; -import TravelMode from "../../../enums/TravelMode"; -import Rdf from "../../../util/Rdf"; -import Units from "../../../util/Units"; -import IConnection from "../IConnection"; - -interface IEntity { -} - -interface IEntityMap { - [subject: string]: IEntity; -} - -/** - * Parses the given array of triples into an array of [[IConnection]]s - * It first builds up an array of entities, where each item is a 'subject', - * its properties are 'predicates' and values are 'objects' - * After, it filters those entities by type, only leaving 'linked connections'. - */ -export default class ConnectionsPageParser { - private readonly documentIri: string; - private readonly triples: Triple[]; - - constructor(documentIri: string, triples: Triple[]) { - this.documentIri = documentIri; - this.triples = triples; - } - - public getConnections(travelMode: TravelMode): IConnection[] { - // group all entities together and - const entities = this.getEntities(this.triples); - - // Find all Connections - let connections = this.filterConnectionsFromEntities(entities); - - // Add travel mode - connections = connections.map((connection: IConnection) => { - connection.travelMode = travelMode; - return connection; - }); - - // Sort connections by departure time - return connections.sort((connectionA, connectionB) => { - return connectionA.departureTime.valueOf() - connectionB.departureTime.valueOf(); - }); - } - - private filterConnectionsFromEntities(entities: IEntityMap): IConnection[] { - const typePredicate = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"; - - // building block 2: every lc:Connection entity is taken from the page and processed - return Object.values(entities) - .filter((entity: IEntity) => - entity[typePredicate] && entity[typePredicate] === "http://semweb.mmlab.be/ns/linkedconnections#Connection", - ) as IConnection[]; - } - - private transformPredicate(triple: Triple): Triple { - return Rdf.transformPredicate({ - "http://semweb.mmlab.be/ns/linkedconnections#departureTime": "departureTime", - "http://semweb.mmlab.be/ns/linkedconnections#departureDelay": "departureDelay", - "http://semweb.mmlab.be/ns/linkedconnections#arrivalDelay": "arrivalDelay", - "http://semweb.mmlab.be/ns/linkedconnections#arrivalTime": "arrivalTime", - "http://semweb.mmlab.be/ns/linkedconnections#departureStop": "departureStop", - "http://semweb.mmlab.be/ns/linkedconnections#arrivalStop": "arrivalStop", - "http://semweb.mmlab.be/ns/linkedconnections#nextConnection": "nextConnection", - - "http://vocab.gtfs.org/terms#route": "gtfs:route", - "http://vocab.gtfs.org/terms#trip": "gtfs:trip", - "http://vocab.gtfs.org/terms#dropOffType": "gtfs:dropOffType", - "http://vocab.gtfs.org/terms#pickupType": "gtfs:pickupType", - "http://vocab.gtfs.org/terms#headsign": "gtfs:headsign", - }, triple); - } - - private transformObject(triple: Triple): Triple { - - if (triple.predicate.value === "gtfs:dropOffType") { - return Rdf.transformObject({ - "http://vocab.gtfs.org/terms#Regular": DropOffType.Regular, - "http://vocab.gtfs.org/terms#NotAvailable": DropOffType.NotAvailable, - "http://vocab.gtfs.org/terms#MustPhone": DropOffType.MustPhone, - "http://vocab.gtfs.org/terms#MustCoordinateWithDriver": DropOffType.MustCoordinateWithDriver, - }, triple); - } - - if (triple.predicate.value === "gtfs:pickupType") { - return Rdf.transformObject({ - "http://vocab.gtfs.org/terms#Regular": PickupType.Regular, - "http://vocab.gtfs.org/terms#NotAvailable": PickupType.NotAvailable, - "http://vocab.gtfs.org/terms#MustPhone": PickupType.MustPhone, - "http://vocab.gtfs.org/terms#MustCoordinateWithDriver": PickupType.MustCoordinateWithDriver, - }, triple); - } - - return triple; - } - - private getEntities(triples: Triple[]): IEntityMap { - - return triples.reduce((entities: IEntityMap, triple: Triple) => { - triple = this.transformObject(this.transformPredicate(triple)); - - const { subject: { value: subject }, predicate: { value: predicate }, object: { value: object } } = triple; - let newObject; - - if (triple.predicate.value === "departureTime" || triple.predicate.value === "arrivalTime") { - newObject = new Date(triple.object.value); - } - - if (triple.predicate.value === "departureDelay" || triple.predicate.value === "arrivalDelay") { - newObject = Units.fromSeconds(parseInt(triple.object.value, 10)); - } - - if (!entities[subject]) { - entities[subject] = { - id: subject, - }; - } - - // nextConnection should be an array - // todo: test once nextConnection becomes available - if (predicate === "nextConnection") { - entities[subject][predicate] = entities[subject][predicate] || []; - entities[subject][predicate].push(object); - - } else { - entities[subject][predicate] = newObject || object; - } - - return entities; - }, {}); - } -} diff --git a/src/fetcher/connections/hydra/HydraPageIterator.ts b/src/fetcher/connections/hydra/HydraPageIterator.ts deleted file mode 100644 index ea962292..00000000 --- a/src/fetcher/connections/hydra/HydraPageIterator.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { BufferedIterator } from "asynciterator"; -import LdFetch from "ldfetch"; -import UriTemplate from "uritemplate"; -import HydraPageParser2 from "./HydraPageParser"; -import IHydraPage from "./IHydraPage"; -import IHydraPageIteratorConfig from "./IHydraPageIteratorConfig"; - -export default class HydraPageIterator extends BufferedIterator { - private readonly baseUrl: string; - private readonly ldFetch: LdFetch; - private readonly config: IHydraPageIteratorConfig; - - private currentPage: IHydraPage; - - constructor( - baseUrl: string, - ldFetch: LdFetch, - config: IHydraPageIteratorConfig, - ) { - super({ - autoStart: true, - }); - - this.baseUrl = baseUrl; - this.ldFetch = ldFetch; - this.config = config; - } - - public _begin(done: () => void): void { - this.ldFetch.get(this.baseUrl) - .then((response) => { - const parser = new HydraPageParser2(response.triples); - const searchTemplate: UriTemplate = parser.getSearchTemplate(); - - const firstPageIri = searchTemplate.expand(this.config.initialTemplateVariables); - - this.loadPage(firstPageIri) - .then(() => done()); - }); - } - - public _read(count: number, done: () => void): void { - - const pageIri = this.config.backward ? - this.currentPage.previousPageIri : this.currentPage.nextPageIri; - - this.loadPage(pageIri) - .then(() => done()); - } - - private async loadPage(url: string) { - await this.ldFetch.get(url) - .then((response) => { - - const parser = new HydraPageParser2(response.triples); - const page = parser.getPage(0); - - if (this.config.backward) { - page.previousPageIri = parser.getPreviousPageIri(); - - } else { - page.nextPageIri = parser.getNextPageIri(); - } - - this.currentPage = page; - this._push(this.currentPage); - }); - } -} diff --git a/src/fetcher/connections/hydra/HydraPageParser.ts b/src/fetcher/connections/hydra/HydraPageParser.ts deleted file mode 100644 index 45ac8261..00000000 --- a/src/fetcher/connections/hydra/HydraPageParser.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { Triple } from "rdf-js"; -import UriTemplate from "uritemplate"; -import Rdf from "../../../util/Rdf"; -import IHydraPage from "./IHydraPage"; - -/** - * Searches the given array of triples for hydra meta data, like the search template and next/previous page iris - * Also allows getting the contained [[IHydraPage]], which holds an array of [[IConnection]]s - */ -export default class HydraPageParser { - private readonly triples: Triple[]; - private readonly documentIri: string; - - constructor(triples: Triple[]) { - this.triples = triples; - this.documentIri = this.getDocumentIri(); - } - - public getPage(index: number): IHydraPage { - return { - index, - documentIri: this.documentIri, - triples: this.triples, - }; - } - - public getSearchTemplate(): UriTemplate { - const searchTriple = this.triples.find( - Rdf.matchesTriple(this.documentIri, "http://www.w3.org/ns/hydra/core#search", null), - ); - - const templateTriple = this.triples.find( - Rdf.matchesTriple(searchTriple.object.value, "http://www.w3.org/ns/hydra/core#template", null), - ); - - const template = templateTriple.object.value; - return UriTemplate.parse(template); - } - - public getNextPageIri(): string { - const nextPageTriple: Triple = this.triples.find( - Rdf.matchesTriple(this.documentIri, "http://www.w3.org/ns/hydra/core#next", null), - ); - - if (nextPageTriple && nextPageTriple.object.value.substr(0, 4) === "http") { - return nextPageTriple.object.value; - } - } - - public getPreviousPageIri(): string { - const previousPageTriple: Triple = this.triples.find( - Rdf.matchesTriple(this.documentIri, "http://www.w3.org/ns/hydra/core#previous", null), - ); - - if (previousPageTriple && previousPageTriple.object.value.substr(0, 4) === "http") { - return previousPageTriple.object.value; - } - } - - private getDocumentIri(): string { - // Type can be either http://www.w3.org/ns/hydra/core#PartialCollectionView - // or http://www.w3.org/ns/hydra/core#PagedCollection - - let typeTriple = this.triples.find( - Rdf.matchesTriple( - null, - "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", - "http://www.w3.org/ns/hydra/core#PartialCollectionView", - ), - ); - - if (!typeTriple) { - typeTriple = this.triples.find( - Rdf.matchesTriple( - null, - "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", - "http://www.w3.org/ns/hydra/core#PagedCollection", - ), - ); - } - - if (!typeTriple) { - throw new Error("Hydra page doesn`t have type triple"); - } - - return typeTriple.subject.value; - } -} diff --git a/src/fetcher/connections/hydra/IHydraPage.ts b/src/fetcher/connections/hydra/IHydraPage.ts deleted file mode 100644 index a629686a..00000000 --- a/src/fetcher/connections/hydra/IHydraPage.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Triple } from "rdf-js"; - -export default interface IHydraPage { - index: number; - documentIri: string; - nextPageIri?: string; - previousPageIri?: string; - triples: Triple[]; -} diff --git a/src/fetcher/connections/hydra/IHydraPageIteratorConfig.ts b/src/fetcher/connections/hydra/IHydraPageIteratorConfig.ts deleted file mode 100644 index 871acfe8..00000000 --- a/src/fetcher/connections/hydra/IHydraPageIteratorConfig.ts +++ /dev/null @@ -1,4 +0,0 @@ -export default interface IHydraPageIteratorConfig { - backward: boolean; - initialTemplateVariables: object; -} diff --git a/src/fetcher/connections/lazy/ConnectionsFetcherLazy.ts b/src/fetcher/connections/lazy/ConnectionsFetcherLazy.ts deleted file mode 100644 index 8e36dbd6..00000000 --- a/src/fetcher/connections/lazy/ConnectionsFetcherLazy.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { AsyncIterator } from "asynciterator"; -import { inject, injectable } from "inversify"; -import LDFetch from "ldfetch"; -import TravelMode from "../../../enums/TravelMode"; -import TYPES from "../../../types"; -import IConnection from "../IConnection"; -import IConnectionsFetcher from "../IConnectionsFetcher"; -import IConnectionsIteratorOptions from "../IConnectionsIteratorOptions"; -import ConnectionsIteratorLazy from "./ConnectionsIteratorLazy"; - -/** - * Wraps the [[ConnectionsIteratorLazy]] - * @implements IConnectionsFetcher - */ -@injectable() -export default class ConnectionsFetcherLazy implements IConnectionsFetcher { - - protected readonly ldFetch: LDFetch; - protected options: IConnectionsIteratorOptions; - private travelMode: TravelMode; - private accessUrl: string; - - constructor(@inject(TYPES.LDFetch) ldFetch: LDFetch) { - this.ldFetch = ldFetch; - } - - public setTravelMode(travelMode: TravelMode) { - this.travelMode = travelMode; - } - - public setAccessUrl(accessUrl: string) { - this.accessUrl = accessUrl; - } - - public prefetchConnections(): void { - return; - } - - public createIterator(): AsyncIterator { - return new ConnectionsIteratorLazy( - this.accessUrl, - this.travelMode, - this.ldFetch, - this.options, - ); - } - - public setIteratorOptions(options: IConnectionsIteratorOptions): void { - this.options = options; - } -} diff --git a/src/fetcher/connections/lazy/ConnectionsIteratorLazy.test.ts b/src/fetcher/connections/lazy/ConnectionsIteratorLazy.test.ts deleted file mode 100644 index 4366f1ed..00000000 --- a/src/fetcher/connections/lazy/ConnectionsIteratorLazy.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -import "jest"; -import LdFetch from "ldfetch"; -import TravelMode from "../../../enums/TravelMode"; -import IConnection from "../IConnection"; -import IConnectionsIteratorOptions from "../IConnectionsIteratorOptions"; -import ConnectionsIteratorLazy from "./ConnectionsIteratorLazy"; - -const CONNECTIONS_TO_LOAD = 500; // Should be more than contained on first page - -test("[ConnectionsIteratorLazy] iterate forwards", (done) => { - jest.setTimeout(90000); - - const options: IConnectionsIteratorOptions = { - backward: false, - lowerBoundDate: new Date(2018, 10, 22, 10), - }; - const iterator = new ConnectionsIteratorLazy( - "https://graph.irail.be/sncb/connections", - TravelMode.Train, - new LdFetch(), - options, - ); - - let i = 0; - let lastConnection: IConnection; - - iterator.on("readable", () => { - lastConnection = iterator.read(); - let connection = iterator.read(); - - while (connection && i++ < CONNECTIONS_TO_LOAD) { - - expect(connection.departureTime.valueOf()).toBeGreaterThanOrEqual(lastConnection.departureTime.valueOf()); - - lastConnection = connection; - connection = iterator.read(); - } - - if (i >= CONNECTIONS_TO_LOAD) { - iterator.close(); - done(); - } - }); - -}); diff --git a/src/fetcher/connections/lazy/ConnectionsIteratorLazy.ts b/src/fetcher/connections/lazy/ConnectionsIteratorLazy.ts deleted file mode 100644 index d3c27ec3..00000000 --- a/src/fetcher/connections/lazy/ConnectionsIteratorLazy.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { ArrayIterator } from "asynciterator"; -import LdFetch from "ldfetch"; -import TravelMode from "../../../enums/TravelMode"; -import FlatMapIterator from "../../../util/iterators/FlatMapIterator"; -import ConnectionsPageParser from "../hydra/ConnectionsPageParser"; -import HydraPageIterator from "../hydra/HydraPageIterator"; -import IHydraPage from "../hydra/IHydraPage"; -import IHydraPageIteratorConfig from "../hydra/IHydraPageIteratorConfig"; -import IConnection from "../IConnection"; -import IConnectionsIteratorOptions from "../IConnectionsIteratorOptions"; - -/** - * Base class for fetching linked connections with LDFetch and letting the caller iterate over them asynchronously - * through implementing the AsyncIterator protocol. - * LDFetch returns documents as an array of RDF triples. - * The meta Hydra triples are used for paginating to the next or previous page. - * The triples that describe linked connections get deserialized to instances of [[IConnection]] - */ -export default class ConnectionsIteratorLazy extends FlatMapIterator { - constructor( - baseUrl: string, - travelMode: TravelMode, - ldFetch: LdFetch, - options: IConnectionsIteratorOptions, - ) { - const departureTimeDate = options.backward ? - options.upperBoundDate : options.lowerBoundDate; - - const pageIteratorConfig: IHydraPageIteratorConfig = { - backward: options.backward, - initialTemplateVariables: { - departureTime: departureTimeDate.toISOString(), - }, - }; - - const pageIterator = new HydraPageIterator(baseUrl, ldFetch, pageIteratorConfig); - const parsePageConnections = (page: IHydraPage) => { - const connectionsParser = new ConnectionsPageParser(page.documentIri, page.triples); - - const connections = connectionsParser.getConnections(travelMode); - - if (options.backward) { - connections.reverse(); - } - - return new ArrayIterator(connections); - }; - - super(pageIterator, parsePageConnections); - } -} diff --git a/src/fetcher/connections/prefetch/ConnectionsProviderPrefetch.ts b/src/fetcher/connections/prefetch/ConnectionsProviderPrefetch.ts deleted file mode 100644 index 694a96db..00000000 --- a/src/fetcher/connections/prefetch/ConnectionsProviderPrefetch.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { AsyncIterator } from "asynciterator"; -import { inject, injectable } from "inversify"; -import Catalog from "../../../Catalog"; -import Context from "../../../Context"; -import TYPES, { ConnectionsFetcherFactory } from "../../../types"; -import ConnectionsProviderMerge from "../ConnectionsProviderMerge"; -import IConnection from "../IConnection"; -import IConnectionsFetcher from "../IConnectionsFetcher"; -import IConnectionsIteratorOptions from "../IConnectionsIteratorOptions"; -import IConnectionsProvider from "../IConnectionsProvider"; -import ConnectionsStore from "./ConnectionsStore"; - -/** - * This connections provider implements the [[IConnectionsProvider.prefetchConnections]] method. - * When called, it asks an AsyncIterator from the instantiated [[IConnectionsFetcher]]. - * All items from that iterator get appended to a [[ConnectionsStore]] - * - * When [[IConnectionsProvider.createIterator]] is called, it returns an iterator *view* from the [[ConnectionsStore]] - */ -@injectable() -export default class ConnectionsProviderPrefetch implements IConnectionsProvider { - - private static MAX_CONNECTIONS = 20000; - - private readonly context: Context; - private readonly connectionsFetcher: IConnectionsFetcher; - private readonly connectionsStore: ConnectionsStore; - - private startedPrefetching: boolean; - private connectionsIterator: AsyncIterator; - private connectionsIteratorOptions: IConnectionsIteratorOptions; - - constructor( - @inject(TYPES.ConnectionsFetcherFactory) connectionsFetcherFactory: ConnectionsFetcherFactory, - @inject(TYPES.Catalog) catalog: Catalog, - @inject(TYPES.Context) context: Context, - ) { - - this.context = context; - - if (catalog.connectionsSourceConfigs.length > 1) { - this.connectionsFetcher = new ConnectionsProviderMerge(connectionsFetcherFactory, catalog); - - } else { - const { accessUrl, travelMode } = catalog.connectionsSourceConfigs[0]; - this.connectionsFetcher = connectionsFetcherFactory(accessUrl, travelMode); - } - - this.connectionsStore = new ConnectionsStore(context); - } - - public prefetchConnections(): void { - if (!this.startedPrefetching) { - this.startedPrefetching = true; - - setTimeout(() => { - const options: IConnectionsIteratorOptions = { - backward: false, - lowerBoundDate: new Date(), - }; - - this.connectionsFetcher.setIteratorOptions(options); - this.connectionsIterator = this.connectionsFetcher.createIterator(); - this.connectionsStore.setSourceIterator(this.connectionsIterator); - this.connectionsStore.startPrimaryPush(ConnectionsProviderPrefetch.MAX_CONNECTIONS); - }, 0); - } - } - - public createIterator(): AsyncIterator { - if (this.startedPrefetching) { - return this.connectionsStore - .getIterator(this.connectionsIteratorOptions); - } - - throw new Error("TODO"); - } - - public setIteratorOptions(options: IConnectionsIteratorOptions): void { - this.connectionsIteratorOptions = options; - } - -} diff --git a/src/fetcher/connections/prefetch/ConnectionsStore.test.ts b/src/fetcher/connections/prefetch/ConnectionsStore.test.ts deleted file mode 100644 index 4348e148..00000000 --- a/src/fetcher/connections/prefetch/ConnectionsStore.test.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { ArrayIterator, AsyncIterator } from "asynciterator"; -import "jest"; -import IConnection from "../IConnection"; -import IConnectionsIteratorOptions from "../IConnectionsIteratorOptions"; -import ConnectionsStore from "./ConnectionsStore"; - -describe("[ConnectionsStore]", () => { - - /** - * In this test, departureTime dates are substituted for numbers for simplicity - * Inside the ConnectionsStore, #valueOf() gets called on the connection.departureTime - * and both Dates and Numbers return a number - */ - - let connectionsStore; - let createIterator; - - beforeEach(() => { - const fakeDepartureTimes = [1, 2, 3, 3, 5, 6, 6, 6, 6, 7, 7]; - // @ts-ignore - const fakeConnections: IConnection[] = fakeDepartureTimes - .map((departureTime) => ({ departureTime })); - - const fakeSourceIterator = new ArrayIterator(fakeConnections); - - connectionsStore = new ConnectionsStore(); - - connectionsStore.setSourceIterator(fakeSourceIterator); - connectionsStore.startPrimaryPush(500); - - createIterator = (backward, lowerBoundDate, upperBoundDate): Promise> => { - return new Promise((resolve) => { - // Primary push start async, so get iterator async - // Running a query is most often initiated by a user event, while prefetching start automatically - setTimeout(() => { - const iteratorOptions: IConnectionsIteratorOptions = { - backward, - }; - - if (lowerBoundDate) { - iteratorOptions.lowerBoundDate = (lowerBoundDate as unknown) as Date; - } - - if (upperBoundDate) { - iteratorOptions.upperBoundDate = (upperBoundDate as unknown) as Date; - } - - resolve(connectionsStore.getIterator(iteratorOptions)); - }, 100); - }); - }; - }); - - describe("backward", () => { - - it("upperBoundDate is loaded & exists in store", async (done) => { - const iteratorView = await createIterator(true, null, 6); - - const expected = [1, 2, 3, 3, 5, 6, 6, 6, 6]; - let current = expected.length - 1; - - iteratorView.each((str: IConnection) => { - expect(expected[current--]).toBe(str.departureTime); - }); - - iteratorView.on("end", () => { - expect(current).toBe(-1); - done(); - }); - }); - - it("upperBoundDate is loaded but doesn\'t exist in store", async (done) => { - const iteratorView = await createIterator(true, null, 4); - - const expected = [1, 2, 3, 3]; - let current = expected.length - 1; - - iteratorView.each((str: IConnection) => { - expect(expected[current--]).toBe(str.departureTime); - }); - - iteratorView.on("end", () => { - expect(current).toBe(-1); - done(); - }); - }); - - }); - - describe("forward", () => { - - it("lowerBoundDate is loaded & exists in store", async (done) => { - const iteratorView = await createIterator(false, 3, 6); - - const expected = [3, 3, 5, 6, 6, 6, 6]; - let current = 0; - - iteratorView.each((str: IConnection) => { - expect(expected[current++]).toBe(str.departureTime); - }); - - iteratorView.on("end", () => { - expect(current).toBe(expected.length); - done(); - }); - }); - - it("lowerBoundDate is loaded but doesn\'t exist in store", async (done) => { - const iteratorView = await createIterator(false, 4, 6); - - const expected = [5, 6, 6, 6, 6]; - let current = 0; - - iteratorView.each((str: IConnection) => { - expect(expected[current++]).toBe(str.departureTime); - }); - - iteratorView.on("end", () => { - expect(current).toBe(expected.length); - done(); - }); - }); - - }); - -}); diff --git a/src/fetcher/connections/prefetch/ConnectionsStore.ts b/src/fetcher/connections/prefetch/ConnectionsStore.ts deleted file mode 100644 index ef49c495..00000000 --- a/src/fetcher/connections/prefetch/ConnectionsStore.ts +++ /dev/null @@ -1,356 +0,0 @@ -import { AsyncIterator, EmptyIterator } from "asynciterator"; -import { PromiseProxyIterator } from "asynciterator-promiseproxy"; -import Context from "../../../Context"; -import EventType from "../../../enums/EventType"; -import BinarySearch from "../../../util/BinarySearch"; -import ArrayViewIterator from "../../../util/iterators/ArrayViewIterator"; -import ExpandingIterator from "../../../util/iterators/ExpandingIterator"; -import Units from "../../../util/Units"; -import IConnection from "../IConnection"; -import IConnectionsIteratorOptions from "../IConnectionsIteratorOptions"; -import IDeferredBackwardView from "./IDeferredBackwardView"; -import IExpandingForwardView from "./IExpandingForwardView"; - -/** - * Class used while prefetching [[IConnection]] instances. It allows appending connections - * and creating iterator *views*. Iterator *views* are AsyncIterators that emit references to connections in the store. - * - * It is assumed that all connections are appended in ascending order by `departureTime`. - * - * Consequently this connections store serves as an in-memory cache for connections - */ -export default class ConnectionsStore { - - private static REPORTING_THRESHOLD = Units.fromMinutes(6); - - private readonly context: Context; - private readonly store: IConnection[]; - private readonly binarySearch: BinarySearch; - - private sourceIterator: AsyncIterator; - private deferredBackwardViews: IDeferredBackwardView[]; - private expandingForwardViews: IExpandingForwardView[]; - - private hasFinishedPrimary: boolean; - private isContinuing: boolean; - private lastReportedDepartureTime: Date; - - constructor(context?: Context) { - this.context = context; - this.store = []; - this.binarySearch = new BinarySearch(this.store, (connection) => connection.departureTime.valueOf()); - this.deferredBackwardViews = []; - this.expandingForwardViews = []; - this.hasFinishedPrimary = false; - this.isContinuing = false; - } - - public setSourceIterator(iterator: AsyncIterator): void { - this.sourceIterator = iterator; - } - - public startPrimaryPush(maxConnections: number): void { - - this.sourceIterator - .transform({ - limit: maxConnections, - destroySource: false, - }) - .on("end", () => this.finishPrimaryPush()) - .each((connection: IConnection) => { - if (this.context) { - this.maybeEmitPrefetchEvent(connection); - } - - this.append(connection); - }); - } - - public getIterator(iteratorOptions: IConnectionsIteratorOptions): AsyncIterator { - const { backward } = iteratorOptions; - let { lowerBoundDate, upperBoundDate } = iteratorOptions; - - if (this.hasFinishedPrimary && this.store.length === 0) { - return new EmptyIterator(); - } - - const firstConnection = this.store[0]; - const firstDepartureTime = firstConnection && firstConnection.departureTime; - - const lastConnection = this.store[this.store.length - 1]; - const lastDepartureTime = lastConnection && lastConnection.departureTime; - - if (lowerBoundDate && lowerBoundDate < firstDepartureTime) { - throw new Error("Must supply a lowerBoundDate after the first prefetched connection"); - } - - if (backward) { - - if (!upperBoundDate) { - throw new Error("Must supply upperBoundDate when iterating backward"); - } - - if (!lowerBoundDate) { - lowerBoundDate = firstDepartureTime; - } - - this.emitConnectionViewEvent(lowerBoundDate, upperBoundDate, false); - - // If the store is still empty or the latest departure time isn't later than the upperBoundDate, - // then return a promise proxy iterator - const notFinishedScenario = !this.hasFinishedPrimary - && (!lastDepartureTime || lastDepartureTime <= upperBoundDate); - - const finishedScenario = this.hasFinishedPrimary - && lastDepartureTime < upperBoundDate; - - if (notFinishedScenario || finishedScenario) { - const { deferred, promise } = this.createDeferredBackwardView(lowerBoundDate, upperBoundDate); - - this.deferredBackwardViews.push(deferred); - - if (this.hasFinishedPrimary) { - this.continueAfterFinishing(); - } - - return new PromiseProxyIterator(() => promise); - } - - } else { - - if (!lowerBoundDate) { - throw new Error("Must supply lowerBoundDate when iterating forward"); - } - - if (!upperBoundDate) { - // Mock +infinity - upperBoundDate = new Date(lowerBoundDate.valueOf() + Units.fromHours(24)); - } - - this.emitConnectionViewEvent(lowerBoundDate, upperBoundDate, false); - - // If the store is still empty or the latest departure time isn't later than the upperBoundDate, - // then return a an expanding iterator view - const notFinishedScenario = !this.hasFinishedPrimary - && (!lastDepartureTime || lastDepartureTime <= upperBoundDate); - - const finishedScenario = this.hasFinishedPrimary - && lastDepartureTime < upperBoundDate; - - if (notFinishedScenario || finishedScenario) { - const { view, iterator } = this.createExpandingForwardView(lowerBoundDate, upperBoundDate); - - this.expandingForwardViews.push(view); - - if (this.hasFinishedPrimary) { - this.continueAfterFinishing(); - } - - return iterator; - } - } - - // If the whole interval fits inside the prefetched window, return an iterator view - if (lowerBoundDate >= firstDepartureTime && upperBoundDate < lastDepartureTime) { - const { iterator } = this.getIteratorView(backward, lowerBoundDate, upperBoundDate); - - this.emitConnectionViewEvent(lowerBoundDate, upperBoundDate, true); - - return iterator; - } - - throw new Error("This shouldn\'t happen"); - } - - /** - * Add a new [[IConnection]] to the store. - * - * Additionally, this method checks if any forward iterator views can be expanded or if any backward iterator can be - * resolved - * - * @returns the number of unsatisfied views - */ - private append(connection: IConnection): number { - this.store.push(connection); - - // Check if any deferred backward views are satisfied - if (this.deferredBackwardViews.length) { - this.deferredBackwardViews = this.deferredBackwardViews - .filter(({ lowerBoundDate, upperBoundDate, resolve }) => { - - if (connection.departureTime > upperBoundDate) { - const { iterator } = this.getIteratorView(true, lowerBoundDate, upperBoundDate); - - this.emitConnectionViewEvent(lowerBoundDate, upperBoundDate, true); - - resolve(iterator); - return false; - } - - return true; - }); - } - - // Check if any forward views can be expanded - if (this.expandingForwardViews.length) { - this.expandingForwardViews = this.expandingForwardViews - .filter(({ tryExpand }) => tryExpand(connection, this.store.length - 1)); - } - - return this.deferredBackwardViews.length + this.expandingForwardViews.length; - } - - /** - * Signals that the store will no longer be appended. - * [[getIterator]] never returns a deferred backward view after this, because those would never get resolved - */ - private finishPrimaryPush(): void { - this.hasFinishedPrimary = true; - - if (this.deferredBackwardViews.length || this.expandingForwardViews.length) { - this.continueAfterFinishing(); - } - } - - private finishSecondaryPush(): void { - this.isContinuing = false; - } - - private continueAfterFinishing(): void { - if (!this.isContinuing) { - this.isContinuing = true; - - setTimeout(() => this.startSecondaryPush(), 0); - } - } - - private startSecondaryPush(): void { - const secondaryPushIterator = this.sourceIterator - .transform({destroySource: false}) - .on("end", () => this.finishSecondaryPush()); - - secondaryPushIterator.each((connection: IConnection) => { - if (this.context) { - this.maybeEmitPrefetchEvent(connection); - } - - const unsatisfiedViewCount = this.append(connection); - - if (unsatisfiedViewCount === 0) { - secondaryPushIterator.close(); - } - }); - } - - private createDeferredBackwardView(lowerBoundDate, upperBoundDate): - { deferred: IDeferredBackwardView, promise: Promise> } { - - const deferred: Partial = { - lowerBoundDate, - upperBoundDate, - }; - - const promise = new Promise>((resolve) => { - deferred.resolve = resolve; - }); - - return { - deferred: deferred as IDeferredBackwardView, - promise, - }; - } - - private createExpandingForwardView(lowerBoundDate, upperBoundDate): - { view: IExpandingForwardView, iterator: AsyncIterator } { - - const { iterator: existingIterator, upperBoundIndex } = this.getIteratorView(false, lowerBoundDate, upperBoundDate); - const expandingIterator = new ExpandingIterator(); - - const iterator = expandingIterator.prepend(existingIterator); - - let lastStoreIndex = upperBoundIndex; - - const view: IExpandingForwardView = { - lowerBoundDate, - upperBoundDate, - tryExpand: (connection: IConnection, storeIndex: number): boolean => { - - if (storeIndex - lastStoreIndex > 1) { - // No idea if this can happen - console.warn("Skipped", storeIndex - lastStoreIndex); - } - - lastStoreIndex = storeIndex; - - // No need to keep trying to expand if the consumer has closed it - if (iterator.closed) { - expandingIterator.close(); - - return false; // Remove from expanding forward views - } - - if (connection.departureTime <= upperBoundDate) { - expandingIterator.write(connection); - - return true; // Keep in expanding forward views - - } else { - expandingIterator.closeAfterFlush(); - // iterator.close(); - - this.emitConnectionViewEvent(lowerBoundDate, upperBoundDate, true); - - return false; // Remove from expanding forward views - } - }, - }; - - return { view, iterator }; - } - - private getIteratorView(backward: boolean, lowerBoundDate: Date, upperBoundDate: Date): - { iterator: AsyncIterator, lowerBoundIndex: number, upperBoundIndex: number } { - - const lowerBoundIndex = this.getLowerBoundIndex(lowerBoundDate); - const upperBoundIndex = this.getUpperBoundIndex(upperBoundDate); - - const start = backward ? upperBoundIndex : lowerBoundIndex; - const stop = backward ? lowerBoundIndex : upperBoundIndex; - const step = backward ? -1 : 1; - - const iterator = new ArrayViewIterator(this.store, start, stop, step); - - return { iterator, lowerBoundIndex, upperBoundIndex }; - } - - private getLowerBoundIndex(date: Date): number { - return this.binarySearch.findFirstIndex(date.valueOf(), 0, this.store.length - 1); - } - - private getUpperBoundIndex(date: Date): number { - return this.binarySearch.findLastIndex(date.valueOf(), 0, this.store.length - 1); - } - - private emitConnectionViewEvent(lowerBoundDate: Date, upperBoundDate: Date, completed: boolean) { - if (this.context) { - this.context.emit(EventType.ConnectionIteratorView, lowerBoundDate, upperBoundDate, completed); - } - } - - private maybeEmitPrefetchEvent(connection: IConnection): void { - if (!this.lastReportedDepartureTime) { - this.lastReportedDepartureTime = connection.departureTime; - - this.context.emit(EventType.ConnectionPrefetch, this.lastReportedDepartureTime); - return; - } - - const timeSinceLastEvent = connection.departureTime.valueOf() - this.lastReportedDepartureTime.valueOf(); - - if (timeSinceLastEvent > ConnectionsStore.REPORTING_THRESHOLD) { - this.lastReportedDepartureTime = connection.departureTime; - - this.context.emit(EventType.ConnectionPrefetch, this.lastReportedDepartureTime); - } - } -} diff --git a/src/fetcher/connections/prefetch/IDeferredBackwardView.ts b/src/fetcher/connections/prefetch/IDeferredBackwardView.ts deleted file mode 100644 index 781878ea..00000000 --- a/src/fetcher/connections/prefetch/IDeferredBackwardView.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { AsyncIterator } from "asynciterator"; -import IConnection from "../IConnection"; - -export default interface IDeferredBackwardView { - lowerBoundDate: Date; - upperBoundDate: Date; - resolve: (iterator: AsyncIterator) => void; -} diff --git a/src/fetcher/connections/prefetch/IExpandingForwardView.ts b/src/fetcher/connections/prefetch/IExpandingForwardView.ts deleted file mode 100644 index 7e376e1a..00000000 --- a/src/fetcher/connections/prefetch/IExpandingForwardView.ts +++ /dev/null @@ -1,7 +0,0 @@ -import IConnection from "../IConnection"; - -export default interface IExpandingForwardView { - lowerBoundDate: Date; - upperBoundDate: Date; - tryExpand: (connection: IConnection, index: number) => boolean; -} diff --git a/src/fetcher/connections/tests/ConnectionsFetcherNMBSTest.ts b/src/fetcher/connections/tests/ConnectionsFetcherNMBSTest.ts deleted file mode 100644 index 5be1c39e..00000000 --- a/src/fetcher/connections/tests/ConnectionsFetcherNMBSTest.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { ArrayIterator, AsyncIterator } from "asynciterator"; -import { injectable } from "inversify"; -import IConnection from "../IConnection"; -import IConnectionsFetcher from "../IConnectionsFetcher"; -import IConnectionsIteratorOptions from "../IConnectionsIteratorOptions"; - -@injectable() -export default class ConnectionsFetcherNMBSTest implements IConnectionsFetcher { - - private connections: Array> = []; - private options: IConnectionsIteratorOptions = {}; - - constructor(connections: Array>) { - this.connections = connections; - } - - public prefetchConnections(): void { - return; - } - - public setIteratorOptions(options: IConnectionsIteratorOptions): void { - this.options = options; - } - - public createIterator(): AsyncIterator { - let array = this.connections - .map((r) => r.value); - - if (this.options.backward) { - array = array.reverse(); - } - - return new ArrayIterator(array); - } -} diff --git a/src/fetcher/connections/tests/ConnectionsProviderNMBSTest.ts b/src/fetcher/connections/tests/ConnectionsProviderNMBSTest.ts new file mode 100644 index 00000000..ac3a756c --- /dev/null +++ b/src/fetcher/connections/tests/ConnectionsProviderNMBSTest.ts @@ -0,0 +1,38 @@ +import { ArrayIterator, AsyncIterator } from "asynciterator"; +import { injectable } from "inversify"; +import IConnection from "../../../entities/connections/connections"; +import { LinkedConnectionsPage } from "../../../entities/connections/page"; +import IConnectionsIteratorOptions from "../IConnectionsIteratorOptions"; +import IConnectionsProvider from "../IConnectionsProvider"; + +@injectable() +export default class ConnectionsProviderNMBSTest implements IConnectionsProvider { + private connections: Array> = []; + private s = {}; + + constructor(connections: Array>) { + this.connections = connections; + } + + public getByUrl(url: string): Promise { + throw new Error("Method not implemented."); + } + public getByTime(date: Date): Promise { + throw new Error("Method not implemented."); + } + + public prefetchConnections(): void { + return; + } + + public createIterator(options: IConnectionsIteratorOptions): AsyncIterator { + let array = this.connections + .map((r) => r.value); + + if (options.backward) { + array = array.reverse(); + } + + return new ArrayIterator(array); + } +} diff --git a/src/fetcher/connections/tests/data/ingelmunster-ghent.ts b/src/fetcher/connections/tests/data/ingelmunster-ghent.ts index d4c5f019..80ae830d 100644 --- a/src/fetcher/connections/tests/data/ingelmunster-ghent.ts +++ b/src/fetcher/connections/tests/data/ingelmunster-ghent.ts @@ -3,242 +3,242 @@ import TravelMode from "../../../../enums/TravelMode"; const connections = [ { value: - { - "arrivalDelay": 0, - "travelMode": TravelMode.Train, - "departureDelay": 0, - "id": "http://irail.be/connections/8891264/20181106/IC2310", - "arrivalStop": "http://irail.be/stations/NMBS/008891314", - "arrivalTime": new Date("2018-11-06T10:30:00.000Z"), - "departureStop": "http://irail.be/stations/NMBS/008891264", - "departureTime": new Date("2018-11-06T10:24:00.000Z"), - "gtfs:trip": "http://irail.be/vehicle/IC2310/20181106", - }, + { + arrivalDelay: 0, + travelMode: TravelMode.Train, + departureDelay: 0, + id: "http://irail.be/connections/8891264/20181106/IC2310", + arrivalStop: "http://irail.be/stations/NMBS/008891314", + arrivalTime: new Date("2018-11-06T10:30:00.000Z"), + departureStop: "http://irail.be/stations/NMBS/008891264", + departureTime: new Date("2018-11-06T10:24:00.000Z"), + tripId: "http://irail.be/vehicle/IC2310/20181106", + }, done: false, }, { value: - { - "arrivalDelay": 0, - "travelMode": TravelMode.Train, - "departureDelay": 0, - "id": "http://irail.be/connections/8891314/20181106/IC2310", - "arrivalStop": "http://irail.be/stations/NMBS/008892205", - "arrivalTime": new Date("2018-11-06T10:35:00.000Z"), - "departureStop": "http://irail.be/stations/NMBS/008891314", - "departureTime": new Date("2018-11-06T10:31:00.000Z"), - "gtfs:trip": "http://irail.be/vehicle/IC2310/20181106", - }, + { + arrivalDelay: 0, + travelMode: TravelMode.Train, + departureDelay: 0, + id: "http://irail.be/connections/8891314/20181106/IC2310", + arrivalStop: "http://irail.be/stations/NMBS/008892205", + arrivalTime: new Date("2018-11-06T10:35:00.000Z"), + departureStop: "http://irail.be/stations/NMBS/008891314", + departureTime: new Date("2018-11-06T10:31:00.000Z"), + tripId: "http://irail.be/vehicle/IC2310/20181106", + }, done: false, }, { value: - { - "arrivalDelay": 0, - "travelMode": TravelMode.Train, - "departureDelay": 0, - "id": "http://irail.be/connections/8892205/20181106/IC2310", - "arrivalStop": "http://irail.be/stations/NMBS/008896800", - "arrivalTime": new Date("2018-11-06T10:43:00.000Z"), - "departureStop": "http://irail.be/stations/NMBS/008892205", - "departureTime": new Date("2018-11-06T10:36:00.000Z"), - "gtfs:trip": "http://irail.be/vehicle/IC2310/20181106", - }, + { + arrivalDelay: 0, + travelMode: TravelMode.Train, + departureDelay: 0, + id: "http://irail.be/connections/8892205/20181106/IC2310", + arrivalStop: "http://irail.be/stations/NMBS/008896800", + arrivalTime: new Date("2018-11-06T10:43:00.000Z"), + departureStop: "http://irail.be/stations/NMBS/008892205", + departureTime: new Date("2018-11-06T10:36:00.000Z"), + tripId: "http://irail.be/vehicle/IC2310/20181106", + }, done: false, }, { value: - { - "arrivalDelay": 0, - "travelMode": TravelMode.Train, - "departureDelay": 0, - "id": "http://irail.be/connections/8896800/20181106/IC2310", - "arrivalStop": "http://irail.be/stations/NMBS/008896909", - "arrivalTime": new Date("2018-11-06T10:50:00.000Z"), - "departureStop": "http://irail.be/stations/NMBS/008896800", - "departureTime": new Date("2018-11-06T10:44:00.000Z"), - "gtfs:trip": "http://irail.be/vehicle/IC2310/20181106", - }, + { + arrivalDelay: 0, + travelMode: TravelMode.Train, + departureDelay: 0, + id: "http://irail.be/connections/8896800/20181106/IC2310", + arrivalStop: "http://irail.be/stations/NMBS/008896909", + arrivalTime: new Date("2018-11-06T10:50:00.000Z"), + departureStop: "http://irail.be/stations/NMBS/008896800", + departureTime: new Date("2018-11-06T10:44:00.000Z"), + tripId: "http://irail.be/vehicle/IC2310/20181106", + }, done: false, }, { value: - { - "arrivalDelay": 0, - "travelMode": TravelMode.Train, - "departureDelay": 0, - "id": "http://irail.be/connections/8896909/20181106/IC2310", - "arrivalStop": "http://irail.be/stations/NMBS/008896925", - "arrivalTime": new Date("2018-11-06T10:56:00.000Z"), - "departureStop": "http://irail.be/stations/NMBS/008896909", - "departureTime": new Date("2018-11-06T10:51:00.000Z"), - "gtfs:trip": "http://irail.be/vehicle/IC2310/20181106", - }, + { + arrivalDelay: 0, + travelMode: TravelMode.Train, + departureDelay: 0, + id: "http://irail.be/connections/8896909/20181106/IC2310", + arrivalStop: "http://irail.be/stations/NMBS/008896925", + arrivalTime: new Date("2018-11-06T10:56:00.000Z"), + departureStop: "http://irail.be/stations/NMBS/008896909", + departureTime: new Date("2018-11-06T10:51:00.000Z"), + tripId: "http://irail.be/vehicle/IC2310/20181106", + }, done: false, }, { value: - { - "arrivalDelay": 0, - "travelMode": TravelMode.Train, - "departureDelay": 0, - "id": "http://irail.be/connections/8896925/20181106/IC2310", - "arrivalStop": "http://irail.be/stations/NMBS/008896008", - "arrivalTime": new Date("2018-11-06T11:05:00.000Z"), - "departureStop": "http://irail.be/stations/NMBS/008896925", - "departureTime": new Date("2018-11-06T10:56:00.000Z"), - "gtfs:trip": "http://irail.be/vehicle/IC2310/20181106", - }, + { + arrivalDelay: 0, + travelMode: TravelMode.Train, + departureDelay: 0, + id: "http://irail.be/connections/8896925/20181106/IC2310", + arrivalStop: "http://irail.be/stations/NMBS/008896008", + arrivalTime: new Date("2018-11-06T11:05:00.000Z"), + departureStop: "http://irail.be/stations/NMBS/008896925", + departureTime: new Date("2018-11-06T10:56:00.000Z"), + tripId: "http://irail.be/vehicle/IC2310/20181106", + }, done: false, }, { value: - { - "arrivalDelay": 0, - "travelMode": TravelMode.Train, - "departureDelay": 0, - "id": "http://irail.be/connections/8896008/20181106/IC2310", - "arrivalStop": "http://irail.be/stations/NMBS/008892601", - "arrivalTime": new Date("2018-11-06T11:29:00.000Z"), - "departureStop": "http://irail.be/stations/NMBS/008896008", - "departureTime": new Date("2018-11-06T11:12:00.000Z"), - "gtfs:trip": "http://irail.be/vehicle/IC2310/20181106", - }, + { + arrivalDelay: 0, + travelMode: TravelMode.Train, + departureDelay: 0, + id: "http://irail.be/connections/8896008/20181106/IC2310", + arrivalStop: "http://irail.be/stations/NMBS/008892601", + arrivalTime: new Date("2018-11-06T11:29:00.000Z"), + departureStop: "http://irail.be/stations/NMBS/008896008", + departureTime: new Date("2018-11-06T11:12:00.000Z"), + tripId: "http://irail.be/vehicle/IC2310/20181106", + }, done: false, }, { value: - { - "arrivalDelay": 0, - "travelMode": TravelMode.Train, - "departureDelay": 0, - "id": "http://irail.be/connections/8896008/20181106/IC412", - "arrivalStop": "http://irail.be/stations/NMBS/008896115", - "arrivalTime": new Date("2018-11-06T11:22:00.000Z"), - "departureStop": "http://irail.be/stations/NMBS/008896008", - "departureTime": new Date("2018-11-06T11:17:00.000Z"), - "gtfs:trip": "http://irail.be/vehicle/IC412/20181106", - }, + { + arrivalDelay: 0, + travelMode: TravelMode.Train, + departureDelay: 0, + id: "http://irail.be/connections/8896008/20181106/IC412", + arrivalStop: "http://irail.be/stations/NMBS/008896115", + arrivalTime: new Date("2018-11-06T11:22:00.000Z"), + departureStop: "http://irail.be/stations/NMBS/008896008", + departureTime: new Date("2018-11-06T11:17:00.000Z"), + tripId: "http://irail.be/vehicle/IC412/20181106", + }, done: false, }, { value: - { - "arrivalDelay": 0, - "travelMode": TravelMode.Train, - "departureDelay": 0, - "id": "http://irail.be/connections/8896115/20181106/IC412", - "arrivalStop": "http://irail.be/stations/NMBS/008896149", - "arrivalTime": new Date("2018-11-06T11:29:00.000Z"), - "departureStop": "http://irail.be/stations/NMBS/008896115", - "departureTime": new Date("2018-11-06T11:23:00.000Z"), - "gtfs:trip": "http://irail.be/vehicle/IC412/20181106", - }, + { + arrivalDelay: 0, + travelMode: TravelMode.Train, + departureDelay: 0, + id: "http://irail.be/connections/8896115/20181106/IC412", + arrivalStop: "http://irail.be/stations/NMBS/008896149", + arrivalTime: new Date("2018-11-06T11:29:00.000Z"), + departureStop: "http://irail.be/stations/NMBS/008896115", + departureTime: new Date("2018-11-06T11:23:00.000Z"), + tripId: "http://irail.be/vehicle/IC412/20181106", + }, done: false, }, { value: - { - "arrivalDelay": 0, - "travelMode": TravelMode.Train, - "departureDelay": 0, - "id": "http://irail.be/connections/8896149/20181106/IC412", - "arrivalStop": "http://irail.be/stations/NMBS/008892106", - "arrivalTime": new Date("2018-11-06T11:37:00.000Z"), - "departureStop": "http://irail.be/stations/NMBS/008896149", - "departureTime": new Date("2018-11-06T11:30:00.000Z"), - "gtfs:trip": "http://irail.be/vehicle/IC412/20181106", - }, + { + arrivalDelay: 0, + travelMode: TravelMode.Train, + departureDelay: 0, + id: "http://irail.be/connections/8896149/20181106/IC412", + arrivalStop: "http://irail.be/stations/NMBS/008892106", + arrivalTime: new Date("2018-11-06T11:37:00.000Z"), + departureStop: "http://irail.be/stations/NMBS/008896149", + departureTime: new Date("2018-11-06T11:30:00.000Z"), + tripId: "http://irail.be/vehicle/IC412/20181106", + }, done: false, }, { value: - { - "arrivalDelay": 0, - "travelMode": TravelMode.Train, - "departureDelay": 0, - "id": "http://irail.be/connections/8892601/20181106/IC2310", - "arrivalStop": "http://irail.be/stations/NMBS/008895208", - "arrivalTime": new Date("2018-11-06T11:44:00.000Z"), - "departureStop": "http://irail.be/stations/NMBS/008892601", - "departureTime": new Date("2018-11-06T11:32:00.000Z"), - "gtfs:trip": "http://irail.be/vehicle/IC2310/20181106", - }, + { + arrivalDelay: 0, + travelMode: TravelMode.Train, + departureDelay: 0, + id: "http://irail.be/connections/8892601/20181106/IC2310", + arrivalStop: "http://irail.be/stations/NMBS/008895208", + arrivalTime: new Date("2018-11-06T11:44:00.000Z"), + departureStop: "http://irail.be/stations/NMBS/008892601", + departureTime: new Date("2018-11-06T11:32:00.000Z"), + tripId: "http://irail.be/vehicle/IC2310/20181106", + }, done: false, }, { value: - { - "arrivalDelay": 0, - "travelMode": TravelMode.Train, - "departureDelay": 0, - "id": "http://irail.be/connections/8892106/20181106/IC412", - "arrivalStop": "http://irail.be/stations/NMBS/008892080", - "arrivalTime": new Date("2018-11-06T11:43:00.000Z"), - "departureStop": "http://irail.be/stations/NMBS/008892106", - "departureTime": new Date("2018-11-06T11:38:00.000Z"), - "gtfs:trip": "http://irail.be/vehicle/IC412/20181106", - }, + { + arrivalDelay: 0, + travelMode: TravelMode.Train, + departureDelay: 0, + id: "http://irail.be/connections/8892106/20181106/IC412", + arrivalStop: "http://irail.be/stations/NMBS/008892080", + arrivalTime: new Date("2018-11-06T11:43:00.000Z"), + departureStop: "http://irail.be/stations/NMBS/008892106", + departureTime: new Date("2018-11-06T11:38:00.000Z"), + tripId: "http://irail.be/vehicle/IC412/20181106", + }, done: false, }, { value: - { - "arrivalDelay": 0, - "travelMode": TravelMode.Train, - "departureDelay": 0, - "id": "http://irail.be/connections/8892080/20181106/IC412", - "arrivalStop": "http://irail.be/stations/NMBS/008892007", - "arrivalTime": new Date("2018-11-06T11:51:00.000Z"), - "departureStop": "http://irail.be/stations/NMBS/008892080", - "departureTime": new Date("2018-11-06T11:44:00.000Z"), - "gtfs:trip": "http://irail.be/vehicle/IC412/20181106", - }, + { + arrivalDelay: 0, + travelMode: TravelMode.Train, + departureDelay: 0, + id: "http://irail.be/connections/8892080/20181106/IC412", + arrivalStop: "http://irail.be/stations/NMBS/008892007", + arrivalTime: new Date("2018-11-06T11:51:00.000Z"), + departureStop: "http://irail.be/stations/NMBS/008892080", + departureTime: new Date("2018-11-06T11:44:00.000Z"), + tripId: "http://irail.be/vehicle/IC412/20181106", + }, done: false, }, { value: - { - "arrivalDelay": 0, - "travelMode": TravelMode.Train, - "departureDelay": 0, - "id": "http://irail.be/connections/8895208/20181106/IC2310", - "arrivalStop": "http://irail.be/stations/NMBS/008895802", - "arrivalTime": new Date("2018-11-06T12:02:00.000Z"), - "departureStop": "http://irail.be/stations/NMBS/008895208", - "departureTime": new Date("2018-11-06T11:46:00.000Z"), - "gtfs:trip": "http://irail.be/vehicle/IC2310/20181106", - }, + { + arrivalDelay: 0, + travelMode: TravelMode.Train, + departureDelay: 0, + id: "http://irail.be/connections/8895208/20181106/IC2310", + arrivalStop: "http://irail.be/stations/NMBS/008895802", + arrivalTime: new Date("2018-11-06T12:02:00.000Z"), + departureStop: "http://irail.be/stations/NMBS/008895208", + departureTime: new Date("2018-11-06T11:46:00.000Z"), + tripId: "http://irail.be/vehicle/IC2310/20181106", + }, done: false, }, { value: - { - "id": "http://irail.be/connections/8895802/20181106/IC2310", - "arrivalStop": "http://irail.be/stations/NMBS/008814001", - "arrivalTime": new Date("2018-11-06T12:20:00.000Z"), - "arrivalDelay": 0, - "travelMode": TravelMode.Train, - "departureStop": "http://irail.be/stations/NMBS/008895802", - "departureTime": new Date("2018-11-06T12:05:00.000Z"), - "departureDelay": 0, - "gtfs:trip": "http://irail.be/vehicle/IC2310/20181106", - }, + { + id: "http://irail.be/connections/8895802/20181106/IC2310", + arrivalStop: "http://irail.be/stations/NMBS/008814001", + arrivalTime: new Date("2018-11-06T12:20:00.000Z"), + arrivalDelay: 0, + travelMode: TravelMode.Train, + departureStop: "http://irail.be/stations/NMBS/008895802", + departureTime: new Date("2018-11-06T12:05:00.000Z"), + departureDelay: 0, + tripId: "http://irail.be/vehicle/IC2310/20181106", + }, done: false, }, { value: - { - "id": "http://irail.be/connections/8814001/20181106/IC2310", - "arrivalStop": "http://irail.be/stations/NMBS/008813003", - "arrivalTime": new Date("2018-11-06T12:26:00.000Z"), - "arrivalDelay": 0, - "travelMode": TravelMode.Train, - "departureStop": "http://irail.be/stations/NMBS/008814001", - "departureTime": new Date("2018-11-06T12:23:00.000Z"), - "departureDelay": 0, - "gtfs:trip": "http://irail.be/vehicle/IC2310/20181106", - }, + { + id: "http://irail.be/connections/8814001/20181106/IC2310", + arrivalStop: "http://irail.be/stations/NMBS/008813003", + arrivalTime: new Date("2018-11-06T12:26:00.000Z"), + arrivalDelay: 0, + travelMode: TravelMode.Train, + departureStop: "http://irail.be/stations/NMBS/008814001", + departureTime: new Date("2018-11-06T12:23:00.000Z"), + departureDelay: 0, + tripId: "http://irail.be/vehicle/IC2310/20181106", + }, done: false, }, ]; diff --git a/src/fetcher/connections/tests/data/joining.ts b/src/fetcher/connections/tests/data/joining.ts index f237967b..4b71291d 100644 --- a/src/fetcher/connections/tests/data/joining.ts +++ b/src/fetcher/connections/tests/data/joining.ts @@ -11,7 +11,7 @@ const connections = [ "departureStop": "http://irail.be/stations/NMBS/008892007", // C "departureTime": new Date("2017-12-19T16:22:00.000Z"), "arrivalTime": new Date("2017-12-19T16:30:00.000Z"), - "gtfs:trip": "A", + "tripId": "A", "gtfs:pickupType": PickupType.Regular, "gtfs:dropOffType": DropOffType.Regular, }, @@ -25,7 +25,7 @@ const connections = [ "departureStop": "http://irail.be/stations/NMBS/008812005", // D "departureTime": new Date("2017-12-19T16:23:00.000Z"), "arrivalTime": new Date("2017-12-19T16:34:00.000Z"), - "gtfs:trip": "B", + "tripId": "B", "nextConnection": ["1"], "gtfs:pickupType": PickupType.Regular, "gtfs:dropOffType": DropOffType.Regular, @@ -40,7 +40,7 @@ const connections = [ "departureStop": "http://irail.be/stations/NMBS/008891702", // B "departureTime": new Date("2017-12-19T16:35:00.000Z"), "arrivalTime": new Date("2017-12-19T16:50:00.000Z"), - "gtfs:trip": "A", + "tripId": "A", "gtfs:pickupType": PickupType.Regular, "gtfs:dropOffType": DropOffType.Regular, }, diff --git a/src/fetcher/connections/tests/data/splitting.ts b/src/fetcher/connections/tests/data/splitting.ts index d625329d..9f388e88 100644 --- a/src/fetcher/connections/tests/data/splitting.ts +++ b/src/fetcher/connections/tests/data/splitting.ts @@ -11,7 +11,7 @@ const connections = [ "arrivalStop": "http://irail.be/stations/NMBS/008891702", // B "departureTime": new Date("2017-12-19T15:50:00.000Z"), "arrivalTime": new Date("2017-12-19T16:20:00.000Z"), - "gtfs:trip": "A", + "tripId": "A", "nextConnection": ["2b"], "gtfs:pickupType": PickupType.Regular, "gtfs:dropOffType": DropOffType.Regular, @@ -26,7 +26,7 @@ const connections = [ "arrivalStop": "http://irail.be/stations/NMBS/008892007", // C "departureTime": new Date("2017-12-19T16:22:00.000Z"), "arrivalTime": new Date("2017-12-19T16:30:00.000Z"), - "gtfs:trip": "A", + "tripId": "A", "gtfs:pickupType": PickupType.Regular, "gtfs:dropOffType": DropOffType.Regular, }, @@ -40,7 +40,7 @@ const connections = [ "arrivalStop": "http://irail.be/stations/NMBS/008812005", // D "departureTime": new Date("2017-12-19T16:23:00.000Z"), "arrivalTime": new Date("2017-12-19T16:50:00.000Z"), - "gtfs:trip": "B", + "tripId": "B", "gtfs:pickupType": PickupType.Regular, "gtfs:dropOffType": DropOffType.Regular, }, diff --git a/src/fetcher/footpaths/FootpathsProviderDefault.ts b/src/fetcher/footpaths/FootpathsProviderDefault.ts new file mode 100644 index 00000000..6a90a83f --- /dev/null +++ b/src/fetcher/footpaths/FootpathsProviderDefault.ts @@ -0,0 +1,85 @@ +import { inject, injectable } from "inversify"; +import LDFetch from "ldfetch"; +import { Footpath, IFootpathIndex } from "../../entities/footpaths/footpath"; +import { RoutableTileCoordinate } from "../../entities/tiles/coordinate"; +import ILocation from "../../interfaces/ILocation"; +import { LDLoader } from "../../loader/ldloader"; +import { IndexThingView } from "../../loader/views"; +import TYPES from "../../types"; +import { PLANNER } from "../../uri/constants"; +import URI from "../../uri/uri"; +import { lat_to_tile, long_to_tile } from "../../util/Tiles"; +import IStop from "../stops/IStop"; +import IFootpathsProvider from "./IFootpathsProvider"; + +const ZOOM = 12; + +interface ITiledFootpathIndex { + [id: string]: Promise; +} + +@injectable() +export default class FootpathsProviderDefault implements IFootpathsProvider { + + protected ldFetch: LDFetch; + protected ldLoader: LDLoader; + protected paths: ITiledFootpathIndex; + + constructor( + @inject(TYPES.LDFetch) ldFetch: LDFetch, + ) { + this.ldFetch = ldFetch; + this.ldLoader = new LDLoader(); + this.paths = {}; + } + + public async get(stop: IStop): Promise { + const tileId = this.getIdForLocation(ZOOM, stop); + if (!this.paths[tileId]) { + this.paths[tileId] = this.getByUrl(tileId); + } + + return this.paths[tileId]; + } + + public getIdForLocation(zoom: number, location: ILocation): string { + const y = lat_to_tile(location.latitude, zoom); + const x = long_to_tile(location.longitude, zoom); + const coordinate = new RoutableTileCoordinate(zoom, x, y ); + return this.getIdForTileCoords(coordinate); + } + + public getIdForTileCoords(coordinate: RoutableTileCoordinate): string { + return `https://hdelva.be/stops/distances/${coordinate.zoom}/${coordinate.x}/${coordinate.y}`; + } + + public getByLocation(zoom: number, location: ILocation): Promise { + const y = lat_to_tile(location.latitude, zoom); + const x = long_to_tile(location.longitude, zoom); + const coordinate = new RoutableTileCoordinate(zoom, x, y); + return this.getByTileCoords(coordinate); + } + + public async getByTileCoords(coordinate: RoutableTileCoordinate): Promise { + const url = this.getIdForTileCoords(coordinate); + return await this.getByUrl(url); + } + + protected async getByUrl(url: string): Promise { + const rdfThing = await this.ldFetch.get(url); + const triples = rdfThing.triples; + + const [paths] = this.ldLoader.process(triples, [ + this.getPathsView(), + ]); + return paths; + } + + protected getPathsView() { + const nodesView = new IndexThingView(Footpath.create); + nodesView.addMapping(URI.inNS(PLANNER, "source"), "from"); + nodesView.addMapping(URI.inNS(PLANNER, "destination"), "to"); + nodesView.addMapping(URI.inNS(PLANNER, "distance"), "distance"); + return nodesView; + } +} diff --git a/src/fetcher/footpaths/FootpathsProviderRaw.ts b/src/fetcher/footpaths/FootpathsProviderRaw.ts new file mode 100644 index 00000000..c6c2e1ae --- /dev/null +++ b/src/fetcher/footpaths/FootpathsProviderRaw.ts @@ -0,0 +1,82 @@ +import { inject, injectable } from "inversify"; +import { Footpath, IFootpathIndex } from "../../entities/footpaths/footpath"; +import { RoutableTileCoordinate } from "../../entities/tiles/coordinate"; +import EventBus from "../../events/EventBus"; +import EventType from "../../events/EventType"; +import ILocation from "../../interfaces/ILocation"; +import { lat_to_tile, long_to_tile } from "../../util/Tiles"; +import IStop from "../stops/IStop"; +import IFootpathsProvider from "./IFootpathsProvider"; + +const ZOOM = 12; + +interface ITiledFootpathIndex { + [id: string]: Promise; +} + +@injectable() +export default class FootpathsProviderRaw implements IFootpathsProvider { + protected paths: ITiledFootpathIndex; + + constructor() { + this.paths = {}; + } + + public async get(stop: IStop): Promise { + const tileId = this.getIdForLocation(ZOOM, stop); + if (!this.paths[tileId]) { + this.paths[tileId] = this.getByUrl(tileId); + } + + return this.paths[tileId]; + } + + public getIdForLocation(zoom: number, location: ILocation): string { + const y = lat_to_tile(location.latitude, zoom); + const x = long_to_tile(location.longitude, zoom); + const coordinate = new RoutableTileCoordinate(zoom, x, y); + return this.getIdForTileCoords(coordinate); + } + + public getIdForTileCoords(coordinate: RoutableTileCoordinate): string { + return `https://hdelva.be/stops/distances/${coordinate.zoom}/${coordinate.x}/${coordinate.y}`; + } + + public getByLocation(zoom: number, location: ILocation): Promise { + const y = lat_to_tile(location.latitude, zoom); + const x = long_to_tile(location.longitude, zoom); + const coordinate = new RoutableTileCoordinate(zoom, x, y); + return this.getByTileCoords(coordinate); + } + + public async getByTileCoords(coordinate: RoutableTileCoordinate): Promise { + const url = this.getIdForTileCoords(coordinate); + return await this.getByUrl(url); + } + + protected async getByUrl(url: string): Promise { + const response = await fetch(url); + const responseText = await response.text(); + + const footpaths: IFootpathIndex = {}; + + if (response.status !== 200) { + EventBus.getInstance().emit(EventType.Warning, `${url} responded with status code ${response.status}`); + } + + if (response.status === 200 && responseText) { + const blob = JSON.parse(responseText); + + for (const entity of blob["@graph"]) { + const id = entity["@id"]; + const footpath = new Footpath(id); + footpath.to = entity["planner:destination"]; + footpath.from = entity["planner:source"]; + footpath.distance = entity["planner:distance"]; + footpaths[id] = footpath; + } + } + + return footpaths; + } +} diff --git a/src/fetcher/footpaths/IFootpathsProvider.ts b/src/fetcher/footpaths/IFootpathsProvider.ts new file mode 100644 index 00000000..656a3383 --- /dev/null +++ b/src/fetcher/footpaths/IFootpathsProvider.ts @@ -0,0 +1,6 @@ +import { IFootpathIndex } from "../../entities/footpaths/footpath"; +import IStop from "../stops/IStop"; + +export default interface IFootpathsProvider { + get: (stop: IStop) => Promise; +} diff --git a/src/fetcher/profiles/IProfileFetcher.ts b/src/fetcher/profiles/IProfileFetcher.ts new file mode 100644 index 00000000..113ca61d --- /dev/null +++ b/src/fetcher/profiles/IProfileFetcher.ts @@ -0,0 +1,6 @@ +import Profile from "../../entities/profile/Profile"; + +export default interface IProfileFetcher { + parseProfileBlob(blob: object, id: string): Promise; + get(url: string): Promise; +} diff --git a/src/fetcher/profiles/IProfileProvider.ts b/src/fetcher/profiles/IProfileProvider.ts new file mode 100644 index 00000000..eb304101 --- /dev/null +++ b/src/fetcher/profiles/IProfileProvider.ts @@ -0,0 +1,9 @@ +import Profile from "../../entities/profile/Profile"; + +export default interface IProfileProvider { + parseDevelopmentProfile(blob: object): Promise; + addProfile(profile: Profile): void; + + getProfile(profileId: string): Promise; + getProfiles(): Promise; +} diff --git a/src/fetcher/profiles/ProfileFetcherDefault.ts b/src/fetcher/profiles/ProfileFetcherDefault.ts new file mode 100644 index 00000000..b8a0206f --- /dev/null +++ b/src/fetcher/profiles/ProfileFetcherDefault.ts @@ -0,0 +1,124 @@ +import { inject, injectable } from "inversify"; +import jsonld = require("jsonld"); +import LDFetch from "ldfetch"; +import CharacteristicProfile from "../../entities/profile/CharacteresticProfile"; +import Profile from "../../entities/profile/Profile"; +import ProfileConclusion from "../../entities/profile/ProfileConclusion"; +import ProfileCondition from "../../entities/profile/ProfileCondition"; +import ProfileRule from "../../entities/profile/ProfileRule"; +import { LDLoader } from "../../loader/ldloader"; +import { ThingView } from "../../loader/views/single"; +import TYPES from "../../types"; +import { PROFILE } from "../../uri/constants"; +import URI from "../../uri/uri"; +import IProfileFetcher from "./IProfileFetcher"; + +@injectable() +export default class ProfileFetcherDefault implements IProfileFetcher { + + protected ldFetch: LDFetch; + protected ldLoader: LDLoader; + + constructor( + @inject(TYPES.LDFetch) ldFetch: LDFetch, + ) { + this.ldFetch = ldFetch; + this.ldLoader = new LDLoader(); + + // unordered collections + this.ldLoader.defineCollection(URI.inNS(PROFILE, "hasAccessRules")); + this.ldLoader.defineCollection(URI.inNS(PROFILE, "hasOnewayRules")); + this.ldLoader.defineCollection(URI.inNS(PROFILE, "hasSpeedRules")); + this.ldLoader.defineCollection(URI.inNS(PROFILE, "hasPriorityRules")); + this.ldLoader.defineCollection(URI.inNS(PROFILE, "hasObstacleRules")); + this.ldLoader.defineCollection(URI.inNS(PROFILE, "hasObstacleTimeRules")); + } + + public async parseProfileBlob(blob: object, id: string): Promise { + const triples = await jsonld.toRDF(blob); + + const [profile] = this.ldLoader.process(triples, [ + this.getView(), + ]); + + profile.id = id; + + return profile; + } + + public async get(url: string): Promise { + const rdfThing = await this.ldFetch.get(url); + const triples = rdfThing.triples; + + const [profile] = this.ldLoader.process(triples, [ + this.getView(), + ]); + + profile.id = url; + + return profile; + } + + protected getView() { + const view = new ThingView(CharacteristicProfile.create); + view.addFilter((entity) => + entity[URI.inNS(PROFILE, "hasAccessRules")] !== undefined || + entity[URI.inNS(PROFILE, "hasOnewayRules")] !== undefined || + entity[URI.inNS(PROFILE, "hasSpeedRules")] !== undefined || + entity[URI.inNS(PROFILE, "hasPriorityRules")] !== undefined || + entity[URI.inNS(PROFILE, "hasObstacleRules")] !== undefined || + entity[URI.inNS(PROFILE, "hasObstacleTimeRules")] !== undefined, + ); + view.addMapping(URI.inNS(PROFILE, "hasAccessRules"), "accessRules", this.getRuleView()); + view.addMapping(URI.inNS(PROFILE, "hasOnewayRules"), "onewayRules", this.getRuleView()); + view.addMapping(URI.inNS(PROFILE, "hasSpeedRules"), "speedRules", this.getRuleView()); + view.addMapping(URI.inNS(PROFILE, "hasPriorityRules"), "priorityRules", this.getRuleView()); + view.addMapping(URI.inNS(PROFILE, "hasObstacleRules"), "obstacleRules", this.getRuleView()); + view.addMapping(URI.inNS(PROFILE, "hasObstacleTimeRules"), "obstacleTimeRules", this.getRuleView()); + view.addMapping(URI.inNS(PROFILE, "hasMaxSpeed"), "maxSpeed"); + view.addMapping(URI.inNS(PROFILE, "usePublicTransport"), "usePublicTransport"); + return view; + } + + protected getRuleView() { + const view = new ThingView(ProfileRule.create); + view.addFilter((entity) => + entity[URI.inNS(PROFILE, "concludes")] !== undefined, + ); + view.addMapping(URI.inNS(PROFILE, "concludes"), "conclusion", this.getConclusionView()); + view.addMapping(URI.inNS(PROFILE, "match"), "condition", this.getConditionView()); + view.addMapping(URI.inNS(PROFILE, "hasOrder"), "order"); + return view; + } + + protected getConditionView() { + const view = new ThingView(ProfileCondition.create); + view.addFilter((entity) => + entity[URI.inNS(PROFILE, "hasPredicate")] !== undefined, + ); + view.addMapping(URI.inNS(PROFILE, "hasPredicate"), "predicate"); + view.addMapping(URI.inNS(PROFILE, "hasObject"), "object"); + return view; + } + + protected getConclusionView() { + const view = new ThingView(ProfileConclusion.create); + view.addFilter((entity) => + (entity[URI.inNS(PROFILE, "hasAccess")] !== undefined) || + (entity[URI.inNS(PROFILE, "isOneway")] !== undefined) || + (entity[URI.inNS(PROFILE, "isReversed")] !== undefined) || + (entity[URI.inNS(PROFILE, "hasSpeed")] !== undefined) || + (entity[URI.inNS(PROFILE, "isObstacle")] !== undefined) || + (entity[URI.inNS(PROFILE, "hasPriority")] !== undefined) || + (entity[URI.inNS(PROFILE, "hasObstacleTime")] !== undefined), + ); + view.addMapping(URI.inNS(PROFILE, "hasAccess"), "hasAccess"); + view.addMapping(URI.inNS(PROFILE, "isOneway"), "isOneway"); + view.addMapping(URI.inNS(PROFILE, "isReversed"), "isReversed"); + view.addMapping(URI.inNS(PROFILE, "hasSpeed"), "speed"); + view.addMapping(URI.inNS(PROFILE, "isObstacle"), "isObstacle"); + view.addMapping(URI.inNS(PROFILE, "hasPriority"), "priority"); + view.addMapping(URI.inNS(PROFILE, "hasObstacleTime"), "obstacleTime"); + return view; + } +} diff --git a/src/fetcher/profiles/ProfileProviderDefault.ts b/src/fetcher/profiles/ProfileProviderDefault.ts new file mode 100644 index 00000000..a6123b44 --- /dev/null +++ b/src/fetcher/profiles/ProfileProviderDefault.ts @@ -0,0 +1,58 @@ +import { inject, injectable } from "inversify"; +import PedestrianProfile from "../../entities/profile/PedestrianProfile"; +import Profile from "../../entities/profile/Profile"; +import TYPES from "../../types"; +import IProfileFetcher from "./IProfileFetcher"; +import IProfileProvider from "./IProfileProvider"; + +interface IProfileMap { + [label: string]: Promise; +} + +@injectable() +export default class ProfileProviderDefault implements IProfileProvider { + // todo, fetcher that loads a profile from a URI + // todo, profiles per location + // e.g. bicycle near a specific station + + private profiles: IProfileMap; + private fetcher: IProfileFetcher; + + private developmentProfile: Profile; // does not have a persistent id, will change often + private developmentProfileCounter: number; + + constructor( + @inject(TYPES.ProfileFetcher) fetcher: IProfileFetcher, + ) { + this.profiles = {}; + this.fetcher = fetcher; + this.developmentProfile = undefined; + this.developmentProfileCounter = 0; + } + + public async parseDevelopmentProfile(blob: object): Promise { + this.developmentProfileCounter += 1; + const newProfile = await this.fetcher.parseProfileBlob(blob, "" + this.developmentProfileCounter); + if (this.developmentProfile) { + delete this.profiles[this.developmentProfile.getID()]; + } + this.developmentProfile = newProfile; + this.profiles[this.developmentProfile.getID()] = Promise.resolve(newProfile); + return newProfile.getID(); + } + + public addProfile(profile: Profile) { + this.profiles[profile.getID()] = Promise.resolve(profile); + } + + public getProfile(profileId: string): Promise { + if (this.profiles[profileId] === undefined) { + this.profiles[profileId] = this.fetcher.get(profileId); + } + return this.profiles[profileId]; + } + + public getProfiles(): Promise { + return Promise.all(Object.values(this.profiles)); + } +} diff --git a/src/fetcher/stops/IStop.ts b/src/fetcher/stops/IStop.ts index b8adbf19..7b4e0a62 100644 --- a/src/fetcher/stops/IStop.ts +++ b/src/fetcher/stops/IStop.ts @@ -1,3 +1,5 @@ +import { DurationMs } from "../../interfaces/units"; + /** * Interface for a Stop. This describes an actual physical stop, e.g. a train or a bus stop * @property id An identifier for the stop that gets used in IConnections @@ -8,4 +10,5 @@ export default interface IStop { name: string; longitude: number; latitude: number; + avgStopTimes?: DurationMs; } diff --git a/src/fetcher/stops/StopsFetcherRaw.ts b/src/fetcher/stops/StopsFetcherRaw.ts new file mode 100644 index 00000000..85697359 --- /dev/null +++ b/src/fetcher/stops/StopsFetcherRaw.ts @@ -0,0 +1,110 @@ +import { inject, injectable } from "inversify"; +import LDFetch from "ldfetch"; +import { EventType } from "../.."; +import EventBus from "../../events/EventBus"; +import TYPES from "../../types"; +import IStop from "./IStop"; +import IStopsFetcher from "./IStopsFetcher"; + +interface IPartialStopMap { + [stopId: string]: Partial; +} + +interface IStopMap { + [stopId: string]: IStop; +} + +@injectable() +// tslint:disable: no-string-literal +export default class StopsFetcherRaw implements IStopsFetcher { + + private accessUrl: string; + + private ldFetch: LDFetch; + private loadPromise: Promise; + private stops: IStopMap; + + constructor( + @inject(TYPES.LDFetch) ldFetch: LDFetch, + ) { + this.ldFetch = ldFetch; + } + + public setAccessUrl(accessUrl: string) { + this.accessUrl = accessUrl; + } + + public prefetchStops(): void { + this.ensureStopsLoaded(); + } + + public async getStopById(stopId: string): Promise { + await this.ensureStopsLoaded(); + + return this.stops[stopId]; + } + + public async getAllStops(): Promise { + await this.ensureStopsLoaded(); + + return Object.values(this.stops); + } + + private async ensureStopsLoaded() { + if (!this.loadPromise && !this.stops) { + this.loadStops(); + } + + if (this.loadPromise) { + await this.loadPromise; + } + } + + private loadStops() { + this.loadPromise = this.getByUrl(this.accessUrl) + .then((stops) => { + this.stops = stops; + this.loadPromise = null; + }) + .catch((reason) => { + console.log(reason); + }); + } + + private async getByUrl(url: string): Promise { + const beginTime = new Date(); + + const response = await fetch(url); + const responseText = await response.text(); + + const stops: IStopMap = {}; + + if (response.status !== 200) { + EventBus.getInstance().emit(EventType.Warning, `${url} responded with status code ${response.status}`); + } + + if (response.status === 200 && responseText) { + const blob = JSON.parse(responseText); + + for (const entity of blob["@graph"]) { + const id = entity["@id"]; + const latitudeRaw = entity["http://www.w3.org/2003/01/geo/wgs84_pos#lat"] || entity["latitude"]; + const longitudeRaw = entity["http://www.w3.org/2003/01/geo/wgs84_pos#long"] || entity["longitude"]; + const stopTimeRaw = entity["avgStopTimes"] || 0; + const stop: IStop = { + id: entity["@id"], + latitude: parseFloat(latitudeRaw), + longitude: parseFloat(longitudeRaw), + name: entity["name"], + avgStopTimes: parseFloat(stopTimeRaw) * 1000, + }; + stops[id] = stop; + } + } + + const duration = (new Date()).getTime() - beginTime.getTime(); + EventBus.getInstance().emit(EventType.LDFetchGet, url, duration); + + return stops; + } +} diff --git a/src/fetcher/stops/ld-fetch/StopsFetcherLDFetch.ts b/src/fetcher/stops/ld-fetch/StopsFetcherLDFetch.ts index 8812fc53..6311d3e8 100644 --- a/src/fetcher/stops/ld-fetch/StopsFetcherLDFetch.ts +++ b/src/fetcher/stops/ld-fetch/StopsFetcherLDFetch.ts @@ -27,6 +27,7 @@ export default class StopsFetcherLDFetch implements IStopsFetcher { @inject(TYPES.LDFetch) ldFetch: LDFetch, ) { this.ldFetch = ldFetch; + // FIXME does this ever do something? this.loadStops(); } diff --git a/src/fetcher/tiles/IRoutableTileFetcher.ts b/src/fetcher/tiles/IRoutableTileFetcher.ts new file mode 100644 index 00000000..74af371d --- /dev/null +++ b/src/fetcher/tiles/IRoutableTileFetcher.ts @@ -0,0 +1,5 @@ +import { RoutableTile } from "../../entities/tiles/tile"; + +export default interface IRoutableTileFetcher { + get(url: string): Promise; +} diff --git a/src/fetcher/tiles/IRoutableTileProvider.ts b/src/fetcher/tiles/IRoutableTileProvider.ts new file mode 100644 index 00000000..f8523aaf --- /dev/null +++ b/src/fetcher/tiles/IRoutableTileProvider.ts @@ -0,0 +1,19 @@ +import { RoutableTileCoordinate } from "../../entities/tiles/coordinate"; +import { RoutableTileSet } from "../../entities/tiles/set"; +import { RoutableTile } from "../../entities/tiles/tile"; +import ILocation from "../../interfaces/ILocation"; + +export default interface IRoutableTileProvider { + wait(): Promise; + + getIdForLocation(zoom: number, location: ILocation): string; + getIdForTileCoords(coordinate: RoutableTileCoordinate): string; + + getByUrl(url: string): Promise; + getByLocation(zoom: number, location: ILocation): Promise; + getByTileCoords(coordinate: RoutableTileCoordinate): Promise; + + getMultipleByUrl(urls: string[]): Promise; + getmultipleByLocation(zoom: number, locations: ILocation[]): Promise; + getMultipleByTileCoords(coordinates: RoutableTileCoordinate[]): Promise; +} diff --git a/src/fetcher/tiles/RoutableTileFetcherDefault.test.ts b/src/fetcher/tiles/RoutableTileFetcherDefault.test.ts new file mode 100644 index 00000000..0d18e466 --- /dev/null +++ b/src/fetcher/tiles/RoutableTileFetcherDefault.test.ts @@ -0,0 +1,34 @@ +import "jest"; +import LDFetch from "ldfetch"; +import RoutableTileRegistry from "../../entities/tiles/registry"; +import PathfinderProvider from "../../pathfinding/PathfinderProvider"; +import ProfileFetcherDefault from "../profiles/ProfileFetcherDefault"; +import ProfileProviderDefault from "../profiles/ProfileProviderDefault"; +import RoutableTileFetcherDefault from "./RoutableTileFetcherDefault"; + +const ldfetch = new LDFetch({ headers: { Accept: "application/ld+json" } }); +const registry = new RoutableTileRegistry(); +const profileProvider = new ProfileProviderDefault(new ProfileFetcherDefault(ldfetch)); +const fetcher = new RoutableTileFetcherDefault( + ldfetch, + new PathfinderProvider(undefined, undefined, registry, profileProvider), + registry); + +test("[RoutableTileFetcherDefault] data completeness", async () => { + jest.setTimeout(15000); + + const expectedNodes: Set = new Set(); + const tile = await fetcher.get("https://tiles.openplanner.team/planet/14/8361/5482/"); + for (const wayId of tile.getWays()) { + const way = registry.getWay(wayId); + for (const segment of way.segments) { + for (const node of segment) { + expectedNodes.add(node); + } + } + } + + for (const id of expectedNodes) { + expect(tile.getNodes().has(id)); + } +}); diff --git a/src/fetcher/tiles/RoutableTileFetcherDefault.ts b/src/fetcher/tiles/RoutableTileFetcherDefault.ts new file mode 100644 index 00000000..7fc0d8da --- /dev/null +++ b/src/fetcher/tiles/RoutableTileFetcherDefault.ts @@ -0,0 +1,95 @@ +import { inject, injectable } from "inversify"; +import LDFetch from "ldfetch"; +import { IRoutableTileNodeIndex, RoutableTileNode } from "../../entities/tiles/node"; +import RoutableTileRegistry from "../../entities/tiles/registry"; +import { RoutableTile } from "../../entities/tiles/tile"; +import { IRoutableTileWayIndex, RoutableTileWay } from "../../entities/tiles/way"; +import getOsmTagMapping from "../../enums/OSMTags"; +import { LDLoader } from "../../loader/ldloader"; +import { IndexThingView } from "../../loader/views"; +import PathfinderProvider from "../../pathfinding/PathfinderProvider"; +import TYPES from "../../types"; +import { GEO, OSM, RDF, RDFS } from "../../uri/constants"; +import URI from "../../uri/uri"; +import IRoutableTileFetcher from "./IRoutableTileFetcher"; + +@injectable() +export default class RoutableTileFetcherDefault implements IRoutableTileFetcher { + + protected ldFetch: LDFetch; + protected ldLoader: LDLoader; + protected pathfinderProvider: PathfinderProvider; + protected routableTileRegistry: RoutableTileRegistry; + + constructor( + @inject(TYPES.LDFetch) ldFetch: LDFetch, + @inject(TYPES.PathfinderProvider) pathfinderProvider: PathfinderProvider, + @inject(TYPES.RoutableTileRegistry) routableTileRegistry: RoutableTileRegistry, + ) { + this.ldFetch = ldFetch; + this.ldLoader = new LDLoader(); + this.ldLoader.defineCollection(URI.inNS(OSM, "hasNodes")); // unordered collection + this.pathfinderProvider = pathfinderProvider; + this.routableTileRegistry = routableTileRegistry; + } + + public async get(url: string): Promise { + const rdfThing = await this.ldFetch.get(url); + const triples = rdfThing.triples; + + let nodes: IRoutableTileNodeIndex; + let ways: IRoutableTileWayIndex; + + [nodes, ways] = this.ldLoader.process(triples, [ + this.getNodesView(), + this.getWaysView(), + ]); + + return this.processTileData(url, nodes, ways); + } + + protected processTileData(url: string, nodes: IRoutableTileNodeIndex, ways: IRoutableTileWayIndex) { + this.pathfinderProvider.registerEdges(ways, nodes); + + for (const node of Object.values(nodes)) { + this.routableTileRegistry.registerNode(node); + } + + for (const way of Object.values(ways)) { + this.routableTileRegistry.registerWay(way); + } + + return new RoutableTile(url, new Set(Object.keys(nodes)), new Set(Object.keys(ways))); + } + + protected getNodesView() { + const nodesView = new IndexThingView(RoutableTileNode.create); + nodesView.addFilter((entity) => + entity[URI.inNS(GEO, "lat")] !== undefined && entity[URI.inNS(GEO, "long")] !== undefined, + ); + nodesView.addMapping(URI.inNS(GEO, "lat"), "latitude"); + nodesView.addMapping(URI.inNS(GEO, "long"), "longitude"); + + for (const [tag, field] of Object.entries(getOsmTagMapping())) { + nodesView.addMapping(tag, field); + } + + return nodesView; + } + + protected getWaysView() { + const waysView = new IndexThingView(RoutableTileWay.create); + waysView.addFilter((entity) => + entity[URI.inNS(RDF, "type")] === URI.inNS(OSM, "Way"), + ); + + waysView.addMapping(URI.inNS(OSM, "hasNodes"), "segments"); + waysView.addMapping(URI.inNS(OSM, "name"), "name"); + + for (const [tag, field] of Object.entries(getOsmTagMapping())) { + waysView.addMapping(tag, field); + } + + return waysView; + } +} diff --git a/src/fetcher/tiles/RoutableTileFetcherExtended.ts b/src/fetcher/tiles/RoutableTileFetcherExtended.ts new file mode 100644 index 00000000..3ee64b20 --- /dev/null +++ b/src/fetcher/tiles/RoutableTileFetcherExtended.ts @@ -0,0 +1,58 @@ +import { inject, injectable } from "inversify"; +import LDFetch from "ldfetch"; +import RoutableTileRegistry from "../../entities/tiles/registry"; +import { RoutableTile } from "../../entities/tiles/tile"; +import PathfinderProvider from "../../pathfinding/PathfinderProvider"; +import TYPES from "../../types"; +import { ROUTE } from "../../uri/constants"; +import URI from "../../uri/uri"; +import RoutableTileFetcherDefault from "./RoutableTileFetcherDefault"; + +@injectable() +export default class RoutableTileFetcherExtended extends RoutableTileFetcherDefault { + + constructor( + @inject(TYPES.LDFetch) ldFetch: LDFetch, + @inject(TYPES.PathfinderProvider) pathfinder: PathfinderProvider, + @inject(TYPES.RoutableTileRegistry) routableTileRegistry: RoutableTileRegistry, + ) { + super(ldFetch, pathfinder, routableTileRegistry); + } + + public async get(url: string): Promise { + const lolJs = url.split("/"); + const tileX = lolJs[lolJs.length - 2]; + const tileY = lolJs[lolJs.length - 1]; + const otherUrl = `https://www.hdelva.be/tiles/inferred/${tileX}/${tileY}`; + + const basePromise = this.ldFetch.get(url); + const otherPromise = this.ldFetch.get(otherUrl); + + const baseResponse = await basePromise; + const baseTriples = baseResponse.triples; + + let otherTriples = []; + try { + const otherResponse = await otherPromise; + otherTriples = otherResponse.triples; + + this.ldLoader.disambiguateBlankNodes(baseTriples, "base"); + this.ldLoader.disambiguateBlankNodes(otherTriples, "other"); + } catch { + // not that important + } + + const [nodes, ways] = this.ldLoader.process(baseTriples.concat(otherTriples), [ + this.getNodesView(), + this.getWaysView(), + ]); + + return this.processTileData(url, nodes, ways); + } + + protected getWaysView() { + const original = super.getWaysView(); + original.addMapping(URI.inNS(ROUTE, "reachable"), "reachable"); + return original; + } +} diff --git a/src/fetcher/tiles/RoutableTileFetcherRaw.ts b/src/fetcher/tiles/RoutableTileFetcherRaw.ts new file mode 100644 index 00000000..288806ec --- /dev/null +++ b/src/fetcher/tiles/RoutableTileFetcherRaw.ts @@ -0,0 +1,134 @@ +import fetch from "cross-fetch"; +import { inject, injectable } from "inversify"; +import { IRoutableTileNodeIndex, RoutableTileNode } from "../../entities/tiles/node"; +import RoutableTileRegistry from "../../entities/tiles/registry"; +import { RoutableTile } from "../../entities/tiles/tile"; +import { IRoutableTileWayIndex, RoutableTileWay } from "../../entities/tiles/way"; +import EventBus from "../../events/EventBus"; +import EventType from "../../events/EventType"; +import PathfinderProvider from "../../pathfinding/PathfinderProvider"; +import TYPES from "../../types"; +import { OSM } from "../../uri/constants"; +import URI from "../../uri/uri"; +import IRoutableTileFetcher from "./IRoutableTileFetcher"; + +@injectable() +export default class RoutableTileFetcherRaw implements IRoutableTileFetcher { + + protected mapping: object; + protected pathfinderProvider: PathfinderProvider; + protected routableTileRegistry: RoutableTileRegistry; + + constructor( + @inject(TYPES.PathfinderProvider) pathfinderProvider: PathfinderProvider, + @inject(TYPES.RoutableTileRegistry) routableTileRegistry: RoutableTileRegistry, + ) { + this.pathfinderProvider = pathfinderProvider; + this.routableTileRegistry = routableTileRegistry; + this.mapping = {}; + + this.mapping["osm:barrier"] = "barrierKind"; + this.mapping["osm:access"] = "accessRestrictions"; + this.mapping["osm:bicycle"] = "bicycleAccessRestrictions"; + this.mapping["osm:construction"] = "constructionKind"; + this.mapping["osm:crossing"] = "crossingKind"; + this.mapping["osm:cycleway"] = "cyclewayKind"; + this.mapping["osm:footway"] = "footwayKind"; + this.mapping["osm:highway"] = "highwayKind"; + this.mapping["osm:maxspeed"] = "maxSpeed"; + this.mapping["osm:motor_vehicle"] = "motorVehicleAccessRestrictions"; + this.mapping["osm:motorcar"] = "motorcarAccessRestrictions"; + this.mapping["osm:oneway_bicycle"] = "onewayBicycleKind"; + this.mapping["osm:oneway"] = "onewayKind"; + this.mapping["osm:smoothness"] = "smoothnessKind"; + this.mapping["osm:surface"] = "surfaceKind"; + this.mapping["osm:tracktype"] = "trackType"; + this.mapping["osm:vehicle"] = "vehicleAccessRestrictions"; + } + + public async get(url: string): Promise { + const beginTime = new Date(); + const response = await fetch(url); + const responseText = await response.text(); + if (response.status !== 200) { + EventBus.getInstance().emit(EventType.Warning, `${url} responded with status code ${response.status}`); + } + if (response.status === 200 && responseText) { + const blob = JSON.parse(responseText); + + const nodes: IRoutableTileNodeIndex = {}; + const ways: IRoutableTileWayIndex = {}; + + for (const entity of blob["@graph"]) { + if (entity["@type"] === "osm:Node") { + const node = this.createNode(entity); + nodes[node.id] = node; + } else if (entity["@type"] === "osm:Way") { + const way = this.createWay(entity); + ways[way.id] = way; + } + } + + const duration = (new Date()).getTime() - beginTime.getTime(); + EventBus.getInstance().emit(EventType.LDFetchGet, url, duration); + + return this.processTileData(url, nodes, ways); + } else { + return new RoutableTile(url, new Set(), new Set()); + } + } + + protected processTileData(url: string, nodes: IRoutableTileNodeIndex, ways: IRoutableTileWayIndex) { + this.pathfinderProvider.registerEdges(ways, nodes); + + for (const node of Object.values(nodes)) { + this.routableTileRegistry.registerNode(node); + } + + for (const way of Object.values(ways)) { + this.routableTileRegistry.registerWay(way); + } + + return new RoutableTile(url, new Set(Object.keys(nodes)), new Set(Object.keys(ways))); + } + + private createNode(blob): RoutableTileNode { + const id = blob["@id"]; + const node = new RoutableTileNode(id); + node.latitude = parseFloat(blob["geo:lat"]); + node.longitude = parseFloat(blob["geo:long"]); + + for (const [tag, field] of Object.entries(this.mapping)) { + if (blob[tag] && !node[field]) { + node[field] = URI.fakeExpand(OSM, blob[tag]); + } + } + + return node; + } + + private createWay(blob): RoutableTileWay { + const id = blob["@id"]; + const way = new RoutableTileWay(id); + if (blob["osm:maxspeed"]) { + way.maxSpeed = parseFloat(blob["osm:maxspeed"]); + } + if (blob["osm:hasNodes"]) { + way.segments = [blob["osm:hasNodes"]]; + } else { + const weights = blob["osm:hasEdges"]; + way.segments = [weights["osm:hasNodes"]]; + way.weights = [weights["osm:hasWeights"]]; + } + + way.name = blob["osm:name"]; + + for (const [tag, field] of Object.entries(this.mapping)) { + if (blob[tag] && !way[field]) { + way[field] = URI.fakeExpand(OSM, blob[tag]); + } + } + + return way; + } +} diff --git a/src/fetcher/tiles/RoutableTileProviderDefault.ts b/src/fetcher/tiles/RoutableTileProviderDefault.ts new file mode 100644 index 00000000..570290c0 --- /dev/null +++ b/src/fetcher/tiles/RoutableTileProviderDefault.ts @@ -0,0 +1,96 @@ +import { inject, injectable } from "inversify"; +import { RoutableTileCoordinate } from "../../entities/tiles/coordinate"; +import RoutableTileRegistry from "../../entities/tiles/registry"; +import { RoutableTileSet } from "../../entities/tiles/set"; +import { IRoutableTileIndex, RoutableTile } from "../../entities/tiles/tile"; +import ILocation from "../../interfaces/ILocation"; +import TYPES from "../../types"; +import { lat_to_tile, long_to_tile } from "../../util/Tiles"; +import IRoutableTileFetcher from "./IRoutableTileFetcher"; +import IRoutableTileProvider from "./IRoutableTileProvider"; + +@injectable() +export default class RoutableTileProviderDefault implements IRoutableTileProvider { + + protected fetcher: IRoutableTileFetcher; + protected registry: RoutableTileRegistry; + protected tiles: IRoutableTileIndex = {}; + + constructor( + @inject(TYPES.RoutableTileFetcher) fetcher: IRoutableTileFetcher, + @inject(TYPES.RoutableTileRegistry) registry: RoutableTileRegistry, + ) { + this.fetcher = fetcher; + this.registry = registry; + } + + public async wait() { + await Promise.all(Object.values(this.tiles)); + } + + public getIdForLocation(zoom: number, location: ILocation): string { + const y = lat_to_tile(location.latitude, zoom); + const x = long_to_tile(location.longitude, zoom); + const coordinate = new RoutableTileCoordinate(zoom, x, y); + return this.getIdForTileCoords(coordinate); + } + + public getIdForTileCoords(coordinate: RoutableTileCoordinate): string { + return `https://tiles.openplanner.team/planet/${coordinate.zoom}/${coordinate.x}/${coordinate.y}`; + } + + public getByLocation(zoom: number, location: ILocation): Promise { + const y = this.lat2tile(location.latitude, zoom); + const x = this.long2tile(location.longitude, zoom); + const coordinate = new RoutableTileCoordinate(zoom, x, y); + return this.getByTileCoords(coordinate); + } + + public async getByTileCoords(coordinate: RoutableTileCoordinate): Promise { + const url = this.getIdForTileCoords(coordinate); + const tile = await this.getByUrl(url); + tile.coordinate = coordinate; // todo, get these from server response + return tile; + } + + public async getByUrl(url: string): Promise { + if (!this.tiles[url]) { + this.tiles[url] = this.fetcher.get(url); + } + + return await this.tiles[url]; + } + + public async getMultipleByUrl(urls: string[]): Promise { + const tiles = await Promise.all(urls.map((url) => { + return this.getByUrl(url); + })); + + return new RoutableTileSet(tiles); + } + + public async getmultipleByLocation(zoom: number, locations: ILocation[]): Promise { + const tiles = await Promise.all(locations.map((location) => { + return this.getByLocation(zoom, location); + })); + + return new RoutableTileSet(tiles); + } + + public async getMultipleByTileCoords(coordinates: RoutableTileCoordinate[]): Promise { + const tiles = await Promise.all(coordinates.map((coordinate) => { + return this.getByTileCoords(coordinate); + })); + + return new RoutableTileSet(tiles); + } + + private long2tile(lon: number, zoom: number) { + return (Math.floor((lon + 180) / 360 * Math.pow(2, zoom))); + } + + private lat2tile(lat: number, zoom: number) { + return (Math.floor((1 - Math.log(Math.tan(lat * Math.PI / 180) + 1 + / Math.cos(lat * Math.PI / 180)) / Math.PI) / 2 * Math.pow(2, zoom))); + } +} diff --git a/src/fetcher/tiles/RoutableTileProviderTransit.ts b/src/fetcher/tiles/RoutableTileProviderTransit.ts new file mode 100644 index 00000000..d8a068e7 --- /dev/null +++ b/src/fetcher/tiles/RoutableTileProviderTransit.ts @@ -0,0 +1,21 @@ +import { inject, injectable } from "inversify"; +import { RoutableTileCoordinate } from "../../entities/tiles/coordinate"; +import RoutableTileRegistry from "../../entities/tiles/registry"; +import TYPES from "../../types"; +import IRoutableTileFetcher from "./IRoutableTileFetcher"; +import RoutableTileProviderDefault from "./RoutableTileProviderDefault"; + +@injectable() +export default class RoutableTileProviderTransit extends RoutableTileProviderDefault { + + constructor( + @inject(TYPES.RoutableTileFetcher) fetcher: IRoutableTileFetcher, + @inject(TYPES.RoutableTileRegistry) registry: RoutableTileRegistry, + ) { + super(fetcher, registry); + } + + public getIdForTileCoords(coordinate: RoutableTileCoordinate): string { + return `https://hdelva.be/tiles/reduced/${coordinate.zoom}/${coordinate.x}/${coordinate.y}`; + } +} diff --git a/src/index.ts b/src/index.ts index 99ba7489..42839df8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,32 @@ import "isomorphic-fetch"; import "reflect-metadata"; -import Planner from "./Planner"; -export default Planner; +import IsochroneGenerator from "./analytics/isochrones/main"; +import EventBus_ from "./events/EventBus"; +import EventType from "./events/EventType"; +import BasicTrainPlanner from "./planner/configurations/BasicTrainPlanner"; +import DissectPlanner from "./planner/configurations/DissectPlanner"; +import TransitCarPlanner from "./planner/configurations/TransitCarPlanner"; +import TriangleDemoPlanner from "./planner/configurations/TriangleDemoPlanner"; +import Units from "./util/Units"; + +export { default as EventType } from "./events/EventType"; +export { default as IsochroneGenerator } from "./analytics/isochrones/main"; +export { default as Units } from "./util/Units"; +export { default as BasicTrainPlanner } from "./planner/configurations/BasicTrainPlanner"; +export { default as DissectPlanner } from "./planner/configurations/DissectPlanner"; +export { default as TransitCarPlanner } from "./planner/configurations/TransitCarPlanner"; +export { default as TriangleDemoPlanner } from "./planner/configurations/TriangleDemoPlanner"; + +export const EventBus = EventBus_.getInstance(); + +export default { + EventType, + IsochroneGenerator, + Units, + EventBus, + BasicTrainPlanner, + DissectPlanner, + TransitCarPlanner, + TriangleDemoPlanner, +}; diff --git a/src/interfaces/ILeg.ts b/src/interfaces/ILeg.ts new file mode 100644 index 00000000..1d1da4de --- /dev/null +++ b/src/interfaces/ILeg.ts @@ -0,0 +1,18 @@ +import TravelMode from "../enums/TravelMode"; +import ILocation from "./ILocation"; +import IStep from "./IStep"; +import { DistanceM, DurationMs } from "./units"; + +export default interface ILeg { + getExpectedDuration(): DurationMs; + getMinimumDuration(): DurationMs; + getAverageDuration(): DurationMs; + getMaximumDuration(): DurationMs; + getDistance(): DistanceM; + getTravelMode(): TravelMode; + getSteps(): IStep[]; + getStartTime(): Date; + getStopTime(): Date; + getStartLocation(): ILocation; + getStopLocation(): ILocation; +} diff --git a/src/interfaces/IPath.ts b/src/interfaces/IPath.ts index efbfce40..743d6a95 100644 --- a/src/interfaces/IPath.ts +++ b/src/interfaces/IPath.ts @@ -1,5 +1,12 @@ -import IStep from "./IStep"; +import ILeg from "./ILeg"; +import IQuery from "./IQuery"; +import { DurationMs } from "./units"; export default interface IPath { - steps: IStep[]; + legs: ILeg[]; + + getDepartureTime(query: IQuery): Date; + getArrivalTime(query: IQuery): Date; + getTravelTime(): DurationMs; + getTransferTime(): DurationMs; } diff --git a/src/interfaces/IQuery.ts b/src/interfaces/IQuery.ts index 4e81ab42..429c0ed2 100644 --- a/src/interfaces/IQuery.ts +++ b/src/interfaces/IQuery.ts @@ -1,13 +1,15 @@ +import Profile from "../entities/profile/Profile"; import ILocation from "./ILocation"; import { DistanceM, DurationMs, SpeedKmH } from "./units"; export default interface IQuery { from?: string | string[] | ILocation | ILocation[]; to?: string | string[] | ILocation | ILocation[]; + profileID?: string; minimumDepartureTime?: Date; maximumArrivalTime?: Date; roadOnly?: boolean; - publicTransportOnly?: boolean; + roadNetworkOnly?: boolean; walkingSpeed?: SpeedKmH; minimumWalkingSpeed?: SpeedKmH; maximumWalkingSpeed?: SpeedKmH; diff --git a/src/interfaces/IStep.ts b/src/interfaces/IStep.ts index db6bbaa8..86f05e64 100644 --- a/src/interfaces/IStep.ts +++ b/src/interfaces/IStep.ts @@ -1,4 +1,3 @@ -import TravelMode from "../enums/TravelMode"; import ILocation from "./ILocation"; import IProbabilisticValue from "./IProbabilisticValue"; import { DistanceM, DurationMs } from "./units"; @@ -6,7 +5,6 @@ import { DistanceM, DurationMs } from "./units"; export default interface IStep { startLocation: ILocation; stopLocation: ILocation; - travelMode: TravelMode; startTime?: Date; stopTime?: Date; duration: IProbabilisticValue; diff --git a/src/inversify.config.ts b/src/inversify.config.ts index a5ec3b50..395482e1 100644 --- a/src/inversify.config.ts +++ b/src/inversify.config.ts @@ -1,29 +1,52 @@ +import { EventEmitter } from "events"; import { Container, interfaces } from "inversify"; import Catalog from "./Catalog"; import catalogDeLijn from "./catalog.delijn"; +import catalogMivb from "./catalog.mivb"; import catalogNmbs from "./catalog.nmbs"; +import catalogTec from "./catalog.tec"; import Context from "./Context"; +import RoutableTileRegistry from "./entities/tiles/registry"; import ReachableStopsSearchPhase from "./enums/ReachableStopsSearchPhase"; +import RoutingPhase from "./enums/RoutingPhase"; import TravelMode from "./enums/TravelMode"; -import ConnectionsProviderMerge from "./fetcher/connections/ConnectionsProviderMerge"; +import ConnectionsFetcherRaw from "./fetcher/connections/ConnectionsFetcherRaw"; +import ConnectionsProviderDefault from "./fetcher/connections/ConnectionsProviderDefault"; import IConnectionsFetcher from "./fetcher/connections/IConnectionsFetcher"; import IConnectionsProvider from "./fetcher/connections/IConnectionsProvider"; -import ConnectionsFetcherLazy from "./fetcher/connections/lazy/ConnectionsFetcherLazy"; -import ConnectionsProviderPrefetch from "./fetcher/connections/prefetch/ConnectionsProviderPrefetch"; +import FootpathsProviderDefault from "./fetcher/footpaths/FootpathsProviderDefault"; +import IFootpathsFetcher from "./fetcher/footpaths/IFootpathsProvider"; import LDFetch from "./fetcher/LDFetch"; +import IProfileFetcher from "./fetcher/profiles/IProfileFetcher"; +import IProfileProvider from "./fetcher/profiles/IProfileProvider"; +import ProfileFetcherDefault from "./fetcher/profiles/ProfileFetcherDefault"; +import ProfileProviderDefault from "./fetcher/profiles/ProfileProviderDefault"; import IStopsFetcher from "./fetcher/stops/IStopsFetcher"; import IStopsProvider from "./fetcher/stops/IStopsProvider"; import StopsFetcherLDFetch from "./fetcher/stops/ld-fetch/StopsFetcherLDFetch"; import StopsProviderDefault from "./fetcher/stops/StopsProviderDefault"; -import CSAProfile from "./planner/public-transport/CSAProfile"; +import IRoutableTileFetcher from "./fetcher/tiles/IRoutableTileFetcher"; +import IRoutableTileProvider from "./fetcher/tiles/IRoutableTileProvider"; +import RoutableTileFetcherDefault from "./fetcher/tiles/RoutableTileFetcherDefault"; +import RoutableTileFetcherExtended from "./fetcher/tiles/RoutableTileFetcherExtended"; +import RoutableTileFetcherRaw from "./fetcher/tiles/RoutableTileFetcherRaw"; +import RoutableTileProviderDefault from "./fetcher/tiles/RoutableTileProviderDefault"; +import RoutableTileProviderTransit from "./fetcher/tiles/RoutableTileProviderTransit"; + +import { LDLoader } from "./loader/ldloader"; +import DijkstraTree from "./pathfinding/dijkstra-tree/DijkstraTree"; +import { Dijkstra } from "./pathfinding/dijkstra/Dijkstra"; +import { IShortestPathAlgorithm, IShortestPathTreeAlgorithm } from "./pathfinding/pathfinder"; +import PathfinderProvider from "./pathfinding/PathfinderProvider"; +import CSAEarliestArrival from "./planner/public-transport/CSAEarliestArrival"; import IJourneyExtractor from "./planner/public-transport/IJourneyExtractor"; import IPublicTransportPlanner from "./planner/public-transport/IPublicTransportPlanner"; import JourneyExtractorProfile from "./planner/public-transport/JourneyExtractorProfile"; import IRoadPlanner from "./planner/road/IRoadPlanner"; -import RoadPlannerBirdsEye from "./planner/road/RoadPlannerBirdsEye"; +import RoadPlannerPathfinding from "./planner/road/RoadPlannerPathfinding"; import IReachableStopsFinder from "./planner/stops/IReachableStopsFinder"; -import ReachableStopsFinderOnlySelf from "./planner/stops/ReachableStopsFinderOnlySelf"; -import ReachableStopsFinderRoadPlannerCached from "./planner/stops/ReachableStopsFinderRoadPlannerCached"; +import ReachableStopsFinderDelaunay from "./planner/stops/ReachableStopsFinderDelaunay"; +import ReachableStopsFinderFootpaths from "./planner/stops/ReachableStopsFinderFootpaths"; import QueryRunnerExponential from "./query-runner/exponential/QueryRunnerExponential"; import ILocationResolver from "./query-runner/ILocationResolver"; import IQueryRunner from "./query-runner/IQueryRunner"; @@ -36,34 +59,38 @@ container.bind(TYPES.QueryRunner).to(QueryRunnerExponential); container.bind(TYPES.LocationResolver).to(LocationResolverConvenience); container.bind(TYPES.PublicTransportPlanner) - .to(CSAProfile); + .to(CSAEarliestArrival); container.bind>(TYPES.PublicTransportPlannerFactory) .toAutoFactory(TYPES.PublicTransportPlanner); container.bind(TYPES.RoadPlanner) - .to(RoadPlannerBirdsEye); + .to(RoadPlannerPathfinding); + +container.bind(TYPES.ShortestPathTreeAlgorithm).to(DijkstraTree).inSingletonScope(); +container.bind(TYPES.ShortestPathAlgorithm).to(Dijkstra).inSingletonScope(); +container.bind(TYPES.PathfinderProvider).to(PathfinderProvider).inSingletonScope(); +container.bind(TYPES.ProfileFetcher).to(ProfileFetcherDefault).inSingletonScope(); +container.bind(TYPES.ProfileProvider).to(ProfileProviderDefault).inSingletonScope(); +// TODO, make this a fixed property of the planner itself container.bind(TYPES.JourneyExtractor) .to(JourneyExtractorProfile); container.bind(TYPES.ReachableStopsFinder) - .to(ReachableStopsFinderRoadPlannerCached).whenTargetTagged("phase", ReachableStopsSearchPhase.Initial); + .to(ReachableStopsFinderDelaunay).whenTargetTagged("phase", ReachableStopsSearchPhase.Initial); container.bind(TYPES.ReachableStopsFinder) - .to(ReachableStopsFinderOnlySelf).whenTargetTagged("phase", ReachableStopsSearchPhase.Transfer); + .to(ReachableStopsFinderFootpaths).whenTargetTagged("phase", ReachableStopsSearchPhase.Transfer); container.bind(TYPES.ReachableStopsFinder) - .to(ReachableStopsFinderRoadPlannerCached).whenTargetTagged("phase", ReachableStopsSearchPhase.Final); + .to(ReachableStopsFinderDelaunay).whenTargetTagged("phase", ReachableStopsSearchPhase.Final); -container.bind(TYPES.ConnectionsProvider).to(ConnectionsProviderPrefetch).inSingletonScope(); -container.bind(TYPES.ConnectionsFetcher).to(ConnectionsFetcherLazy); +container.bind(TYPES.ConnectionsProvider).to(ConnectionsProviderDefault).inSingletonScope(); +container.bind(TYPES.ConnectionsFetcher).to(ConnectionsFetcherRaw); container.bind>(TYPES.ConnectionsFetcherFactory) .toFactory( (context: interfaces.Context) => - (accessUrl: string, travelMode: TravelMode) => { - const fetcher = context.container.get(TYPES.ConnectionsFetcher); - - fetcher.setAccessUrl(accessUrl); + (travelMode: TravelMode) => { + const fetcher = context.container.get(TYPES.ConnectionsFetcher); fetcher.setTravelMode(travelMode); - return fetcher; }, ); @@ -80,13 +107,21 @@ container.bind>(TYPES.StopsFetcherFactory) }, ); +container.bind(TYPES.RoutableTileRegistry).to(RoutableTileRegistry).inSingletonScope(); +container.bind(TYPES.RoutableTileFetcher).to(RoutableTileFetcherRaw).inSingletonScope(); +container.bind(TYPES.RoutableTileProvider) + .to(RoutableTileProviderDefault).inSingletonScope().whenTargetTagged("phase", RoutingPhase.Base); +container.bind(TYPES.RoutableTileProvider) + .to(RoutableTileProviderTransit).inSingletonScope().whenTargetTagged("phase", RoutingPhase.Transit); + +container.bind(TYPES.FootpathsProvider).to(FootpathsProviderDefault).inSingletonScope(); + // Bind catalog container.bind(TYPES.Catalog).toConstantValue(catalogNmbs); -// const combinedCatalog = Catalog.combine(catalogNmbs, catalogDeLijn); -// container.bind(TYPES.Catalog).toConstantValue(combinedCatalog); - // Init LDFetch container.bind(TYPES.LDFetch).to(LDFetch).inSingletonScope(); +container.bind(TYPES.LDLoader).to(LDLoader); + export default container; diff --git a/src/isochrone.demo.ts b/src/isochrone.demo.ts new file mode 100644 index 00000000..6e02b53b --- /dev/null +++ b/src/isochrone.demo.ts @@ -0,0 +1,7 @@ +import { IsochroneGenerator } from "."; + +const x = new IsochroneGenerator({ latitude: 51.0262973, longitude: 3.7110885 }); +x.enableDebugLogs(); +x.getIsochrone(2500, true).then((y) => { + console.log(y); +}); diff --git a/src/loader/common.ts b/src/loader/common.ts new file mode 100644 index 00000000..5a4b0380 --- /dev/null +++ b/src/loader/common.ts @@ -0,0 +1,11 @@ +export interface ISemiEntity { + id?: string; +} + +export interface IEntity extends ISemiEntity { + id: string; +} + +export interface IEntityMap { + [id: string]: T; +} diff --git a/src/loader/ldloader.ts b/src/loader/ldloader.ts new file mode 100644 index 00000000..00a2adc0 --- /dev/null +++ b/src/loader/ldloader.ts @@ -0,0 +1,95 @@ +import { injectable } from "inversify"; +import { Triple } from "rdf-js"; +import { XMLS } from "../uri/constants"; +import URI from "../uri/uri"; +import { IEntity, IEntityMap } from "./common"; +import { ThingView } from "./views/single"; + +@injectable() +export class LDLoader { + + private collectionFields: Set = new Set(); + + public defineCollection(field: string) { + this.collectionFields.add(field); + } + + public process(triples: Triple[], views: Array>) { + const entities = this._extractEntities(triples); + + for (const entity of Object.values(entities)) { + for (const view of views) { + const mapped = view.process(entity); + if (mapped) { + view.addEntity(mapped); + } + } + } + + return views.map((view) => view.getContents()); + } + + public disambiguateBlankNodes(triples, scope: string) { + for (const triple of triples) { + if (triple.subject.termType === "BlankNode") { + triple.subject.value = `${scope}#${triple.subject.value}`; + } + if (triple.object.termType === "BlankNode") { + triple.object.value = `${scope}#${triple.object.value}`; + } + } + } + + private _parseValue(entities, triple) { + const tripleObject = triple.object; + const rawValue = tripleObject.value; + if (tripleObject.termType === "BlankNode") { + if (!entities[rawValue]) { + entities[rawValue] = { id: rawValue }; + } + + return entities[rawValue]; + } + if (tripleObject.termType === "Literal") { + const valueType = tripleObject.datatype.value; + if (valueType === URI.inNS(XMLS, "string")) { + return rawValue; + } + if (valueType === URI.inNS(XMLS, "boolean")) { + return rawValue === "true"; + } + if (valueType === URI.inNS(XMLS, "double")) { + return parseFloat(rawValue); + } + if (valueType === URI.inNS(XMLS, "integer")) { + return parseInt(rawValue, 10); + } + } + + return rawValue; + } + + private _extractEntities(triples): IEntityMap { + const entities = {}; + for (const triple of triples) { + const { subject: { value: subject }, predicate: { value: predicate } } = triple; + + if (!(subject in entities)) { + entities[subject] = { id: subject }; + } + + const entity = entities[subject]; + const parsedValue = this._parseValue(entities, triple); + + if (!this.collectionFields.has(predicate)) { + entity[predicate] = parsedValue; + } else { + const fieldData = entity[predicate] || []; + fieldData.push(parsedValue); + entity[predicate] = fieldData; + } + + } + return entities; + } +} diff --git a/src/loader/results/common.ts b/src/loader/results/common.ts new file mode 100644 index 00000000..536ea161 --- /dev/null +++ b/src/loader/results/common.ts @@ -0,0 +1,6 @@ +import { IEntityMap, ISemiEntity } from "../common"; + +export interface IThingViewResult { + addEntity(entity: T): void; + getContents(): T | IEntityMap; +} diff --git a/src/loader/results/index.ts b/src/loader/results/index.ts new file mode 100644 index 00000000..495718d3 --- /dev/null +++ b/src/loader/results/index.ts @@ -0,0 +1,18 @@ +import { IEntity, IEntityMap } from "../common"; +import { IThingViewResult } from "./common"; + +export class IndexThingViewResult implements IThingViewResult { + private contents: IEntityMap; + + constructor() { + this.contents = {}; + } + + public addEntity(entity: T) { + this.contents[entity.id] = entity; + } + + public getContents(): IEntityMap { + return this.contents; + } +} diff --git a/src/loader/results/single.ts b/src/loader/results/single.ts new file mode 100644 index 00000000..32cbe44c --- /dev/null +++ b/src/loader/results/single.ts @@ -0,0 +1,13 @@ +import { ISemiEntity } from "../common"; +import { IThingViewResult } from "./common"; + +export class SingleThingViewResult implements IThingViewResult { + private contents: T; + public addEntity(entity: T): void { + this.contents = entity; + } + + public getContents(): T { + return this.contents; + } +} diff --git a/src/loader/views/index.ts b/src/loader/views/index.ts new file mode 100644 index 00000000..e27605e6 --- /dev/null +++ b/src/loader/views/index.ts @@ -0,0 +1,10 @@ +import { IEntity, ISemiEntity } from "../common"; +import { IndexThingViewResult } from "../results"; +import { IThingViewResult } from "../results/common"; +import { ThingView } from "./single"; + +export class IndexThingView extends ThingView { + public createResultObject(): IThingViewResult { + return new IndexThingViewResult(); + } +} diff --git a/src/loader/views/single.ts b/src/loader/views/single.ts new file mode 100644 index 00000000..c7d0e1f1 --- /dev/null +++ b/src/loader/views/single.ts @@ -0,0 +1,121 @@ +import { RDF } from "../../uri/constants"; +import URI from "../../uri/uri"; +import { IEntity, ISemiEntity } from "../common"; +import { IThingViewResult } from "../results/common"; +import { SingleThingViewResult } from "../results/single"; + +export class ThingView { + private filters: Array<(entity: IEntity) => boolean> = []; + private mappings = {}; + private nestedViews = {}; + private showId = true; + private resultObject: IThingViewResult; + + constructor(private entityType: (id?: string) => T) { + this.resultObject = this.createResultObject(); + } + + public addEntity(entity: T) { + this.resultObject.addEntity(entity); + } + + public getContents() { + return this.resultObject.getContents(); + } + + public hideId() { + this.showId = false; + } + + public addFilter(fn: (Entity) => boolean) { + this.filters.push(fn); + } + + public addMapping(from, to, view?: ThingView) { + this.mappings[from] = to; + this.nestedViews[from] = view; + } + + public process(entity: IEntity): T { + if (this._filter(entity)) { + return this._map(entity); + } + } + + public createResultObject(): IThingViewResult { + return new SingleThingViewResult(); + } + + private _filter(entity: IEntity) { + let ok = true; + for (const fn of this.filters) { + if (!fn(entity)) { + ok = false; + break; + } + } + return ok; + } + + private _makeList(element: IEntity): any[] { + let current = element; + const list = [current[URI.inNS(RDF, "first")]]; + let rest = current[URI.inNS(RDF, "rest")]; + + while (rest && rest !== URI.inNS(RDF, "nil")) { + current = rest; + list.push(current[URI.inNS(RDF, "first")]); + rest = current[URI.inNS(RDF, "rest")]; + } + + return list; + } + + private _flattenLists(entity: IEntity) { + for (const kv of Object.entries(entity)) { + const [field, entityValue] = kv; + if (Array.isArray(entityValue)) { + for (const v of entityValue.entries()) { + const [valueElementIndex, valueElement] = v; + if (valueElement[URI.inNS(RDF, "first")]) { + const list = this._makeList(valueElement); + entityValue[valueElementIndex] = list; + } + } + } + if (entityValue[URI.inNS(RDF, "first")]) { + // this value should become an array + entity[field] = this._makeList(entityValue); + } + } + } + + private _map(entity: IEntity): T { + this._flattenLists(entity); + + let result; + if (this.showId) { + result = this.entityType(entity.id); + } else { + result = this.entityType(); + } + + for (const kv of Object.entries(entity)) { + const field = kv[0]; + let value = kv[1]; + const fieldView = this.nestedViews[field]; + if (fieldView) { + if (Array.isArray(value)) { + value = value.map((v) => fieldView.process(v)); + } else { + value = fieldView.process(value); + } + } + const destinationField = this.mappings[field]; + if (destinationField) { + result[destinationField] = value; + } + } + return result; + } +} diff --git a/src/pathfinding/PathfinderProvider.ts b/src/pathfinding/PathfinderProvider.ts new file mode 100644 index 00000000..4b50a3ca --- /dev/null +++ b/src/pathfinding/PathfinderProvider.ts @@ -0,0 +1,243 @@ +import { inject, injectable } from "inversify"; +import Profile from "../entities/profile/Profile"; +import { IRoutableTileNodeIndex, RoutableTileNode } from "../entities/tiles/node"; +import RoutableTileRegistry from "../entities/tiles/registry"; +import { RoutableTile } from "../entities/tiles/tile"; +import { IRoutableTileWayIndex, RoutableTileWay } from "../entities/tiles/way"; +import ProfileProvider from "../fetcher/profiles/ProfileProviderDefault"; +import ILocation from "../interfaces/ILocation"; +import TYPES from "../types"; +import Geo from "../util/Geo"; +import PathfindingGraph from "./graph"; +import { + IShortestPathAlgorithm, + IShortestPathInstance, + IShortestPathTreeAlgorithm, + IShortestPathTreeInstance, +} from "./pathfinder"; + +interface IPointEmbedding { + way: RoutableTileWay; // the road where the point gets embedded in + point: ILocation; // point that's embedded into the road network + intersection: ILocation; // closest point on the road segment closest to the point + segA: RoutableTileNode; // one side of the road segment closest to the point + segB: RoutableTileNode; // other side of the road segment closest to the point +} + +interface IGraphMap { + [label: string]: PathfindingGraph; +} + +@injectable() +export default class PathfinderProvider { + private graphs: IGraphMap; + + private shortestPath: IShortestPathAlgorithm; + private shortestPathTree: IShortestPathTreeAlgorithm; + private routableTileRegistry: RoutableTileRegistry; + private profileProvider: ProfileProvider; + + constructor( + @inject(TYPES.ShortestPathTreeAlgorithm) shortestPathTree: IShortestPathTreeAlgorithm, + @inject(TYPES.ShortestPathAlgorithm) pointToPoint: IShortestPathAlgorithm, + @inject(TYPES.RoutableTileRegistry) routableTileRegistry: RoutableTileRegistry, + @inject(TYPES.ProfileProvider) profileProvider: ProfileProvider, + ) { + this.shortestPath = pointToPoint; + this.shortestPathTree = shortestPathTree; + this.routableTileRegistry = routableTileRegistry; + this.profileProvider = profileProvider; + this.graphs = {}; + } + + public getShortestPathAlgorithm(profile: Profile): IShortestPathInstance { + const graph = this.getGraphForProfile(profile); + return this.shortestPath.createInstance(graph); + } + + public getShortestPathTreeAlgorithm(profile: Profile): IShortestPathTreeInstance { + const graph = this.getGraphForProfile(profile); + return this.shortestPathTree.createInstance(graph); + } + + public async registerEdges(ways: IRoutableTileWayIndex, nodes: IRoutableTileNodeIndex): Promise { + // add new edges to existing graphs + for (const profileId of Object.keys(this.graphs)) { + const profile = await this.profileProvider.getProfile(profileId); + + for (const way of Object.values(ways)) { + if (!profile.hasAccess(way)) { + continue; + } + + for (const edge of way.getParts()) { + const from = nodes[edge.from]; + const to = nodes[edge.to]; + if (from && to) { + if (profile.isObstacle(from) || profile.isObstacle(to)) { + continue; + } + this.addEdge(profile, from, to, way, edge.distance); + if (!profile.isOneWay(way)) { + this.addEdge(profile, to, from, way, edge.distance); + } + } + } + } + } + } + + public async embedLocation(p: ILocation, tileset: RoutableTile, invert = false) { + for (const profile of await this.profileProvider.getProfiles()) { + let bestDistance = Infinity; + let bestEmbedding: IPointEmbedding; + + for (const wayId of tileset.getWays()) { + const way = this.routableTileRegistry.getWay(wayId); + + if (!profile.hasAccess(way) || way.reachable === false) { + continue; + } + + for (const segment of way.segments) { + for (let i = 0; i < segment.length - 1; i++) { + const nodeA = segment[i]; + const from = this.routableTileRegistry.getNode(nodeA); + const nodeB = segment[i + 1]; + const to = this.routableTileRegistry.getNode(nodeB); + + if (!from || !to) { + // FIXME, caused by bug in data + continue; + } + + const [distance, intersection] = this.segmentDistToPoint(from, to, p); + if (distance < bestDistance) { + bestDistance = distance; + bestEmbedding = { + way, + point: p, + segA: from, + segB: to, + intersection, + }; + } + } + } + } + + if (bestEmbedding) { + const intersection = bestEmbedding.intersection; + const segA = bestEmbedding.segA; + const segB = bestEmbedding.segB; + const way = bestEmbedding.way; + const isOneWay = profile.isOneWay(way); + + if (!invert) { + // A -------------------> B + // A <-- intersection --> B + // | + // p + this.addEdge(profile, p, intersection, way); + this.addEdge(profile, intersection, segB, way); + if (!isOneWay) { + this.addEdge(profile, intersection, segA, way); + } + } else { + // A -------------------> B + // A --> intersection <-- B + // | + // p + this.addEdge(profile, intersection, p, way); + this.addEdge(profile, segA, intersection, way); + if (!isOneWay) { + this.addEdge(profile, segB, intersection, way); + } + } + } + } + } + + public getGraphForProfile(profile: Profile): PathfindingGraph { + if (!this.graphs[profile.getID()]) { + // we don't have a graph for this profile yet + // create one + const graph = new PathfindingGraph(profile.getID()); + this.graphs[profile.getID()] = graph; + + // and populate it with all the data we have + for (const way of this.routableTileRegistry.getWays()) { + if (!profile.hasAccess(way)) { + continue; + } + + for (const edge of way.getParts()) { + const from = this.routableTileRegistry.getNode(edge.from); + const to = this.routableTileRegistry.getNode(edge.to); + if (from && to) { + if (profile.isObstacle(from) || profile.isObstacle(to)) { + continue; + } + this.addEdge(profile, from, to, way, edge.distance, graph); + if (!profile.isOneWay(way)) { + this.addEdge(profile, to, from, way, edge.distance, graph); + } + } + } + } + } + return this.graphs[profile.getID()]; + } + + private addEdge( + profile: Profile, + from: ILocation, to: + ILocation, + way: RoutableTileWay, + distance?: number, + graph?: PathfindingGraph, + ) { + // this specifically adds an edge that corresponds to an actual street + // if you need to add any other edge, you'll need to create a different method + graph = graph || this.getGraphForProfile(profile); + distance = distance || profile.getDistance(from, to, way); + const duration = profile.getDuration(from, to, way); + const cost = profile.getCost(from, to, way); + graph.addEdge(Geo.getId(from), Geo.getId(to), distance, duration, cost); + } + + private segmentDistToPoint(segA: ILocation, segB: ILocation, p: ILocation): [number, ILocation] { + // seems numerically unstable, see 'catastrophic cancellation' + const sx1 = segA.longitude; + const sx2 = segB.longitude; + const px = p.longitude; + + const sy1 = segA.latitude; + const sy2 = segB.latitude; + const py = p.latitude; + + const px2 = sx2 - sx1; // <- + const py2 = sy2 - sy2; // <- + + const norm = px2 * px2 + py2 * py2; + let u = ((px - sx1) * px2 + (py - sy1) * py2) / norm; + + if (u > 1) { + u = 1; + } else if (u < 0) { + u = 0; + } + + const x = sx1 + u * px2; + const y = sy1 + u * py2; + + const intersection = { + longitude: x, + latitude: y, + }; + + const dist = Geo.getDistanceBetweenLocations(p, intersection); + + return [dist, intersection]; + } +} diff --git a/src/pathfinding/bidirdijkstra/BidirDijkstra.ts b/src/pathfinding/bidirdijkstra/BidirDijkstra.ts new file mode 100644 index 00000000..cbbb08c0 --- /dev/null +++ b/src/pathfinding/bidirdijkstra/BidirDijkstra.ts @@ -0,0 +1,11 @@ +import { injectable } from "inversify"; +import PathfindingGraph from "../graph"; +import { IShortestPathAlgorithm, IShortestPathInstance } from "../pathfinder"; +import { BidirDijkstraInstance } from "./BidirDijkstraInstance"; + +@injectable() +export class BidirDijkstra implements IShortestPathAlgorithm { + public createInstance(graph: PathfindingGraph): IShortestPathInstance { + return new BidirDijkstraInstance(graph); + } +} diff --git a/src/pathfinding/bidirdijkstra/BidirDijkstraInstance.ts b/src/pathfinding/bidirdijkstra/BidirDijkstraInstance.ts new file mode 100644 index 00000000..b740cc96 --- /dev/null +++ b/src/pathfinding/bidirdijkstra/BidirDijkstraInstance.ts @@ -0,0 +1,304 @@ +import { injectable } from "inversify"; +import TinyQueue from "tinyqueue"; +import { DistanceM, DurationMs } from "../../interfaces/units"; +import PathfindingGraph from "../graph"; +import { IShortestPathInstance } from "../pathfinder"; + +interface IState { + position: number; + distance: DistanceM; + duration: DurationMs; + cost: number; +} + +enum StepResultKind { + Continue, + Break, + NodeHandled, +} + +type IStepResult = IContinueStep | IBreakStep | INodeHandledStep; + +interface IContinueStep { + kind: StepResultKind.Continue; +} + +interface IBreakStep { + kind: StepResultKind.Break; +} + +interface INodeHandledStep { + kind: StepResultKind.NodeHandled; + nodeId: number; +} + +@injectable() +export class BidirDijkstraInstance implements IShortestPathInstance { + private graph: PathfindingGraph; + private useWeightedCost: boolean; + + private forwardCosts: number[]; + private backwardCosts: number[]; + private forwardParents: number[]; + private backwardParents: number[]; + + constructor(graph: PathfindingGraph) { + this.useWeightedCost = true; + this.graph = graph; + } + + public setUseWeightedCost(useWeightedCost: boolean) { + this.useWeightedCost = useWeightedCost; + } + + public setBreakPoint(on: string, callback: (on: string) => Promise): void { + this.graph.setBreakPoint(on, callback); + } + + public removeBreakPoint(on: string): void { + this.graph.removeBreakPoint(on); + } + + public async queryPath(from: string, to: string, maxDistance = Infinity) { + let forwardQueue: TinyQueue; + let backwardQueue: TinyQueue; + if (this.useWeightedCost) { + forwardQueue = new TinyQueue([], (a, b) => a.cost - b.cost); + backwardQueue = new TinyQueue([], (a, b) => a.cost - b.cost); + } else { + forwardQueue = new TinyQueue([], (a, b) => a.duration - b.duration); + backwardQueue = new TinyQueue([], (a, b) => a.duration - b.duration); + } + + this.forwardCosts = [...Array(this.graph.getAdjacencyList().length)].fill(Infinity); + this.forwardParents = [...Array(this.graph.getAdjacencyList().length)].fill(undefined); + this.backwardCosts = [...Array(this.graph.getAdjacencyList().length)].fill(Infinity); + this.backwardParents = [...Array(this.graph.getAdjacencyList().length)].fill(undefined); + + const fromIndex = this.graph.getNodeIndex(from); + const toIndex = this.graph.getNodeIndex(to); + this.setForwardCost(fromIndex, 0); + this.setBackwardCost(toIndex, 0); + forwardQueue.push({ distance: 0, duration: 0, cost: 0, position: fromIndex }); + backwardQueue.push({ distance: 0, duration: 0, cost: 0, position: toIndex }); + + while (forwardQueue.length && backwardQueue.length) { + const [forwardResult, backwardResult] = await Promise.all([ + this.forwardStep(forwardQueue, toIndex, maxDistance), + this.backwardStep(backwardQueue, fromIndex, maxDistance), + ]); + + if (forwardResult.kind === StepResultKind.Break || backwardResult.kind === StepResultKind.Break) { + // failed to find a path + return []; + } + + if (forwardResult.kind === StepResultKind.NodeHandled) { + if (this.backwardCosts[forwardResult.nodeId] < Infinity) { + // shortest path has been found + // note that it doesn't necessarily contain the handled node + return this.constructPath(forwardResult.nodeId); + } + } + + if (backwardResult.kind === StepResultKind.NodeHandled) { + if (this.forwardCosts[backwardResult.nodeId] < Infinity) { + return this.constructPath(backwardResult.nodeId); + } + } + } + + // no path found + return []; + } + + private constructPath(toIndex: number) { + let currentPosition = toIndex; + const forwardSteps = []; + const backwardSteps = []; + + // reconstruct forward part of the path + while (this.backwardParents[currentPosition]) { + let nextEdge; + let nextPositionCost = Infinity; + + for (const edge of this.graph.getAdjacencyList()[currentPosition]) { + if (this.getBackwardCost(edge.node) < nextPositionCost) { + nextPositionCost = this.getBackwardCost(edge.node); + nextEdge = edge; + } + } + + if (!nextEdge) { + break; + } + + backwardSteps.push({ + from: this.graph.getLabel(nextEdge.node), + to: this.graph.getLabel(currentPosition), + distance: nextEdge.distance, + duration: nextEdge.duration, + }); + + currentPosition = nextEdge.node; + } + + currentPosition = toIndex; + while (this.forwardParents[currentPosition]) { + let nextEdge; + let nextPositionCost = Infinity; + + for (const edge of this.graph.getReverseAdjacencyList()[currentPosition]) { + if (this.getForwardCost(edge.node) < nextPositionCost) { + nextPositionCost = this.getForwardCost(edge.node); + nextEdge = edge; + } + } + + if (!nextEdge) { + break; + } + + forwardSteps.push({ + from: this.graph.getLabel(nextEdge.node), + to: this.graph.getLabel(currentPosition), + distance: nextEdge.distance, + duration: nextEdge.duration, + }); + + currentPosition = nextEdge.node; + } + + return forwardSteps.reverse().concat(backwardSteps); + } + + private async forwardStep(queue: TinyQueue, toIndex: number, maxDistance): Promise { + if (!queue.length) { + return { kind: StepResultKind.Break }; + } + + const { duration, distance, cost, position } = queue.pop(); + + if (distance > maxDistance) { + // avoid hopeless searches + return { kind: StepResultKind.Break }; + } + + if (position === toIndex) { + // it is done, break the loop and start reconstructing the path + return { kind: StepResultKind.Break }; + } + + if (cost > this.getForwardCost(position)) { + // we have already found a better way + return { kind: StepResultKind.Continue }; + } + + if (this.graph.getBreakPoint(position)) { + await this.graph.getBreakPoint(position)(this.graph.getLabel(position)); + } + + for (const edge of this.graph.getAdjacencyList()[position]) { + const next = { + distance: distance + edge.distance, + duration: duration + edge.duration, + cost: cost + edge.cost, + position: edge.node, + }; + + if (next.cost < this.getForwardCost(next.position)) { + this.setForwardCost(next.position, next.cost); + this.forwardParents[next.position] = position; + queue.push(next); + } + } + + return { + kind: StepResultKind.NodeHandled, + nodeId: position, + }; + } + + private async backwardStep(queue: TinyQueue, toIndex: number, maxDistance): Promise { + if (!queue.length) { + return { kind: StepResultKind.Break }; + } + + const { duration, distance, cost, position } = queue.pop(); + + if (distance > maxDistance) { + // avoid hopeless searches + return { kind: StepResultKind.Break }; + } + + if (position === toIndex) { + // it is done, break the loop and start reconstructing the path + return { kind: StepResultKind.Break }; + } + + if (cost > this.getBackwardCost(position)) { + // we have already found a better way + return { kind: StepResultKind.Continue }; + } + + if (this.graph.getBreakPoint(position)) { + await this.graph.getBreakPoint(position)(this.graph.getLabel(position)); + } + + for (const edge of this.graph.getReverseAdjacencyList()[position]) { + const next = { + distance: distance + edge.distance, + duration: duration + edge.duration, + cost: cost + edge.cost, + position: edge.node, + }; + + if (next.cost < this.getBackwardCost(next.position)) { + this.setBackwardCost(next.position, next.cost); + this.backwardParents[next.position] = position; + queue.push(next); + } + } + + return { + kind: StepResultKind.NodeHandled, + nodeId: position, + }; + } + + private setForwardCost(position: number, cost: number) { + if (position >= this.forwardCosts.length) { + const missingCosts = this.graph.getAdjacencyList().length - this.forwardCosts.length; + this.forwardCosts = this.forwardCosts.concat([...Array(missingCosts)].fill(Infinity)); + this.forwardParents = this.forwardParents.concat([...Array(missingCosts)].fill(undefined)); + } + this.forwardCosts[position] = cost; + } + + private getForwardCost(position: number): number { + if (position >= this.forwardCosts.length) { + const missingCosts = this.graph.getAdjacencyList().length - this.forwardCosts.length; + this.forwardCosts = this.forwardCosts.concat([...Array(missingCosts)].fill(Infinity)); + this.forwardParents = this.forwardParents.concat([...Array(missingCosts)].fill(undefined)); + } + return this.forwardCosts[position]; + } + + private setBackwardCost(position: number, cost: number) { + if (position >= this.backwardCosts.length) { + const missingCosts = this.graph.getAdjacencyList().length - this.backwardCosts.length; + this.backwardCosts = this.backwardCosts.concat([...Array(missingCosts)].fill(Infinity)); + this.backwardParents = this.backwardParents.concat([...Array(missingCosts)].fill(undefined)); + } + this.backwardCosts[position] = cost; + } + + private getBackwardCost(position: number): number { + if (position >= this.backwardCosts.length) { + const missingCosts = this.graph.getAdjacencyList().length - this.backwardCosts.length; + this.backwardCosts = this.backwardCosts.concat([...Array(missingCosts)].fill(Infinity)); + this.backwardParents = this.backwardParents.concat([...Array(missingCosts)].fill(undefined)); + } + return this.backwardCosts[position]; + } +} diff --git a/src/pathfinding/dijkstra-tree/DijkstraTree.ts b/src/pathfinding/dijkstra-tree/DijkstraTree.ts new file mode 100644 index 00000000..d39292d9 --- /dev/null +++ b/src/pathfinding/dijkstra-tree/DijkstraTree.ts @@ -0,0 +1,20 @@ +import { injectable } from "inversify"; +import TinyQueue from "tinyqueue"; +import { DistanceM, DurationMs } from "../../interfaces/units"; +import PathfindingGraph from "../graph"; +import { IPathTree, IShortestPathTreeAlgorithm, IShortestPathTreeInstance } from "../pathfinder"; +import DijkstraTreeInstance from "./DijkstraTreeInstance"; + +interface IState { + position: number; + distance: DistanceM; + duration: DurationMs; + cost: number; +} + +@injectable() +export default class DijkstraTree implements IShortestPathTreeAlgorithm { + public createInstance(graph: PathfindingGraph): IShortestPathTreeInstance { + return new DijkstraTreeInstance(graph); + } +} diff --git a/src/pathfinding/dijkstra-tree/DijkstraTreeInstance.ts b/src/pathfinding/dijkstra-tree/DijkstraTreeInstance.ts new file mode 100644 index 00000000..c99a13c7 --- /dev/null +++ b/src/pathfinding/dijkstra-tree/DijkstraTreeInstance.ts @@ -0,0 +1,111 @@ +import { injectable } from "inversify"; +import TinyQueue from "tinyqueue"; +import { DistanceM, DurationMs } from "../../interfaces/units"; +import PathfindingGraph from "../graph"; +import { IPathTree, IShortestPathTreeInstance } from "../pathfinder"; + +interface IState { + position: number; + distance: DistanceM; + duration: DurationMs; + cost: number; +} + +@injectable() +export default class DijkstraTreeInstance implements IShortestPathTreeInstance { + private nextQueue: IState[]; + private costs: number[]; + private previousNodes: number[]; + private graph: PathfindingGraph; + private useWeightedCost: boolean; + + constructor(graph: PathfindingGraph) { + this.graph = graph; + this.useWeightedCost = true; + } + + public setUseWeightedCost(useWeightedCost: boolean) { + this.useWeightedCost = useWeightedCost; + } + + public setBreakPoint(on: string, callback: (on: string) => Promise): void { + this.graph.setBreakPoint(on, callback); + } + + public removeBreakPoint(on: string): void { + this.graph.removeBreakPoint(on); + } + + public async start(from: string, maxCost: number): Promise { + this.costs = [...Array(this.graph.getAdjacencyList().length)].fill(Infinity); + this.previousNodes = [...Array(this.graph.getAdjacencyList().length)].fill(undefined); + + const fromIndex = this.graph.getNodeIndex(from); + this.costs[fromIndex] = 0; + this.nextQueue = [{ distance: 0, duration: 0, cost: 0, position: fromIndex }]; + + return this.continue(maxCost); + } + + public async continue(maxCost: number): Promise { + const queue = new TinyQueue(this.nextQueue, (a, b) => a.duration - b.duration); + this.nextQueue = []; + + while (queue.length) { + const { position, distance, duration, cost } = queue.pop(); + + if (duration > this.getCost(position)) { + // we have already found a better way + continue; + } + + if (this.graph.getBreakPoint(position)) { + await this.graph.getBreakPoint(position)(this.graph.getLabel(position)); + } + + if (cost > maxCost) { + // remember this state for subsequent calls + this.nextQueue.push({ duration, distance, cost, position }); + } else { + for (const edge of this.graph.getAdjacencyList()[position]) { + const next = { + distance: distance + edge.distance, + duration: duration + edge.duration, + cost: cost + edge.cost, + position: edge.node, + previousPosition: position, + }; + + if (next.duration < this.getCost(next.position)) { + queue.push(next); + this.costs[next.position] = next.duration; + this.previousNodes[next.position] = position; + + if (this.graph.getBreakPoint(next.position)) { + this.graph.getBreakPoint(next.position)(this.graph.getLabel(next.position)); + } + } + } + } + } + + const result: IPathTree = {}; + + for (const [position, cost] of this.costs.entries()) { + const label = this.graph.getLabel(position); + const previousLabel = this.graph.getLabel(this.previousNodes[position]); + result[label] = { duration: cost, previousNode: previousLabel }; + } + + return result; + } + + private getCost(position: number): number { + if (position >= this.costs.length) { + const missingCosts = this.graph.getAdjacencyList().length - this.costs.length; + this.costs = this.costs.concat([...Array(missingCosts)].fill(Infinity)); + this.previousNodes = this.previousNodes.concat([...Array(missingCosts)].fill(undefined)); + } + return this.costs[position]; + } +} diff --git a/src/pathfinding/dijkstra/Dijkstra.ts b/src/pathfinding/dijkstra/Dijkstra.ts new file mode 100644 index 00000000..9199e023 --- /dev/null +++ b/src/pathfinding/dijkstra/Dijkstra.ts @@ -0,0 +1,11 @@ +import { injectable } from "inversify"; +import PathfindingGraph from "../graph"; +import { IShortestPathAlgorithm, IShortestPathInstance } from "../pathfinder"; +import { DijkstraInstance } from "./DijkstraInstance"; + +@injectable() +export class Dijkstra implements IShortestPathAlgorithm { + public createInstance(graph: PathfindingGraph): IShortestPathInstance { + return new DijkstraInstance(graph); + } +} diff --git a/src/pathfinding/dijkstra/DijkstraInstance.ts b/src/pathfinding/dijkstra/DijkstraInstance.ts new file mode 100644 index 00000000..7a8dcc1c --- /dev/null +++ b/src/pathfinding/dijkstra/DijkstraInstance.ts @@ -0,0 +1,142 @@ +import { injectable } from "inversify"; +import TinyQueue from "tinyqueue"; +import { DistanceM, DurationMs } from "../../interfaces/units"; +import PathfindingGraph from "../graph"; +import { IShortestPathInstance } from "../pathfinder"; + +interface IState { + position: number; + distance: DistanceM; + duration: DurationMs; + cost: number; +} + +@injectable() +export class DijkstraInstance implements IShortestPathInstance { + private graph: PathfindingGraph; + private useWeightedCost: boolean; + private costs: number[]; + private previousNodes: number[]; + + constructor(graph: PathfindingGraph) { + this.useWeightedCost = true; + this.graph = graph; + } + + public setUseWeightedCost(useWeightedCost: boolean) { + this.useWeightedCost = useWeightedCost; + } + + public setBreakPoint(on: string, callback: (on: string) => Promise): void { + this.graph.setBreakPoint(on, callback); + } + + public removeBreakPoint(on: string): void { + this.graph.removeBreakPoint(on); + } + + public async queryPath(from: string, to: string, maxDistance = Infinity) { + let queue: TinyQueue; + if (this.useWeightedCost) { + queue = new TinyQueue([], (a, b) => a.cost - b.cost); + } else { + queue = new TinyQueue([], (a, b) => a.duration - b.duration); + } + + this.costs = [...Array(this.graph.getAdjacencyList().length)].fill(Infinity); + this.previousNodes = [...Array(this.graph.getAdjacencyList().length)].fill(undefined); + + const fromIndex = this.graph.getNodeIndex(from); + this.setCost(fromIndex, 0); + queue.push({ distance: 0, duration: 0, cost: 0, position: fromIndex }); + + const toIndex = this.graph.getNodeIndex(to); + + while (queue.length) { + const { duration, distance, cost, position } = queue.pop(); + + if (distance > maxDistance) { + // avoid hopeless searches + break; + } + + if (position === toIndex) { + // it is done, break the loop and start reconstructing the path + break; + } + + if (cost > this.getCost(position)) { + // we have already found a better way + continue; + } + + if (this.graph.getBreakPoint(position)) { + await this.graph.getBreakPoint(position)(this.graph.getLabel(position)); + } + + for (const edge of this.graph.getAdjacencyList()[position]) { + const next = { + distance: distance + edge.distance, + duration: duration + edge.duration, + cost: cost + edge.cost, + position: edge.node, + }; + + if (next.cost < this.getCost(next.position)) { + this.setCost(next.position, next.cost); + this.previousNodes[next.position] = position; + queue.push(next); + } + } + } + + let currentPosition = toIndex; + const steps = []; + + // reconstruct the path + while (this.previousNodes[currentPosition]) { + let nextEdge; + let nextPositionCost = Infinity; + + for (const edge of this.graph.getReverseAdjacencyList()[currentPosition]) { + if (this.getCost(edge.node) < nextPositionCost) { + nextPositionCost = this.getCost(edge.node); + nextEdge = edge; + } + } + + if (!nextEdge) { + break; + } + + steps.push({ + from: this.graph.getLabel(nextEdge.node), + to: this.graph.getLabel(currentPosition), + distance: nextEdge.distance, + duration: nextEdge.duration, + }); + + currentPosition = nextEdge.node; + } + + return steps.reverse(); + } + + private setCost(position: number, cost: number) { + if (position >= this.costs.length) { + const missingCosts = this.graph.getAdjacencyList().length - this.costs.length; + this.costs = this.costs.concat([...Array(missingCosts)].fill(Infinity)); + this.previousNodes = this.previousNodes.concat([...Array(missingCosts)].fill(undefined)); + } + this.costs[position] = cost; + } + + private getCost(position: number): number { + if (position >= this.costs.length) { + const missingCosts = this.graph.getAdjacencyList().length - this.costs.length; + this.costs = this.costs.concat([...Array(missingCosts)].fill(Infinity)); + this.previousNodes = this.previousNodes.concat([...Array(missingCosts)].fill(undefined)); + } + return this.costs[position]; + } +} diff --git a/src/pathfinding/graph.ts b/src/pathfinding/graph.ts new file mode 100644 index 00000000..0b19dcc1 --- /dev/null +++ b/src/pathfinding/graph.ts @@ -0,0 +1,81 @@ +interface IEdge { + node: number; + distance: number; + duration: number; + cost: number; +} + +interface INodeMap { + [label: string]: number; +} + +interface IBreakPointIndex { + [position: number]: (on: string) => Promise; +} + +export default class PathfindingGraph { + private id: string; + private nodes: Map; + private labels: string[]; + private adjacencyList: IEdge[][]; + private reverseAdjacencyList: IEdge[][]; + private breakPoints: IBreakPointIndex; + + constructor(id: string) { + this.nodes = new Map(); + this.labels = []; + this.adjacencyList = []; + this.reverseAdjacencyList = []; + this.id = id; + this.breakPoints = {}; + } + + public addEdge(from: string, to: string, distance: number, duration: number, cost: number) { + const fromIndex = this.getNodeIndex(from); + const toIndex = this.getNodeIndex(to); + this.adjacencyList[fromIndex].push({ node: toIndex, distance, cost, duration }); + this.reverseAdjacencyList[toIndex].push({ node: fromIndex, distance, cost, duration }); + } + + public getNodeMap() { + return this.nodes; + } + + public getLabel(position: number) { + return this.labels[position]; + } + + public getAdjacencyList() { + return this.adjacencyList; + } + + public getReverseAdjacencyList() { + return this.reverseAdjacencyList; + } + + public getNodeIndex(label: string) { + if (!this.nodes.has(label)) { + const index = this.adjacencyList.length; + this.nodes.set(label, index); + this.labels.push(label); + this.adjacencyList.push([]); + this.reverseAdjacencyList.push([]); + } + + return this.nodes.get(label); + } + + public setBreakPoint(on: string, callback: (on: string) => Promise): void { + const position = this.getNodeIndex(on); + this.breakPoints[position] = callback; + } + + public getBreakPoint(position: number): (on: string) => Promise { + return this.breakPoints[position]; + } + + public removeBreakPoint(on: string): void { + const position = this.getNodeIndex(on); + delete this.breakPoints[position]; + } +} diff --git a/src/pathfinding/pathfinder.ts b/src/pathfinding/pathfinder.ts new file mode 100644 index 00000000..47acd85f --- /dev/null +++ b/src/pathfinding/pathfinder.ts @@ -0,0 +1,44 @@ +import { DistanceM, DurationMs } from "../interfaces/units"; +import PathfindingGraph from "./graph"; + +export interface IPathTree { + [node: string]: IPathTreeBranch; +} + +export interface IPathTreeBranch { + duration: DurationMs; + previousNode: string; +} + +export interface IPathSummary { + distance: DistanceM; + duration: DurationMs; + cost: number; +} + +interface IPathfinder { + createInstance(graph: PathfindingGraph): IPathfinderInstance; +} + +interface IPathfinderInstance { + setUseWeightedCost(useWeightedCost: boolean): void; + setBreakPoint(on: string, callback: (on: string) => Promise): void; + removeBreakPoint(on: string): void; +} + +export interface IShortestPathInstance extends IPathfinderInstance { + queryPath(from: string, to: string, maxDistance: number); +} + +export interface IShortestPathTreeInstance extends IPathfinderInstance { + start(from: string, maxCost: number): Promise; + continue(maxCost: number): Promise; +} + +export interface IShortestPathAlgorithm extends IPathfinder { + createInstance(graph: PathfindingGraph): IShortestPathInstance; +} + +export interface IShortestPathTreeAlgorithm extends IPathfinder { + createInstance(graph: PathfindingGraph): IShortestPathTreeInstance; +} diff --git a/src/planner/Leg.ts b/src/planner/Leg.ts new file mode 100644 index 00000000..942d6a3a --- /dev/null +++ b/src/planner/Leg.ts @@ -0,0 +1,94 @@ +import TravelMode from "../enums/TravelMode"; +import ILeg from "../interfaces/ILeg"; +import ILocation from "../interfaces/ILocation"; +import IStep from "../interfaces/IStep"; +import { DistanceM, DurationMs } from "../interfaces/units"; +import Step from "./Step"; + +export default class Leg implements ILeg { + public static compareEquals(leg: ILeg, otherLeg: ILeg): boolean { + if (leg.getSteps().length !== otherLeg.getSteps().length) { + return false; + } + + if (otherLeg.getTravelMode() !== leg.getTravelMode()) { + return false; + } + + return leg.getSteps().every((step, stepIndex) => { + const otherStep = otherLeg.getSteps()[stepIndex]; + + return Step.compareEquals(step, otherStep); + }); + } + + private travelMode: TravelMode; + private steps: IStep[]; + + public constructor(travelMode: TravelMode, steps: IStep[]) { + this.travelMode = travelMode; + this.steps = steps; + } + + public getExpectedDuration(): DurationMs { + return this.getAverageDuration() || this.getMinimumDuration() || this.getMaximumDuration(); + } + + public getMinimumDuration(): DurationMs { + return this.steps.reduce((previous, current) => { + return previous + current.duration.minimum; + }, 0); + } + + public getAverageDuration(): DurationMs { + // the average of averages isn't really the average of the whole series + // but this will have to do + return this.steps.reduce((previous, current) => { + return previous + current.duration.average; + }, 0); + } + + public getMaximumDuration(): DurationMs { + return this.steps.reduce((previous, current) => { + return previous + current.duration.maximum; + }, 0); + } + + public getDistance(): DistanceM { + return this.steps.reduce((previous, current) => { + return previous + current.distance; + }, 0); + } + + public getTravelMode(): TravelMode { + return this.travelMode; + } + + public getSteps(): IStep[] { + return this.steps; + } + + public getStartTime(): Date { + if (this.steps.length > 0) { + return this.steps[0].startTime; + } + } + + public getStopTime(): Date { + if (this.steps.length > 0) { + return this.steps[this.steps.length - 1].stopTime; + } + } + + public getStartLocation(): ILocation { + if (this.steps.length > 0) { + return this.steps[0].startLocation; + } + } + + public getStopLocation(): ILocation { + if (this.steps.length > 0) { + return this.steps[this.steps.length - 1].stopLocation; + } + } +} diff --git a/src/planner/Path.ts b/src/planner/Path.ts index 3174b223..947c0e9b 100644 --- a/src/planner/Path.ts +++ b/src/planner/Path.ts @@ -1,7 +1,9 @@ +import TravelMode from "../enums/TravelMode"; +import ILeg from "../interfaces/ILeg"; import IPath from "../interfaces/IPath"; -import IStep from "../interfaces/IStep"; +import IQuery from "../interfaces/IQuery"; import { DurationMs } from "../interfaces/units"; -import Step from "./Step"; +import Leg from "./Leg"; /** * This Path class serves as an implementation of the [[IPath]] interface and as a home for some helper functions @@ -20,44 +22,78 @@ export default class Path implements IPath { * @returns true if the two paths are the same */ public static compareEquals(path: IPath, otherPath: IPath): boolean { - if (path.steps.length !== otherPath.steps.length) { + if (path.legs.length !== otherPath.legs.length) { return false; } - return path.steps.every((step, stepIndex) => { - const otherStep = otherPath.steps[stepIndex]; + return path.legs.every((leg, legIndex) => { + const otherLeg = otherPath.legs[legIndex]; - return Step.compareEquals(step, otherStep); + return Leg.compareEquals(leg, otherLeg); }); } - public steps: IStep[]; + public legs: ILeg[]; - constructor(steps: IStep[]) { - this.steps = steps; + constructor(legs: ILeg[]) { + this.legs = legs; } - public addStep(step: IStep): void { - this.steps.push(step); + public prependLeg(leg: ILeg) { + this.legs.unshift(leg); } - public addPath(path: IPath): void { - this.steps.push(...path.steps); + public appendLeg(leg: ILeg): void { + this.legs.push(leg); } - public reverse(): void { - this.steps.reverse(); + public addPath(path: IPath): void { + this.legs.push(...path.legs); } public getStartLocationId(): string { - return (" " + this.steps[0].startLocation.id).slice(1); + return (" " + this.legs[0].getStartLocation().id).slice(1); + } + + public getDepartureTime(query: IQuery): Date { + let acc = 0; + for (const leg of this.legs) { + if (leg.getStartTime()) { + return new Date(leg.getStartTime().getTime() - acc); + } else { + acc += leg.getExpectedDuration(); + } + } + + return query.minimumDepartureTime; + } + + public getArrivalTime(query: IQuery): Date { + let acc = 0; + for (let i = this.legs.length - 1; i >= 0; i--) { + const leg = this.legs[i]; + if (leg.getStopTime()) { + return new Date(leg.getStopTime().getTime() + acc); + } else { + acc += leg.getExpectedDuration(); + } + } + return new Date(query.minimumDepartureTime.getTime() + (this.getTravelTime())); + } + + public getTravelTime(): DurationMs { + return this.legs.reduce((time, leg) => time + leg.getExpectedDuration(), 0); } - public addTime(duration: DurationMs): void { - this.steps = this.steps.map((step: IStep) => ({ - ...step, - startTime: new Date(step.startTime.getTime() + duration), - stopTime: new Date(step.stopTime.getTime() + duration), - })); + public getTransferTime(): DurationMs { + let time = this.getTravelTime(); + + for (const leg of this.legs) { + if (leg.getTravelMode() === TravelMode.Train || leg.getTravelMode() === TravelMode.Bus) { + time -= leg.getExpectedDuration(); + } + } + + return time; } } diff --git a/src/planner/Step.ts b/src/planner/Step.ts index bfd7af1b..550fa261 100644 --- a/src/planner/Step.ts +++ b/src/planner/Step.ts @@ -1,9 +1,9 @@ -import TravelMode from "../enums/TravelMode"; -import IConnection from "../fetcher/connections/IConnection"; +import IConnection from "../entities/connections/connections"; import ILocation from "../interfaces/ILocation"; import IProbabilisticValue from "../interfaces/IProbabilisticValue"; import IStep from "../interfaces/IStep"; import { DistanceM, DurationMs } from "../interfaces/units"; +import Geo from "../util/Geo"; /** * This Step class serves as an implementation of the [[IStep]] interface and as a home for some helper functions @@ -14,7 +14,6 @@ export default class Step implements IStep { public static create( startLocation: ILocation, stopLocation: ILocation, - travelMode: TravelMode, duration: IProbabilisticValue, startTime?: Date, stopTime?: Date, @@ -23,7 +22,6 @@ export default class Step implements IStep { return new Step( startLocation, stopLocation, - travelMode, duration, startTime, stopTime, @@ -33,9 +31,8 @@ export default class Step implements IStep { public static createFromConnections(enterConnection: IConnection, exitConnection: IConnection): IStep { return new Step( - {id: enterConnection.departureStop}, - {id: exitConnection.arrivalStop}, - enterConnection.travelMode, + { id: enterConnection.departureStop }, + { id: exitConnection.arrivalStop }, { minimum: ( exitConnection.arrivalTime.getTime() - @@ -55,23 +52,12 @@ export default class Step implements IStep { * @returns true if the two steps are the same */ public static compareEquals(step: IStep, otherStep: IStep): boolean { - if (otherStep.travelMode !== step.travelMode) { - return false; - } - - if (otherStep.travelMode === TravelMode.Train || otherStep.travelMode === TravelMode.Bus) { - return otherStep.enterConnectionId === step.enterConnectionId && - otherStep.exitConnectionId === step.exitConnectionId; - } - - if (otherStep.travelMode === TravelMode.Walking) { - return Step.compareLocations(otherStep.startLocation, step.startLocation) && - Step.compareLocations(otherStep.stopLocation, step.stopLocation); - } + return Step.compareLocations(otherStep.startLocation, step.startLocation) && + Step.compareLocations(otherStep.stopLocation, step.stopLocation); } private static compareLocations(a: ILocation, b: ILocation): boolean { - return a.id === b.id && a.longitude === b.longitude && a.latitude === b.latitude; + return Geo.getId(a) === Geo.getId(b) && a.longitude === b.longitude && a.latitude === b.latitude; } public distance: DistanceM; @@ -80,14 +66,12 @@ export default class Step implements IStep { public startTime: Date; public stopLocation: ILocation; public stopTime: Date; - public travelMode: TravelMode; public enterConnectionId: string; public exitConnectionId: string; constructor( startLocation: ILocation, stopLocation: ILocation, - travelMode: TravelMode, duration: IProbabilisticValue, startTime?: Date, stopTime?: Date, @@ -97,7 +81,6 @@ export default class Step implements IStep { ) { this.distance = distance; this.duration = duration; - this.travelMode = travelMode; this.startLocation = startLocation; this.startTime = startTime; this.stopLocation = stopLocation; diff --git a/src/planner/configurations/BasicTrainPlanner.ts b/src/planner/configurations/BasicTrainPlanner.ts new file mode 100644 index 00000000..74f2c115 --- /dev/null +++ b/src/planner/configurations/BasicTrainPlanner.ts @@ -0,0 +1,8 @@ +import basicTrainProfile from "../../configs/basic_train"; +import Planner from "./Planner"; + +export default class BasicTrainPlanner extends Planner { + constructor() { + super(basicTrainProfile); + } +} diff --git a/src/planner/configurations/DissectPlanner.ts b/src/planner/configurations/DissectPlanner.ts new file mode 100644 index 00000000..654e7b01 --- /dev/null +++ b/src/planner/configurations/DissectPlanner.ts @@ -0,0 +1,8 @@ +import dissectProfile from "../../configs/dissect"; +import Planner from "./Planner"; + +export default class DissectPlanner extends Planner { + constructor() { + super(dissectProfile); + } +} diff --git a/src/planner/configurations/Planner.ts b/src/planner/configurations/Planner.ts new file mode 100644 index 00000000..17fc1af4 --- /dev/null +++ b/src/planner/configurations/Planner.ts @@ -0,0 +1,165 @@ +import { AsyncIterator } from "asynciterator"; +import { PromiseProxyIterator } from "asynciterator-promiseproxy"; +import { EventEmitter } from "events"; +import Context from "../../Context"; +import TravelMode from "../../enums/TravelMode"; +import EventBus from "../../events/EventBus"; +import EventType from "../../events/EventType"; +import IConnectionsProvider from "../../fetcher/connections/IConnectionsProvider"; +import ProfileProvider from "../../fetcher/profiles/ProfileProviderDefault"; +import IStop from "../../fetcher/stops/IStop"; +import IStopsProvider from "../../fetcher/stops/IStopsProvider"; +import IPath from "../../interfaces/IPath"; +import IQuery from "../../interfaces/IQuery"; +import defaultContainer from "../../inversify.config"; +import IQueryRunner from "../../query-runner/IQueryRunner"; +import TYPES from "../../types"; +import Iterators from "../../util/Iterators"; +import Units from "../../util/Units"; +import Path from "../Path"; +import IRoadPlanner from "../road/IRoadPlanner"; + +/** + * Allows to ask route planning queries. Emits events defined in [[EventType]] + */ +export default abstract class Planner { + public static Units = Units; + + private activeProfileID: string; + private context: Context; + private eventBus: EventEmitter; + private queryRunner: IQueryRunner; + private profileProvider: ProfileProvider; + private roadPlanner: IRoadPlanner; + + /** + * Initializes a new Planner + * @param container The container of dependencies we are working with + */ + constructor(container = defaultContainer) { + // Store container on context before doing anything else + this.context = container.get(TYPES.Context); + this.context.setContainer(container); + + this.queryRunner = container.get(TYPES.QueryRunner); + this.profileProvider = container.get(TYPES.ProfileProvider); + this.eventBus = EventBus.getInstance(); + this.roadPlanner = container.get(TYPES.RoadPlanner); + + this.activeProfileID = "https://hdelva.be/profile/pedestrian"; + } + + public async completePath(path: IPath): Promise { + const completePath = Path.create(); + + let walkingDeparture; + let walkingDestination; + + for (const leg of path.legs) { + if (leg.getTravelMode() === TravelMode.Walking) { + if (!walkingDeparture) { + walkingDeparture = leg.getStartLocation(); + } + walkingDestination = leg.getStopLocation(); + } else { + if (walkingDestination) { + const walkingPathIterator = await this.roadPlanner.plan({ + from: [walkingDeparture], + to: [walkingDestination], + profileID: this.activeProfileID, + }); + const walkingPaths = await Iterators.toArray(walkingPathIterator); + for (const walkingLeg of walkingPaths[0].legs) { + completePath.appendLeg(walkingLeg); + } + + walkingDeparture = null; + walkingDestination = null; + } + + completePath.appendLeg(leg); + } + } + + if (walkingDestination) { + const walkingPathIterator = await this.roadPlanner.plan({ + from: [walkingDeparture], + to: [walkingDestination], + profileID: this.activeProfileID, + }); + const walkingPaths = await Iterators.toArray(walkingPathIterator); + for (const walkingLeg of walkingPaths[0].legs) { + completePath.appendLeg(walkingLeg); + } + + walkingDeparture = null; + walkingDestination = null; + } + + return completePath; + } + + /** + * Given an [[IQuery]], it will evaluate the query and return a promise for an AsyncIterator of [[IPath]] instances + * @param query An [[IQuery]] specifying a route planning query + * @returns An [[AsyncIterator]] of [[IPath]] instances + */ + public query(query: IQuery): AsyncIterator { + this.eventBus.emit(EventType.Query, query); + + query.profileID = this.activeProfileID; + const iterator = new PromiseProxyIterator(() => this.queryRunner.run(query)); + + this.eventBus.once(EventType.AbortQuery, () => { + iterator.close(); + }); + + iterator.on("error", (e) => { + if (e && e.eventType) { + this.eventBus.emit(e.eventType, e.message); + } + }); + + return iterator; + } + + public prefetchStops(): void { + const container = this.context.getContainer(); + const stopsProvider = container.get(TYPES.StopsProvider); + + if (stopsProvider) { + stopsProvider.prefetchStops(); + } + } + + public prefetchConnections(from: Date, to: Date): void { + // TODO, get rid of service locator anti-pattern + const container = this.context.getContainer(); + const connectionsProvider = container.get(TYPES.ConnectionsProvider); + connectionsProvider.prefetchConnections(from, to); + } + + public async setDevelopmentProfile(blob: object) { + const profileID = await this.profileProvider.parseDevelopmentProfile(blob); + return this.setProfileID(profileID); + } + + public setProfileID(profileID: string) { + this.activeProfileID = profileID; + return this; + } + + public getAllStops(): Promise { + // fixme, why is this here? + // is this just for visualizations? + const container = this.context.getContainer(); + const stopsProvider = container.get(TYPES.StopsProvider); + + if (stopsProvider) { + return stopsProvider.getAllStops(); + } + + return Promise.reject(); + } + +} diff --git a/src/planner/configurations/TransitCarPlanner.ts b/src/planner/configurations/TransitCarPlanner.ts new file mode 100644 index 00000000..94f87376 --- /dev/null +++ b/src/planner/configurations/TransitCarPlanner.ts @@ -0,0 +1,17 @@ +import { AsyncIterator } from "asynciterator"; +import transitCarProfile from "../../configs/transit_car"; +import IPath from "../../interfaces/IPath"; +import IQuery from "../../interfaces/IQuery"; +import Planner from "./Planner"; + +export default class TransitCarPlanner extends Planner { + constructor() { + super(transitCarProfile); + this.setProfileID("http://hdelva.be/profile/car"); + } + + public query(query: IQuery): AsyncIterator { + query.roadNetworkOnly = true; + return super.query(query); + } +} diff --git a/src/planner/configurations/TriangleDemoPlanner.ts b/src/planner/configurations/TriangleDemoPlanner.ts new file mode 100644 index 00000000..e0fb9dda --- /dev/null +++ b/src/planner/configurations/TriangleDemoPlanner.ts @@ -0,0 +1,8 @@ +import triangleDemoProfile from "../../configs/triangle_demo"; +import Planner from "./Planner"; + +export default class TriangleDemoPlanner extends Planner { + constructor() { + super(triangleDemoProfile); + } +} diff --git a/src/planner/public-transport/CSA/FootpathQueue.ts b/src/planner/public-transport/CSA/FootpathQueue.ts new file mode 100644 index 00000000..27b88229 --- /dev/null +++ b/src/planner/public-transport/CSA/FootpathQueue.ts @@ -0,0 +1,53 @@ +import { AsyncIterator } from "asynciterator"; +import TinyQueue from "tinyqueue"; +import IConnection from "../../../entities/connections/connections"; + +export default class FootpathQueue extends AsyncIterator { + + private buffer: TinyQueue; + private shouldClose: boolean; + + constructor(backwards = false) { + super(); + + if (backwards) { + this.buffer = new TinyQueue([], (a, b) => { + return b.departureTime - a.departureTime; + }); + } else { + this.buffer = new TinyQueue([], (a, b) => { + return a.departureTime - b.departureTime; + }); + } + + this.readable = true; + this.shouldClose = false; + } + + public read(): IConnection { + let item; + + if (this.buffer.length) { + item = this.buffer.pop(); + } else { + item = null; + } + + if (this.shouldClose) { + this.close(); + } + + return item; + } + + public write(item: IConnection): void { + if (!this.shouldClose) { + this.buffer.push(item); + this.readable = true; + } + } + + public closeAfterFlush(): void { + this.shouldClose = true; + } +} diff --git a/src/planner/public-transport/CSA/data-structure/IArrivalTimeByTransfers.ts b/src/planner/public-transport/CSA/data-structure/IArrivalTimeByTransfers.ts index ffcb1877..e527ddcd 100644 --- a/src/planner/public-transport/CSA/data-structure/IArrivalTimeByTransfers.ts +++ b/src/planner/public-transport/CSA/data-structure/IArrivalTimeByTransfers.ts @@ -1,10 +1,10 @@ /** - * Stores an arrival time in milliseconds and the corresponding gtfs:trip + * Stores an arrival time in milliseconds and the corresponding trip ID * for a maximum amount of transfers that can be made. */ -export default interface IArrivalTimeByTransfers extends Array<{arrivalTime: number, "gtfs:trip"?: string}> { +export default interface IArrivalTimeByTransfers extends Array<{arrivalTime: number, tripId?: string}> { [amountOfTransfers: number]: { arrivalTime: number, - "gtfs:trip"?: string, + tripId?: string, }; } diff --git a/src/planner/public-transport/CSA/data-structure/stops/ITransferProfile.ts b/src/planner/public-transport/CSA/data-structure/stops/ITransferProfile.ts index 06b021cf..536169b6 100644 --- a/src/planner/public-transport/CSA/data-structure/stops/ITransferProfile.ts +++ b/src/planner/public-transport/CSA/data-structure/stops/ITransferProfile.ts @@ -1,4 +1,4 @@ -import IConnection from "../../../../../fetcher/connections/IConnection"; +import IConnection from "../../../../../entities/connections/connections"; import Path from "../../../../Path"; /** diff --git a/src/planner/public-transport/CSA/data-structure/stops/Profile.ts b/src/planner/public-transport/CSA/data-structure/stops/Profile.ts index b9b09ed5..2ad29a9e 100644 --- a/src/planner/public-transport/CSA/data-structure/stops/Profile.ts +++ b/src/planner/public-transport/CSA/data-structure/stops/Profile.ts @@ -60,8 +60,8 @@ export default class Profile implements IProfile { public getArrivalTimeByTransfers(tripId?: string): IArrivalTimeByTransfers { return this.transferProfiles.map((transfer: ITransferProfile) => ({ - "arrivalTime": transfer.arrivalTime, - "gtfs:trip": tripId, + arrivalTime: transfer.arrivalTime, + tripId, })); } } diff --git a/src/planner/public-transport/CSA/data-structure/trips/EarliestArrivalByTransfers.ts b/src/planner/public-transport/CSA/data-structure/trips/EarliestArrivalByTransfers.ts index 3a101353..963f8e6c 100644 --- a/src/planner/public-transport/CSA/data-structure/trips/EarliestArrivalByTransfers.ts +++ b/src/planner/public-transport/CSA/data-structure/trips/EarliestArrivalByTransfers.ts @@ -1,4 +1,4 @@ -import IConnection from "../../../../../fetcher/connections/IConnection"; +import IConnection from "../../../../../entities/connections/connections"; import IArrivalTimeByTransfers from "../IArrivalTimeByTransfers"; import IEarliestArrival from "./IEarliestArrival"; import IEarliestArrivalByTransfers from "./IEarliestArrivalByTransfers"; diff --git a/src/planner/public-transport/CSA/data-structure/trips/IEarliestArrival.ts b/src/planner/public-transport/CSA/data-structure/trips/IEarliestArrival.ts index c97870b7..be6004aa 100644 --- a/src/planner/public-transport/CSA/data-structure/trips/IEarliestArrival.ts +++ b/src/planner/public-transport/CSA/data-structure/trips/IEarliestArrival.ts @@ -1,4 +1,4 @@ -import IConnection from "../../../../../fetcher/connections/IConnection"; +import IConnection from "../../../../../entities/connections/connections"; /** * @property arrivalTime Describes the earliest arrival time in milliseconds to the target [[IStop]]. diff --git a/src/planner/public-transport/CSA/data-structure/trips/IEarliestArrivalByTrip.ts b/src/planner/public-transport/CSA/data-structure/trips/IEarliestArrivalByTrip.ts index 31cd4627..bbb4f7b8 100644 --- a/src/planner/public-transport/CSA/data-structure/trips/IEarliestArrivalByTrip.ts +++ b/src/planner/public-transport/CSA/data-structure/trips/IEarliestArrivalByTrip.ts @@ -1,5 +1,5 @@ /** - * Stores for each gtfs:trip the earliest arrival [[IEarliestArrivalByTransfers]] to the target [[IStop]]. + * Stores for each tripId the earliest arrival [[IEarliestArrivalByTransfers]] to the target [[IStop]]. */ import IEarliestArrivalByTransfers from "./IEarliestArrivalByTransfers"; diff --git a/src/planner/public-transport/CSA/data-structure/trips/IEnterConnectionByTrip.ts b/src/planner/public-transport/CSA/data-structure/trips/IEnterConnectionByTrip.ts index 78a3c402..12b0916d 100644 --- a/src/planner/public-transport/CSA/data-structure/trips/IEnterConnectionByTrip.ts +++ b/src/planner/public-transport/CSA/data-structure/trips/IEnterConnectionByTrip.ts @@ -1,4 +1,4 @@ -import IConnection from "../../../../../fetcher/connections/IConnection"; +import IConnection from "../../../../../entities/connections/connections"; /** * @property arrivalTime Describes the earliest arrival time in milliseconds to the target [[IStop]]. diff --git a/src/planner/public-transport/CSA/util/ProfileUtil.ts b/src/planner/public-transport/CSA/util/ProfileUtil.ts index 95a9f7e9..423c9525 100644 --- a/src/planner/public-transport/CSA/util/ProfileUtil.ts +++ b/src/planner/public-transport/CSA/util/ProfileUtil.ts @@ -1,5 +1,5 @@ +import IConnection from "../../../../entities/connections/connections"; import DropOffType from "../../../../enums/DropOffType"; -import IConnection from "../../../../fetcher/connections/IConnection"; import { DurationMs } from "../../../../interfaces/units"; import IArrivalTimeByTransfers from "../data-structure/IArrivalTimeByTransfers"; import IProfilesByStop from "../data-structure/stops/IProfilesByStop"; @@ -34,7 +34,7 @@ export default class ProfileUtil { maximumTransferDuration: DurationMs, ): IArrivalTimeByTransfers { const { arrivalStop, arrivalTime } = connection; - const trip: string = connection["gtfs:trip"]; + const trip: string = connection.tripId; if (connection["gtfs:dropOffType"] !== DropOffType.NotAvailable) { @@ -56,8 +56,8 @@ export default class ProfileUtil { } return Array(maxLegs + 1).fill({ - "arrivalTime": Infinity, - "gtfs:trip": trip, + arrivalTime: Infinity, + tripId: trip, }); } } diff --git a/src/planner/public-transport/CSAEarliestArrival.test.ts b/src/planner/public-transport/CSAEarliestArrival.test.ts index ac04174a..c2a18250 100644 --- a/src/planner/public-transport/CSAEarliestArrival.test.ts +++ b/src/planner/public-transport/CSAEarliestArrival.test.ts @@ -1,23 +1,23 @@ import "jest"; import LDFetch from "ldfetch"; +import Catalog from "../../Catalog"; import Defaults from "../../Defaults"; +import RoutableTileRegistry from "../../entities/tiles/registry"; import TravelMode from "../../enums/TravelMode"; -import ConnectionsFetcherLazy from "../../fetcher/connections/lazy/ConnectionsFetcherLazy"; -import ConnectionsFetcherNMBSTest from "../../fetcher/connections/tests/ConnectionsFetcherNMBSTest"; +import ConnectionsFetcherRaw from "../../fetcher/connections/ConnectionsFetcherRaw"; +import ConnectionsProviderDefault from "../../fetcher/connections/ConnectionsProviderDefault"; +import ConnectionsProviderNMBSTest from "../../fetcher/connections/tests/ConnectionsProviderNMBSTest"; import connectionsIngelmunsterGhent from "../../fetcher/connections/tests/data/ingelmunster-ghent"; -import connectionsJoining from "../../fetcher/connections/tests/data/joining"; -import connectionsSplitting from "../../fetcher/connections/tests/data/splitting"; import StopsFetcherLDFetch from "../../fetcher/stops/ld-fetch/StopsFetcherLDFetch"; +import ILeg from "../../interfaces/ILeg"; import IPath from "../../interfaces/IPath"; import IQuery from "../../interfaces/IQuery"; -import IStep from "../../interfaces/IStep"; import IResolvedQuery from "../../query-runner/IResolvedQuery"; import LocationResolverDefault from "../../query-runner/LocationResolverDefault"; import QueryRunnerDefault from "../../query-runner/QueryRunnerDefault"; import Iterators from "../../util/Iterators"; import ReachableStopsFinderBirdsEyeCached from "../stops/ReachableStopsFinderBirdsEyeCached"; import CSAEarliestArrival from "./CSAEarliestArrival"; -import JourneyExtractorEarliestArrival from "./JourneyExtractorEarliestArrival"; describe("[PublicTransportPlannerCSAEarliestArrival]", () => { describe("mock data", () => { @@ -26,25 +26,19 @@ describe("[PublicTransportPlannerCSAEarliestArrival]", () => { const createCSA = (connections) => { const ldFetch = new LDFetch({ headers: { Accept: "application/ld+json" } }); - const connectionFetcher = new ConnectionsFetcherNMBSTest(connections); - connectionFetcher.setIteratorOptions({ backward: false }); - + const connectionProvider = new ConnectionsProviderNMBSTest(connections); const stopsFetcher = new StopsFetcherLDFetch(ldFetch); stopsFetcher.setAccessUrl("https://irail.be/stations/NMBS"); - const locationResolver = new LocationResolverDefault(stopsFetcher); + const locationResolver = new LocationResolverDefault(stopsFetcher, new RoutableTileRegistry()); const reachableStopsFinder = new ReachableStopsFinderBirdsEyeCached(stopsFetcher); - const journeyExtractor = new JourneyExtractorEarliestArrival( - locationResolver, - ); return new CSAEarliestArrival( - connectionFetcher, + connectionProvider, locationResolver, reachableStopsFinder, reachableStopsFinder, reachableStopsFinder, - journeyExtractor, ); }; @@ -52,9 +46,9 @@ describe("[PublicTransportPlannerCSAEarliestArrival]", () => { let result: IPath[]; const query: IResolvedQuery = { - publicTransportOnly: true, - from: [{latitude: 50.914326, longitude: 3.255415, id: "http://irail.be/stations/NMBS/008896925" }], + from: [{ latitude: 50.914326, longitude: 3.255415, id: "http://irail.be/stations/NMBS/008896925" }], to: [{ latitude: 51.035896, longitude: 3.710875, id: "http://irail.be/stations/NMBS/008892007" }], + profileID: "https://hdelva.be/profile/pedestrian", minimumDepartureTime: new Date("2018-11-06T09:00:00.000Z"), maximumArrivalTime: new Date("2018-11-06T19:00:00.000Z"), maximumTransfers: 8, @@ -71,22 +65,22 @@ describe("[PublicTransportPlannerCSAEarliestArrival]", () => { }); it("Correct departure and arrival stop", () => { - expect(result).toBeDefined(); + expect(result).toBeDefined(); - for (const path of result) { - expect(path.steps).toBeDefined(); - expect(path.steps[0]).toBeDefined(); - expect(query.from.map((from) => from.id)).toContain(path.steps[0].startLocation.id); - expect(query.to.map((to) => to.id)).toContain(path.steps[path.steps.length - 1].stopLocation.id); + for (const path of result) { + expect(path.legs).toBeDefined(); + expect(path.legs[0]).toBeDefined(); + expect(query.from.map((from) => from.id)).toContain(path.legs[0].getStartLocation().id); + expect(query.to.map((to) => to.id)).toContain(path.legs[path.legs.length - 1].getStopLocation().id); } }); }); + /* describe("splitting", () => { let result: IPath[]; const query: IResolvedQuery = { - publicTransportOnly: true, from: [{ id: "http://irail.be/stations/NMBS/008821006", latitude: 51.2172, @@ -132,7 +126,6 @@ describe("[PublicTransportPlannerCSAEarliestArrival]", () => { let result: IPath[]; const query: IResolvedQuery = { - publicTransportOnly: true, from: [{ id: "http://irail.be/stations/NMBS/008812005", latitude: 50.859663, @@ -172,81 +165,83 @@ describe("[PublicTransportPlannerCSAEarliestArrival]", () => { expect(query.to.map((to) => to.id)).toContain(path.steps[0].stopLocation.id); } }); - }); + });*/ }); describe("real-time data", () => { const createQueryRunner = () => { const ldFetch = new LDFetch({ headers: { Accept: "application/ld+json" } }); - const connectionFetcher = new ConnectionsFetcherLazy(ldFetch); - connectionFetcher.setTravelMode(TravelMode.Train); - connectionFetcher.setAccessUrl("https://graph.irail.be/sncb/connections"); + const catalog = new Catalog(); + catalog.addConnectionsSource("https://graph.irail.be/sncb/connections", TravelMode.Train); + const connectionProvider = new ConnectionsProviderDefault( + (travelMode: TravelMode) => { + const fetcher = new ConnectionsFetcherRaw(); + fetcher.setTravelMode(travelMode); + return fetcher; + }, catalog, + ); const stopsFetcher = new StopsFetcherLDFetch(ldFetch); stopsFetcher.setAccessUrl("https://irail.be/stations/NMBS"); - const locationResolver = new LocationResolverDefault(stopsFetcher); + const locationResolver = new LocationResolverDefault(stopsFetcher, new RoutableTileRegistry()); const reachableStopsFinder = new ReachableStopsFinderBirdsEyeCached(stopsFetcher); - const journeyExtractor = new JourneyExtractorEarliestArrival( - locationResolver, - ); const CSA = new CSAEarliestArrival( - connectionFetcher, + connectionProvider, locationResolver, reachableStopsFinder, reachableStopsFinder, reachableStopsFinder, - journeyExtractor, ); - return new QueryRunnerDefault(locationResolver, CSA); + return new QueryRunnerDefault(locationResolver, CSA, undefined); }; - const checkStops = (result, query) => { + const checkStops = (result: IPath[], query) => { expect(result).toBeDefined(); expect(result.length).toBeGreaterThanOrEqual(1); for (const path of result) { - expect(path.steps).toBeDefined(); + expect(path.legs).toBeDefined(); - expect(path.steps.length).toBeGreaterThanOrEqual(1); + expect(path.legs.length).toBeGreaterThanOrEqual(1); let currentLocation = query.from; - path.steps.forEach((step: IStep) => { - expect(step).toBeDefined(); - expect(currentLocation).toEqual(step.startLocation.id); - currentLocation = step.stopLocation.id; + path.legs.forEach((leg: ILeg) => { + expect(leg).toBeDefined(); + expect(currentLocation).toEqual(leg.getStartLocation().id); + currentLocation = leg.getStopLocation().id; }); expect(query.to).toEqual(currentLocation); } }; - const checkTimes = (result, minimumDepartureTime) => { + const checkTimes = (result: IPath[], minimumDepartureTime) => { expect(result).toBeDefined(); expect(result.length).toBeGreaterThanOrEqual(1); for (const path of result) { - expect(path.steps).toBeDefined(); + expect(path.legs).toBeDefined(); - expect(path.steps.length).toBeGreaterThanOrEqual(1); - expect(path.steps[0]).toBeDefined(); - expect(path.steps[path.steps.length - 1]).toBeDefined(); + expect(path.legs.length).toBeGreaterThanOrEqual(1); + expect(path.legs[0]).toBeDefined(); + expect(path.legs[path.legs.length - 1]).toBeDefined(); let currentTime = minimumDepartureTime.getTime(); - path.steps.forEach((step: IStep) => { - expect(step).toBeDefined(); - if (step.travelMode === TravelMode.Walking) { - currentTime += step.duration.minimum; + path.legs.forEach((leg: ILeg) => { + expect(leg).toBeDefined(); + if (leg.getTravelMode() === TravelMode.Walking) { + currentTime += leg.getMinimumDuration(); } else { - expect(currentTime).toBeLessThanOrEqual(step.startTime.getTime()); - currentTime = step.stopTime.getTime(); + expect(currentTime).toBeLessThanOrEqual(leg.getStartTime().getTime()); + currentTime = leg.getStopTime().getTime(); } }); - expect(path.steps[0].startTime.getTime()).toBeGreaterThanOrEqual(minimumDepartureTime.getTime()); + expect(path.legs[0].getStartTime().getTime()).toBeGreaterThanOrEqual(minimumDepartureTime.getTime()); } }; @@ -256,7 +251,6 @@ describe("[PublicTransportPlannerCSAEarliestArrival]", () => { const minimumDepartureTime = new Date(); const query: IQuery = { - publicTransportOnly: true, from: "http://irail.be/stations/NMBS/008896925", // Ingelmunster to: "http://irail.be/stations/NMBS/008892007", // Ghent-Sint-Pieters minimumDepartureTime, @@ -264,7 +258,7 @@ describe("[PublicTransportPlannerCSAEarliestArrival]", () => { let result: IPath[]; beforeAll(async () => { - const queryRunner = createQueryRunner(); + const queryRunner = createQueryRunner(); const iterator = await queryRunner.run(query); result = await Iterators.toArray(iterator); diff --git a/src/planner/public-transport/CSAEarliestArrival.ts b/src/planner/public-transport/CSAEarliestArrival.ts index c065fc5a..8f6aaad1 100644 --- a/src/planner/public-transport/CSAEarliestArrival.ts +++ b/src/planner/public-transport/CSAEarliestArrival.ts @@ -1,132 +1,140 @@ import { ArrayIterator, AsyncIterator } from "asynciterator"; +import { EventEmitter } from "events"; import { inject, injectable, tagged } from "inversify"; -import Context from "../../Context"; +import IConnection from "../../entities/connections/connections"; import DropOffType from "../../enums/DropOffType"; -import EventType from "../../enums/EventType"; import PickupType from "../../enums/PickupType"; import ReachableStopsFinderMode from "../../enums/ReachableStopsFinderMode"; import ReachableStopsSearchPhase from "../../enums/ReachableStopsSearchPhase"; import TravelMode from "../../enums/TravelMode"; -import IConnection from "../../fetcher/connections/IConnection"; +import EventBus from "../../events/EventBus"; +import EventType from "../../events/EventType"; import IConnectionsProvider from "../../fetcher/connections/IConnectionsProvider"; import IStop from "../../fetcher/stops/IStop"; import ILocation from "../../interfaces/ILocation"; import IPath from "../../interfaces/IPath"; -import IStep from "../../interfaces/IStep"; import ILocationResolver from "../../query-runner/ILocationResolver"; import IResolvedQuery from "../../query-runner/IResolvedQuery"; import TYPES from "../../types"; import Geo from "../../util/Geo"; -import Path from "../Path"; -import Step from "../Step"; +import MergeIterator from "../../util/iterators/MergeIterator"; import IReachableStopsFinder, { IReachableStop } from "../stops/IReachableStopsFinder"; import IProfileByStop from "./CSA/data-structure/stops/IProfileByStop"; import ITransferProfile from "./CSA/data-structure/stops/ITransferProfile"; import IEnterConnectionByTrip from "./CSA/data-structure/trips/IEnterConnectionByTrip"; +import FootpathQueue from "./CSA/FootpathQueue"; import IJourneyExtractor from "./IJourneyExtractor"; import IPublicTransportPlanner from "./IPublicTransportPlanner"; +import JourneyExtractorEarliestArrival from "./JourneyExtractorEarliestArrival"; + +interface IFinalReachableStops { + [stop: string]: IReachableStop; +} + +// Implementation is as close as possible to the original paper: https://arxiv.org/pdf/1703.05997.pdf -/** - * An implementation of the Earliest Arrival Connection Scan Algorithm. - * The earliest arrival connection scan algorithm takes the initial, transfer and final footpaths into account. - * - * Doesn't support the maximumTravelDuration and maximumTransfers query parameters. - * - * @implements [[IPublicTransportPlanner]] - * @property profilesByStop Describes the CSA profiles for each scanned stop. - * @property enterConnectionByTrip Describes the connection you should enter at a departure location for each trip. - * @property gtfsTripByConnection Stores the gtfs:trip's a connection is part of. Used for splitting and joining. - * - * @returns one [[IPath]] that consist of several [[IStep]]s. - */ @injectable() export default class CSAEarliestArrival implements IPublicTransportPlanner { - private readonly connectionsProvider: IConnectionsProvider; - private readonly locationResolver: ILocationResolver; - private readonly initialReachableStopsFinder: IReachableStopsFinder; - private readonly finalReachableStopsFinder: IReachableStopsFinder; - private readonly transferReachableStopsFinder: IReachableStopsFinder; - private readonly journeyExtractor: IJourneyExtractor; - private readonly context: Context; + private static forwardsConnectionSelector(connections: IConnection[]): number { + if (connections.length === 1) { + return 0; + } + + let earliestIndex = 0; + const earliest = connections[earliestIndex]; + + for (let i = 1; i < connections.length; i++) { + const connection = connections[i]; + + if (connection && connection.departureTime < earliest.departureTime) { + earliestIndex = i; + } + } + + return earliestIndex; + } - private profilesByStop: IProfileByStop = {}; // S - private enterConnectionByTrip: IEnterConnectionByTrip = {}; // T - private gtfsTripsByConnection = {}; + protected readonly connectionsProvider: IConnectionsProvider; + protected readonly locationResolver: ILocationResolver; + protected readonly transferReachableStopsFinder: IReachableStopsFinder; + protected readonly initialReachableStopsFinder: IReachableStopsFinder; + protected readonly finalReachableStopsFinder: IReachableStopsFinder; + protected readonly eventBus: EventEmitter; - private initialReachableStops: IReachableStop[] = []; - private finalReachableStops: IReachableStop[] = []; + protected finalReachableStops: IFinalReachableStops; + protected profilesByStop: IProfileByStop; // S + protected enterConnectionByTrip: IEnterConnectionByTrip; // T - private query: IResolvedQuery; - private connectionsIterator: AsyncIterator; + protected footpathsQueue: FootpathQueue; + protected connectionsQueue: AsyncIterator; + + protected journeyExtractor: IJourneyExtractor; constructor( @inject(TYPES.ConnectionsProvider) - connectionsProvider: IConnectionsProvider, + connectionsProvider: IConnectionsProvider, @inject(TYPES.LocationResolver) - locationResolver: ILocationResolver, - @inject(TYPES.ReachableStopsFinder) - @tagged("phase", ReachableStopsSearchPhase.Initial) - initialReachableStopsFinder: IReachableStopsFinder, + locationResolver: ILocationResolver, @inject(TYPES.ReachableStopsFinder) @tagged("phase", ReachableStopsSearchPhase.Transfer) - transferReachableStopsFinder: IReachableStopsFinder, + transferReachableStopsFinder: IReachableStopsFinder, + @inject(TYPES.ReachableStopsFinder) + @tagged("phase", ReachableStopsSearchPhase.Initial) + initialReachableStopsFinder: IReachableStopsFinder, @inject(TYPES.ReachableStopsFinder) @tagged("phase", ReachableStopsSearchPhase.Final) - finalReachableStopsFinder: IReachableStopsFinder, - @inject(TYPES.JourneyExtractor) - journeyExtractor: IJourneyExtractor, - @inject(TYPES.Context) - context?: Context, + finalReachableStopsFinder: IReachableStopsFinder, ) { this.connectionsProvider = connectionsProvider; this.locationResolver = locationResolver; - this.initialReachableStopsFinder = initialReachableStopsFinder; this.transferReachableStopsFinder = transferReachableStopsFinder; + this.initialReachableStopsFinder = initialReachableStopsFinder; this.finalReachableStopsFinder = finalReachableStopsFinder; - this.journeyExtractor = journeyExtractor; - this.context = context; + this.eventBus = EventBus.getInstance(); + this.journeyExtractor = new JourneyExtractorEarliestArrival(locationResolver); } public async plan(query: IResolvedQuery): Promise> { - this.query = query; - - this.setBounds(); - - return this.calculateJourneys(); - } + // reset state + this.finalReachableStops = {}; + this.profilesByStop = {}; + this.enterConnectionByTrip = {}; - private setBounds() { const { minimumDepartureTime: lowerBoundDate, maximumArrivalTime: upperBoundDate, - } = this.query; + } = query; - this.connectionsProvider.setIteratorOptions({ + this.footpathsQueue = new FootpathQueue(); + const connectionsIterator = this.connectionsProvider.createIterator({ upperBoundDate, lowerBoundDate, }); - } - private async calculateJourneys(): Promise> { - const hasInitialReachableStops: boolean = await this.initInitialReachableStops(); - const hasFinalReachableStops: boolean = await this.initFinalReachableStops(); + this.connectionsQueue = new MergeIterator( + [connectionsIterator, this.footpathsQueue], + CSAEarliestArrival.forwardsConnectionSelector, + true, + ); + + const [hasInitialReachableStops, hasFinalReachableStops] = await Promise.all([ + this.initInitialReachableStops(query), + this.initFinalReachableStops(query), + ]); if (!hasInitialReachableStops || !hasFinalReachableStops) { return Promise.resolve(new ArrayIterator([])); } - this.connectionsIterator = this.connectionsProvider.createIterator(); - const self = this; - return new Promise((resolve, reject) => { - let isDone = false; + let isDone: boolean = false; const done = () => { if (!isDone) { - self.connectionsIterator.close(); + self.connectionsQueue.close(); - self.journeyExtractor.extractJourneys(self.profilesByStop, self.query) + self.extractJourneys(query) .then((resultIterator) => { resolve(resultIterator); }); @@ -135,74 +143,93 @@ export default class CSAEarliestArrival implements IPublicTransportPlanner { } }; - this.connectionsIterator.on("readable", () => - self.processNextConnection(done), + connectionsIterator.on("readable", () => + self.processConnections(query, done), ); - this.connectionsIterator.on("end", () => done()); + connectionsIterator.on("end", () => done()); + + // iterator may have become readable before the listener was attached + self.processConnections(query, done); }) as Promise>; } - private async processNextConnection(done: () => void) { - let connection = this.connectionsIterator.read(); - - while (connection) { - this.discoverConnection(connection); - - const { - to, - minimumDepartureTime, - maximumWalkingDuration, - minimumTransferDuration, - maximumTransferDuration, - } = this.query; - - const arrivalStopId: string = to[0].id; - if (this.profilesByStop[arrivalStopId].arrivalTime <= connection.departureTime.getTime()) { - this.connectionsIterator.close(); - done(); - break; - } + protected updateProfile(query: IResolvedQuery, connection: IConnection) { + /* + Call this ONLY if the given connection is known to improve the arrival stop's profile + */ + + const tripId = connection.tripId; + const departureTime = connection.departureTime.getTime(); + const arrivalTime = connection.arrivalTime.getTime(); + + // update profile of arrival stop + const arrivalProfile: ITransferProfile = { + departureTime, + arrivalTime, + exitConnection: connection, + enterConnection: this.enterConnectionByTrip[tripId], + }; + this.profilesByStop[connection.arrivalStop] = arrivalProfile; + } - if (connection.departureTime < minimumDepartureTime && !this.connectionsIterator.closed) { - connection = this.connectionsIterator.read(); - continue; - } + private async extractJourneys(query: IResolvedQuery): Promise> { + return this.journeyExtractor.extractJourneys(this.profilesByStop, query); + } - const tripIds = this.getTripIdsFromConnection(connection); - for (const tripId of tripIds) { + private async processConnections(query: IResolvedQuery, resolve: () => void) { + const { from, to, minimumDepartureTime } = query; + const departureStopId: string = from[0].id; + const arrivalStopId: string = to[0].id; - const canRemainSeated = this.enterConnectionByTrip[tripId]; + let connection: IConnection = this.connectionsQueue.read(); - const initialStop = this.initialReachableStops.find(({ stop }) => - stop.id === connection.departureStop, - ); + while (connection && !this.connectionsQueue.closed) { - const departure = connection.departureTime.getTime(); - const arrival = this.profilesByStop[connection.departureStop].arrivalTime; + if (connection.departureTime < minimumDepartureTime && !this.connectionsQueue.closed) { + // starting criterion + // skip connections before the minimum departure time + connection = this.connectionsQueue.read(); + continue; + } - const transferDuration = departure - arrival; + if (this.getProfile(arrivalStopId).arrivalTime <= connection.departureTime.getTime()) { + // stopping criterion + // we cannot improve the tentative arrival time anymore + return resolve(); + } - const canTakeTransfer = ( - transferDuration > -Infinity && - (transferDuration >= minimumTransferDuration || initialStop && transferDuration >= 0) && - (transferDuration <= maximumTransferDuration || initialStop && transferDuration <= maximumWalkingDuration) && - connection["gtfs:pickupType"] !== PickupType.NotAvailable - ); + const tripId = connection.tripId; + const departureTime = connection.departureTime.getTime(); - if (canRemainSeated || canTakeTransfer) { - this.updateTrips(connection, tripId); + const canRemainSeated = this.enterConnectionByTrip[tripId]; + const canTakeTransfer = ( + ( + connection.departureStop === departureStopId || + this.getProfile(connection.departureStop).arrivalTime <= departureTime + ) && + connection["gtfs:pickupType"] !== PickupType.NotAvailable + ); - if (connection["gtfs:dropOffType"] !== DropOffType.NotAvailable) { - await this.updateProfiles(connection, tripId); - } + if (canRemainSeated || canTakeTransfer) { + // enterConnectionByTrip should point to the first reachable connection + if (!this.enterConnectionByTrip[tripId]) { + this.enterConnectionByTrip[tripId] = connection; } + // limited walking optimization + const canImprove = connection.arrivalTime.getTime() < this.getProfile(connection.arrivalStop).arrivalTime; + const canLeave = connection["gtfs:dropOffType"] !== DropOffType.NotAvailable; + + if (canLeave && canImprove) { + this.updateProfile(query, connection); + await this.scheduleExtraConnections(query, connection); + } } - if (!this.connectionsIterator.closed) { - connection = this.connectionsIterator.read(); + if (!this.connectionsQueue.closed) { + connection = this.connectionsQueue.read(); continue; } @@ -210,309 +237,158 @@ export default class CSAEarliestArrival implements IPublicTransportPlanner { } } - private async initInitialReachableStops(): Promise { - const fromLocation: IStop = this.query.from[0] as IStop; - - // Making sure the departure location has an id - const geoId = Geo.getId(this.query.from[0]); - if (!fromLocation.id) { - this.query.from[0].id = geoId; - this.query.from[0].name = "Departure location"; + private getProfile(stopId: string): ITransferProfile { + if (!this.profilesByStop[stopId]) { + this.profilesByStop[stopId] = { + departureTime: Infinity, + arrivalTime: Infinity, + }; } + return this.profilesByStop[stopId]; + } - this.initialReachableStops = await this.initialReachableStopsFinder.findReachableStops( - fromLocation, - ReachableStopsFinderMode.Source, - this.query.maximumWalkingDuration, - this.query.minimumWalkingSpeed, - ); - - // Abort when we can't reach a single stop. - if (this.initialReachableStops.length <= 1 && this.initialReachableStops[0].stop.id === geoId && this.context) { - this.context.emit(EventType.AbortQuery, "No reachable stops at departure location"); - - return false; - } + private async scheduleExtraConnections(query: IResolvedQuery, sourceConnection: IConnection) { + try { + const arrivalStop: ILocation = await this.locationResolver.resolve(sourceConnection.arrivalStop); + const reachableStops: IReachableStop[] = await this.transferReachableStopsFinder.findReachableStops( + arrivalStop as IStop, + ReachableStopsFinderMode.Source, + query.maximumTransferDuration, + query.minimumWalkingSpeed, + query.profileID, + ); - // Check if departure location is a stop. - for (const reachableStop of this.initialReachableStops) { - if (reachableStop.duration === 0) { - this.query.from[0] = reachableStop.stop; + if (this.finalReachableStops[arrivalStop.id]) { + reachableStops.push(this.finalReachableStops[arrivalStop.id]); } - } - if (this.context) { - this.context.emit(EventType.InitialReachableStops, this.initialReachableStops); - } - - this.initialReachableStops.forEach(({ stop, duration }: IReachableStop) => { - const departureTime = this.query.minimumDepartureTime.getTime(); - const arrivalTime = this.query.minimumDepartureTime.getTime() + duration; - - this.profilesByStop[stop.id] = { - departureTime, - arrivalTime, - }; - - if (duration > 0) { - const path: Path = Path.create(); - - const footpath: IStep = Step.create( - this.query.from[0], - stop, - TravelMode.Walking, - { - minimum: arrivalTime - departureTime, - }, - new Date(departureTime), - new Date(arrivalTime), - ); - - path.addStep(footpath); - - this.profilesByStop[stop.id].path = path; + for (const reachableStop of reachableStops) { + const { stop: stop, duration: duration } = reachableStop; + + if (duration && stop.id) { + const transferTentativeArrival = this.getProfile(stop.id).arrivalTime; + const newArrivalTime = new Date(sourceConnection.arrivalTime.getTime() + duration); + + if (transferTentativeArrival > newArrivalTime.getTime() && newArrivalTime <= query.maximumArrivalTime) { + // create a connection that resembles a footpath + // TODO, ditch the IReachbleStop and IConnection interfaces and make these proper objects + const transferConnection: IConnection = { + id: `TRANSFER_TO:${stop.id}`, + tripId: `TRANSFER_TO:${stop.id}`, + travelMode: TravelMode.Walking, // TODO, this should be part of the reachable stop object + departureTime: sourceConnection.arrivalTime, + departureStop: sourceConnection.arrivalStop, + arrivalTime: new Date(sourceConnection.arrivalTime.getTime() + duration), + arrivalStop: stop.id, + dropOffType: DropOffType.Regular, + pickupType: PickupType.Regular, + headsign: stop.id, + }; + + this.footpathsQueue.write(transferConnection); + } + } } - - }); - - return true; + } catch (e) { + if (this.eventBus) { + this.eventBus.emit(EventType.Warning, (e)); + } + } } - private async initFinalReachableStops(): Promise { - const arrivalStop: IStop = this.query.to[0] as IStop; + private async initInitialReachableStops(query: IResolvedQuery): Promise { + const fromLocation: ILocation = query.from[0]; - const geoId = Geo.getId(this.query.to[0]); - if (!this.query.to[0].id) { - this.query.to[0].id = geoId; - this.query.to[0].name = "Arrival location"; + // Making sure the departure location has an id + const geoId = Geo.getId(fromLocation); + if (!fromLocation.id) { + query.from[0].id = geoId; + query.from[0].name = "Departure location"; } - this.finalReachableStops = await this.finalReachableStopsFinder - .findReachableStops( - arrivalStop, - ReachableStopsFinderMode.Target, - this.query.maximumWalkingDuration, - this.query.minimumWalkingSpeed, - ); + const reachableStops = await this.initialReachableStopsFinder.findReachableStops( + fromLocation, + ReachableStopsFinderMode.Source, + query.maximumWalkingDuration, + query.minimumWalkingSpeed, + query.profileID, + ); - if (this.finalReachableStops.length <= 1 && this.finalReachableStops[0].stop.id === geoId && this.context) { - this.context.emit(EventType.AbortQuery, "No reachable stops at arrival location"); + // Abort when we can't reach a single stop. + if (reachableStops.length === 0) { + this.eventBus.emit(EventType.AbortQuery, "No reachable stops at departure location"); return false; } - if (this.context) { - this.context.emit(EventType.FinalReachableStops, this.finalReachableStops); + if (this.eventBus) { + this.eventBus.emit(EventType.InitialReachableStops, reachableStops); } - // Check if arrival location is a stop. - for (const reachableStop of this.finalReachableStops) { - if (reachableStop.duration === 0) { - this.query.to[0] = reachableStop.stop; + for (const reachableStop of reachableStops) { + const { stop: stop, duration: duration } = reachableStop; + + if (duration) { + // create a connection that resembles a footpath + // TODO, ditch the IReachbleStop and IConnection interfaces and make these proper objects + const transferConnection: IConnection = { + id: `MOVE_TO:${stop.id}`, + tripId: `MOVE_TO:${stop.id}`, + travelMode: TravelMode.Walking, // TODO, this should be part of the reachable stop object + departureTime: query.minimumDepartureTime, + departureStop: fromLocation.id, + arrivalTime: new Date(query.minimumDepartureTime.getTime() + duration), + arrivalStop: stop.id, + dropOffType: DropOffType.Regular, + pickupType: PickupType.Regular, + headsign: stop.id, + }; + + this.footpathsQueue.write(transferConnection); } } - this.profilesByStop[this.query.to[0].id] = { - departureTime: Infinity, - arrivalTime: Infinity, - }; - return true; } - private discoverConnection(connection: IConnection) { - this.setTripIdsByConnectionId(connection); - - if (!this.profilesByStop[connection.departureStop]) { - this.profilesByStop[connection.departureStop] = { - departureTime: Infinity, - arrivalTime: Infinity, - }; - } - - if (!this.profilesByStop[connection.arrivalStop]) { - this.profilesByStop[connection.arrivalStop] = { - departureTime: Infinity, - arrivalTime: Infinity, - }; - } - } - - private getTripIdsFromConnection(connection: IConnection): string[] { - return this.gtfsTripsByConnection[connection.id]; - } - - private setTripIdsByConnectionId(connection: IConnection): void { - if (!this.gtfsTripsByConnection.hasOwnProperty(connection.id)) { - this.gtfsTripsByConnection[connection.id] = []; - } - - this.gtfsTripsByConnection[connection.id].push(connection["gtfs:trip"]); - - let nextConnectionIndex = 0; - while (connection.nextConnection && nextConnectionIndex < connection.nextConnection.length) { - const connectionId = connection.nextConnection[nextConnectionIndex]; + private async initFinalReachableStops(query: IResolvedQuery): Promise { + const toLocation: ILocation = query.to[0]; - if (!this.gtfsTripsByConnection.hasOwnProperty(connectionId)) { - this.gtfsTripsByConnection[connectionId] = []; - - } - - this.gtfsTripsByConnection[connectionId].push(connection["gtfs:trip"]); - nextConnectionIndex++; + // Making sure the departure location has an id + const geoId = Geo.getId(toLocation); + if (!toLocation.id) { + query.to[0].id = geoId; + query.to[0].name = "Arrival location"; } - } - - private updateTrips(connection: IConnection, tripId: string): void { - const isInitialReachableStop = this.initialReachableStops.find(({ stop }: IReachableStop) => - stop.id === connection.departureStop, + const reachableStops = await this.finalReachableStopsFinder.findReachableStops( + toLocation, + ReachableStopsFinderMode.Target, + query.maximumWalkingDuration, + query.minimumWalkingSpeed, + query.profileID, ); - if (!this.enterConnectionByTrip[tripId] || isInitialReachableStop) { - this.enterConnectionByTrip[tripId] = connection; - } - } - - private async updateProfiles(connection: IConnection, tripId: string): Promise { - try { - const arrivalStop: ILocation = await this.locationResolver.resolve(connection.arrivalStop); - const reachableStops: IReachableStop[] = await this.transferReachableStopsFinder.findReachableStops( - arrivalStop as IStop, - ReachableStopsFinderMode.Source, - this.query.maximumTransferDuration, - this.query.minimumWalkingSpeed, - ); - - reachableStops.forEach((reachableStop: IReachableStop) => { - const { stop, duration } = reachableStop; - - if (!this.profilesByStop[stop.id]) { - this.profilesByStop[stop.id] = { - departureTime: Infinity, - arrivalTime: Infinity, - }; - } - - if (stop.id === this.query.to[0].id) { - return; - } - - const reachableStopArrival = this.profilesByStop[stop.id].arrivalTime; - - const departureTime = connection.departureTime.getTime(); - const arrivalTime = connection.arrivalTime.getTime() + duration; - - if (reachableStopArrival > arrivalTime) { - const transferProfile: ITransferProfile = { - departureTime, - arrivalTime, - exitConnection: connection, - enterConnection: this.enterConnectionByTrip[tripId], - }; - - if (duration > 0) { - const path: Path = Path.create(); - - const footpath: IStep = Step.create( - arrivalStop, - stop, - TravelMode.Walking, - { - minimum: duration, - }, - new Date(arrivalTime - duration), - new Date(arrivalTime), - ); - - path.addStep(footpath); - - transferProfile.path = path; - } - - if (this.context && this.context.listenerCount(EventType.AddedNewTransferProfile) > 0) { - this.emitTransferProfile(transferProfile); - } - - this.profilesByStop[stop.id] = transferProfile; - } - }); - - this.checkIfArrivalStopIsReachable(connection, tripId, arrivalStop); + // Abort when we can't reach a single stop. + if (reachableStops.length === 0) { + this.eventBus.emit(EventType.AbortQuery, "No reachable stops at arrival location"); - } catch (e) { - if (this.context) { - this.context.emitWarning(e); - } + return false; } - } - - private checkIfArrivalStopIsReachable(connection: IConnection, tripId: string, arrivalStop: ILocation): void { - const canReachArrivalStop = this.finalReachableStops.find((reachableStop: IReachableStop) => - reachableStop.stop.id === arrivalStop.id, - ); - - if (canReachArrivalStop) { - const finalLocationId = this.query.to[0].id; - - if (canReachArrivalStop.stop.id === finalLocationId) { - const departureTime = connection.departureTime.getTime(); - const arrivalTime = connection.arrivalTime.getTime(); - const reachableStopArrival = this.profilesByStop[connection.arrivalStop].arrivalTime; - - if (reachableStopArrival > arrivalTime) { - this.profilesByStop[finalLocationId] = { - departureTime, - arrivalTime, - exitConnection: connection, - enterConnection: this.enterConnectionByTrip[tripId], - }; - } - - } - - const finalProfile = this.profilesByStop[finalLocationId]; - - const departureTime = connection.arrivalTime.getTime(); - const arrivalTime = connection.arrivalTime.getTime() + canReachArrivalStop.duration; - if ((!finalProfile || finalProfile.arrivalTime > arrivalTime) && canReachArrivalStop.duration > 0) { - const path: Path = Path.create(); - - const footpath: IStep = Step.create( - arrivalStop, - this.query.to[0], - TravelMode.Walking, - { - minimum: arrivalTime - departureTime, - }, - new Date(departureTime), - new Date(arrivalTime), - ); - - path.addStep(footpath); + if (this.eventBus) { + this.eventBus.emit(EventType.FinalReachableStops, reachableStops); + } - this.profilesByStop[finalLocationId] = { - departureTime, - arrivalTime, - path, + for (const reachableStop of reachableStops) { + if (reachableStop.duration > 0) { + this.finalReachableStops[reachableStop.stop.id] = { + stop: toLocation as IStop, + duration: reachableStop.duration, }; } } - } - - private async emitTransferProfile(transferProfile: ITransferProfile): Promise { - try { - const departureStop = await this.locationResolver.resolve(transferProfile.enterConnection.departureStop); - const arrivalStop = await this.locationResolver.resolve(transferProfile.exitConnection.arrivalStop); - - this.context.emit(EventType.AddedNewTransferProfile, { - departureStop, - arrivalStop, - }); - } catch (e) { - this.context.emitWarning(e); - } + return true; } } diff --git a/src/planner/public-transport/CSAEarliestArrivalVerbose.ts b/src/planner/public-transport/CSAEarliestArrivalVerbose.ts new file mode 100644 index 00000000..20a58106 --- /dev/null +++ b/src/planner/public-transport/CSAEarliestArrivalVerbose.ts @@ -0,0 +1,38 @@ +import { inject, injectable, tagged } from "inversify"; +import IConnection from "../../entities/connections/connections"; +import ReachableStopsSearchPhase from "../../enums/ReachableStopsSearchPhase"; +import EventBus from "../../events/EventBus"; +import EventType from "../../events/EventType"; +import IConnectionsProvider from "../../fetcher/connections/IConnectionsProvider"; +import ILocationResolver from "../../query-runner/ILocationResolver"; +import IResolvedQuery from "../../query-runner/IResolvedQuery"; +import TYPES from "../../types"; +import IReachableStopsFinder from "../stops/IReachableStopsFinder"; +import CSAEarliestArrival from "./CSAEarliestArrival"; + +@injectable() +export default class CSAEarliestArrivalVerbose extends CSAEarliestArrival { + constructor( + @inject(TYPES.ConnectionsProvider) + connectionsProvider: IConnectionsProvider, + @inject(TYPES.LocationResolver) + locationResolver: ILocationResolver, + @inject(TYPES.ReachableStopsFinder) + @tagged("phase", ReachableStopsSearchPhase.Transfer) + transferReachableStopsFinder: IReachableStopsFinder, + @inject(TYPES.ReachableStopsFinder) + @tagged("phase", ReachableStopsSearchPhase.Initial) + initialReachableStopsFinder: IReachableStopsFinder, + @inject(TYPES.ReachableStopsFinder) + @tagged("phase", ReachableStopsSearchPhase.Final) + finalReachableStopsFinder: IReachableStopsFinder, + ) { + super(connectionsProvider, locationResolver, transferReachableStopsFinder, + initialReachableStopsFinder, finalReachableStopsFinder); + } + + protected updateProfile(query: IResolvedQuery, connection: IConnection) { + super.updateProfile(query, connection); + EventBus.getInstance().emit(EventType.PointReached, this.locationResolver.resolve(connection.arrivalStop)); + } +} diff --git a/src/planner/public-transport/CSAProfile.test.ts b/src/planner/public-transport/CSAProfile.test.ts index 8bcba17e..72f9c95e 100644 --- a/src/planner/public-transport/CSAProfile.test.ts +++ b/src/planner/public-transport/CSAProfile.test.ts @@ -1,16 +1,19 @@ import "jest"; import LDFetch from "ldfetch"; +import Catalog from "../../Catalog"; import Defaults from "../../Defaults"; +import RoutableTileRegistry from "../../entities/tiles/registry"; import TravelMode from "../../enums/TravelMode"; -import ConnectionsFetcherLazy from "../../fetcher/connections/lazy/ConnectionsFetcherLazy"; -import ConnectionsFetcherNMBSTest from "../../fetcher/connections/tests/ConnectionsFetcherNMBSTest"; +import ConnectionsFetcherRaw from "../../fetcher/connections/ConnectionsFetcherRaw"; +import ConnectionsProviderDefault from "../../fetcher/connections/ConnectionsProviderDefault"; +import ConnectionsProviderNMBSTest from "../../fetcher/connections/tests/ConnectionsProviderNMBSTest"; import connectionsIngelmunsterGhent from "../../fetcher/connections/tests/data/ingelmunster-ghent"; import connectionsJoining from "../../fetcher/connections/tests/data/joining"; import connectionsSplitting from "../../fetcher/connections/tests/data/splitting"; import StopsFetcherLDFetch from "../../fetcher/stops/ld-fetch/StopsFetcherLDFetch"; +import ILeg from "../../interfaces/ILeg"; import IPath from "../../interfaces/IPath"; import IQuery from "../../interfaces/IQuery"; -import IStep from "../../interfaces/IStep"; import IResolvedQuery from "../../query-runner/IResolvedQuery"; import LocationResolverDefault from "../../query-runner/LocationResolverDefault"; import QueryRunnerDefault from "../../query-runner/QueryRunnerDefault"; @@ -26,20 +29,18 @@ describe("[PublicTransportPlannerCSAProfile]", () => { const createCSA = (connections) => { const ldFetch = new LDFetch({ headers: { Accept: "application/ld+json" } }); - const connectionFetcher = new ConnectionsFetcherNMBSTest(connections); - connectionFetcher.setIteratorOptions({ backward: true }); - + const connectionProvider = new ConnectionsProviderNMBSTest(connections); const stopsFetcher = new StopsFetcherLDFetch(ldFetch); stopsFetcher.setAccessUrl("https://irail.be/stations/NMBS"); - const locationResolver = new LocationResolverDefault(stopsFetcher); + const locationResolver = new LocationResolverDefault(stopsFetcher, new RoutableTileRegistry()); const reachableStopsFinder = new ReachableStopsFinderBirdsEyeCached(stopsFetcher); const journeyExtractor = new JourneyExtractorProfile( locationResolver, ); return new CSAProfile( - connectionFetcher, + connectionProvider, locationResolver, reachableStopsFinder, reachableStopsFinder, @@ -52,9 +53,9 @@ describe("[PublicTransportPlannerCSAProfile]", () => { let result: IPath[]; const query: IResolvedQuery = { - publicTransportOnly: true, from: [{latitude: 50.914326, longitude: 3.255415 }], to: [{ latitude: 51.035896, longitude: 3.710875 }], + profileID: "https://hdelva.be/profile/pedestrian", minimumDepartureTime: new Date("2018-11-06T09:00:00.000Z"), maximumArrivalTime: new Date("2018-11-06T19:00:00.000Z"), maximumTransfers: 8, @@ -73,10 +74,10 @@ describe("[PublicTransportPlannerCSAProfile]", () => { expect(result).toBeDefined(); for (const path of result) { - expect(path.steps).toBeDefined(); - expect(path.steps[0]).toBeDefined(); - expect(query.from.map((from) => from.id)).toContain(path.steps[0].startLocation.id); - expect(query.to.map((to) => to.id)).toContain(path.steps[path.steps.length - 1].stopLocation.id); + expect(path.legs).toBeDefined(); + expect(path.legs[0]).toBeDefined(); + expect(query.from.map((from) => from.id)).toContain(path.legs[0].getStartLocation().id); + expect(query.to.map((to) => to.id)).toContain(path.legs[path.legs.length - 1].getStopLocation().id); } }); }); @@ -85,7 +86,6 @@ describe("[PublicTransportPlannerCSAProfile]", () => { let result: IPath[]; const query: IResolvedQuery = { - publicTransportOnly: true, from: [{ id: "http://irail.be/stations/NMBS/008821006", latitude: 51.2172, @@ -96,6 +96,7 @@ describe("[PublicTransportPlannerCSAProfile]", () => { latitude: 50.859663, longitude: 4.360846, }], + profileID: "https://hdelva.be/profile/pedestrian", minimumDepartureTime: new Date("2017-12-19T15:50:00.000Z"), maximumArrivalTime: new Date("2017-12-19T16:50:00.000Z"), maximumTransfers: 1, @@ -115,13 +116,13 @@ describe("[PublicTransportPlannerCSAProfile]", () => { expect(result.length).toBeGreaterThanOrEqual(1); for (const path of result) { - expect(path.steps).toBeDefined(); + expect(path.legs).toBeDefined(); - expect(path.steps.length).toEqual(1); - expect(path.steps[0]).toBeDefined(); + expect(path.legs.length).toEqual(1); + expect(path.legs[0]).toBeDefined(); - expect(query.from.map((from) => from.id)).toContain(path.steps[0].startLocation.id); - expect(query.to.map((to) => to.id)).toContain(path.steps[0].stopLocation.id); + expect(query.from.map((from) => from.id)).toContain(path.legs[0].getStartLocation().id); + expect(query.to.map((to) => to.id)).toContain(path.legs[0].getStopLocation().id); } }); }); @@ -130,7 +131,6 @@ describe("[PublicTransportPlannerCSAProfile]", () => { let result: IPath[]; const query: IResolvedQuery = { - publicTransportOnly: true, from: [{ id: "http://irail.be/stations/NMBS/008812005", latitude: 50.859663, @@ -141,6 +141,7 @@ describe("[PublicTransportPlannerCSAProfile]", () => { latitude: 51.2172, longitude: 4.421101, }], + profileID: "https://hdelva.be/profile/pedestrian", minimumDepartureTime: new Date("2017-12-19T16:20:00.000Z"), maximumArrivalTime: new Date("2017-12-19T16:50:00.000Z"), maximumTransfers: 1, @@ -160,13 +161,13 @@ describe("[PublicTransportPlannerCSAProfile]", () => { expect(result.length).toBeGreaterThanOrEqual(1); for (const path of result) { - expect(path.steps).toBeDefined(); + expect(path.legs).toBeDefined(); - expect(path.steps.length).toEqual(1); - expect(path.steps[0]).toBeDefined(); + expect(path.legs.length).toEqual(1); + expect(path.legs[0]).toBeDefined(); - expect(query.from.map((from) => from.id)).toContain(path.steps[0].startLocation.id); - expect(query.to.map((to) => to.id)).toContain(path.steps[0].stopLocation.id); + expect(query.from.map((from) => from.id)).toContain(path.legs[0].getStartLocation().id); + expect(query.to.map((to) => to.id)).toContain(path.legs[0].getStopLocation().id); } }); }); @@ -176,21 +177,27 @@ describe("[PublicTransportPlannerCSAProfile]", () => { const createQueryRunner = () => { const ldFetch = new LDFetch({ headers: { Accept: "application/ld+json" } }); - const connectionFetcher = new ConnectionsFetcherLazy(ldFetch); - connectionFetcher.setTravelMode(TravelMode.Train); - connectionFetcher.setAccessUrl("https://graph.irail.be/sncb/connections"); + const catalog = new Catalog(); + catalog.addConnectionsSource("https://graph.irail.be/sncb/connections", TravelMode.Train); + const connectionProvider = new ConnectionsProviderDefault( + (travelMode: TravelMode) => { + const fetcher = new ConnectionsFetcherRaw(); + fetcher.setTravelMode(travelMode); + return fetcher; + }, catalog, + ); const stopsFetcher = new StopsFetcherLDFetch(ldFetch); stopsFetcher.setAccessUrl("https://irail.be/stations/NMBS"); - const locationResolver = new LocationResolverDefault(stopsFetcher); + const locationResolver = new LocationResolverDefault(stopsFetcher, new RoutableTileRegistry()); const reachableStopsFinder = new ReachableStopsFinderBirdsEyeCached(stopsFetcher); const journeyExtractor = new JourneyExtractorProfile( locationResolver, ); const CSA = new CSAProfile( - connectionFetcher, + connectionProvider, locationResolver, reachableStopsFinder, reachableStopsFinder, @@ -198,52 +205,52 @@ describe("[PublicTransportPlannerCSAProfile]", () => { journeyExtractor, ); - return new QueryRunnerDefault(locationResolver, CSA); + return new QueryRunnerDefault(locationResolver, CSA, undefined); }; - const checkStops = (result, query) => { + const checkStops = (result: IPath[], query) => { expect(result).toBeDefined(); expect(result.length).toBeGreaterThanOrEqual(1); for (const path of result) { - expect(path.steps).toBeDefined(); + expect(path.legs).toBeDefined(); - expect(path.steps.length).toBeGreaterThanOrEqual(1); + expect(path.legs.length).toBeGreaterThanOrEqual(1); let currentLocation = query.from; - path.steps.forEach((step: IStep) => { - expect(step).toBeDefined(); - expect(currentLocation).toEqual(step.startLocation.id); - currentLocation = step.stopLocation.id; + path.legs.forEach((leg: ILeg) => { + expect(leg).toBeDefined(); + expect(currentLocation).toEqual(leg.getStartLocation().id); + currentLocation = leg.getStopLocation().id; }); expect(query.to).toEqual(currentLocation); } }; - const checkTimes = (result, minimumDepartureTime, maximumArrivalTime) => { + const checkTimes = (result: IPath[], minimumDepartureTime, maximumArrivalTime) => { expect(result).toBeDefined(); expect(result.length).toBeGreaterThanOrEqual(1); for (const path of result) { - expect(path.steps).toBeDefined(); + expect(path.legs).toBeDefined(); - expect(path.steps.length).toBeGreaterThanOrEqual(1); - expect(path.steps[0]).toBeDefined(); - expect(path.steps[path.steps.length - 1]).toBeDefined(); + expect(path.legs.length).toBeGreaterThanOrEqual(1); + expect(path.legs[0]).toBeDefined(); + expect(path.legs[path.legs.length - 1]).toBeDefined(); let currentTime = minimumDepartureTime.getTime(); - path.steps.forEach((step: IStep) => { - expect(step).toBeDefined(); - if (step.travelMode === TravelMode.Walking) { - currentTime += step.duration.minimum; + path.legs.forEach((leg: ILeg) => { + expect(leg).toBeDefined(); + if (leg.getTravelMode() === TravelMode.Walking) { + currentTime += leg.getMinimumDuration(); } else { - expect(currentTime).toBeLessThanOrEqual(step.startTime.getTime()); - currentTime = step.stopTime.getTime(); + expect(currentTime).toBeLessThanOrEqual(leg.getStartTime().getTime()); + currentTime = leg.getStopTime().getTime(); } }); - expect(path.steps[0].startTime.getTime()).toBeGreaterThanOrEqual(minimumDepartureTime.getTime()); + expect(path.legs[0].getStartTime().getTime()).toBeGreaterThanOrEqual(minimumDepartureTime.getTime()); expect(currentTime).toBeLessThanOrEqual(maximumArrivalTime.getTime()); } }; @@ -257,7 +264,6 @@ describe("[PublicTransportPlannerCSAProfile]", () => { const maximumArrivalTime = new Date(1543518087748); const query: IQuery = { - publicTransportOnly: true, from: "http://irail.be/stations/NMBS/008896925", // Ingelmunster to: "http://irail.be/stations/NMBS/008892007", // Ghent-Sint-Pieters maximumArrivalTime, @@ -285,11 +291,11 @@ describe("[PublicTransportPlannerCSAProfile]", () => { jest.setTimeout(100000); const minimumDepartureTime = new Date(); + minimumDepartureTime.setHours(8); const maximumArrivalTime = new Date(); - maximumArrivalTime.setHours(maximumArrivalTime.getHours() + 2); + maximumArrivalTime.setHours(8 + 2); const query: IQuery = { - publicTransportOnly: true, from: "http://irail.be/stations/NMBS/008896925", // Ingelmunster to: "http://irail.be/stations/NMBS/008892007", // Ghent-Sint-Pieters maximumArrivalTime, @@ -317,11 +323,11 @@ describe("[PublicTransportPlannerCSAProfile]", () => { jest.setTimeout(100000); const minimumDepartureTime = new Date(); + minimumDepartureTime.setHours(8); const maximumArrivalTime = new Date(); - maximumArrivalTime.setHours(maximumArrivalTime.getHours() + 3); + maximumArrivalTime.setHours(8 + 3); const query: IQuery = { - publicTransportOnly: true, from: "http://irail.be/stations/NMBS/008812005", // Brussels North to: "http://irail.be/stations/NMBS/008892007", // Ghent-Sint-Pieters maximumArrivalTime, diff --git a/src/planner/public-transport/CSAProfile.ts b/src/planner/public-transport/CSAProfile.ts index 20cb7941..63e58475 100644 --- a/src/planner/public-transport/CSAProfile.ts +++ b/src/planner/public-transport/CSAProfile.ts @@ -1,12 +1,13 @@ import { ArrayIterator, AsyncIterator } from "asynciterator"; +import { EventEmitter } from "events"; import { inject, injectable, tagged } from "inversify"; -import Context from "../../Context"; +import IConnection from "../../entities/connections/connections"; import DropOffType from "../../enums/DropOffType"; -import EventType from "../../enums/EventType"; import PickupType from "../../enums/PickupType"; import ReachableStopsFinderMode from "../../enums/ReachableStopsFinderMode"; import ReachableStopsSearchPhase from "../../enums/ReachableStopsSearchPhase"; -import IConnection from "../../fetcher/connections/IConnection"; +import EventBus from "../../events/EventBus"; +import EventType from "../../events/EventType"; import IConnectionsProvider from "../../fetcher/connections/IConnectionsProvider"; import IStop from "../../fetcher/stops/IStop"; import ILocation from "../../interfaces/ILocation"; @@ -50,11 +51,11 @@ export default class CSAProfile implements IPublicTransportPlanner { private readonly finalReachableStopsFinder: IReachableStopsFinder; private readonly transferReachableStopsFinder: IReachableStopsFinder; private readonly journeyExtractor: IJourneyExtractor; - private readonly context: Context; + private readonly eventBus: EventEmitter; private profilesByStop: IProfilesByStop = {}; // S private earliestArrivalByTrip: IEarliestArrivalByTrip = {}; // T - private durationToTargetByStop: DurationMs[] = []; + private durationToTargetByStop = {}; private gtfsTripByConnection = {}; private initialReachableStops: IReachableStop[] = []; @@ -77,8 +78,6 @@ export default class CSAProfile implements IPublicTransportPlanner { finalReachableStopsFinder: IReachableStopsFinder, @inject(TYPES.JourneyExtractor) journeyExtractor: IJourneyExtractor, - @inject(TYPES.Context) - context?: Context, ) { this.connectionsProvider = connectionsProvider; this.locationResolver = locationResolver; @@ -86,39 +85,32 @@ export default class CSAProfile implements IPublicTransportPlanner { this.transferReachableStopsFinder = transferReachableStopsFinder; this.finalReachableStopsFinder = finalReachableStopsFinder; this.journeyExtractor = journeyExtractor; - this.context = context; + this.eventBus = EventBus.getInstance(); } public async plan(query: IResolvedQuery): Promise> { this.query = query; - - this.setBounds(); - return this.calculateJourneys(); } - private setBounds() { + private async calculateJourneys(): Promise> { + const hasInitialReachableStops: boolean = await this.initDurationToTargetByStop(); + const hasFinalReachableStops: boolean = await this.initInitialReachableStops(); + + if (!hasInitialReachableStops || !hasFinalReachableStops) { + return Promise.resolve(new ArrayIterator([])); + } + const { minimumDepartureTime: lowerBoundDate, maximumArrivalTime: upperBoundDate, } = this.query; - this.connectionsProvider.setIteratorOptions({ + this.connectionsIterator = this.connectionsProvider.createIterator({ backward: true, upperBoundDate, lowerBoundDate, }); - } - - private async calculateJourneys(): Promise> { - const hasInitialReachableStops: boolean = await this.initDurationToTargetByStop(); - const hasFinalReachableStops: boolean = await this.initInitialReachableStops(); - - if (!hasInitialReachableStops || !hasFinalReachableStops) { - return Promise.resolve(new ArrayIterator([])); - } - - this.connectionsIterator = this.connectionsProvider.createIterator(); const self = this; @@ -162,8 +154,8 @@ export default class CSAProfile implements IPublicTransportPlanner { break; } - if (this.context) { - this.context.emit(EventType.ConnectionScan, connection); + if (this.eventBus) { + this.eventBus.emit(EventType.ConnectionScan, connection); } this.discoverConnection(connection); @@ -266,18 +258,19 @@ export default class CSAProfile implements IPublicTransportPlanner { ReachableStopsFinderMode.Target, this.query.maximumWalkingDuration, this.query.minimumWalkingSpeed, + this.query.profileID, ); - if (reachableStops.length <= 1 && reachableStops[0].stop.id === geoId) { - if (this.context) { - this.context.emit(EventType.AbortQuery, "No reachable stops at arrival location"); + if (reachableStops.length < 1) { + if (this.eventBus) { + this.eventBus.emit(EventType.AbortQuery, "No reachable stops at arrival location"); } return false; } - if (this.context) { - this.context.emit(EventType.FinalReachableStops, reachableStops); + if (this.eventBus) { + this.eventBus.emit(EventType.FinalReachableStops, reachableStops); } for (const reachableStop of reachableStops) { @@ -305,6 +298,7 @@ export default class CSAProfile implements IPublicTransportPlanner { ReachableStopsFinderMode.Source, this.query.maximumWalkingDuration, this.query.minimumWalkingSpeed, + this.query.profileID, ); for (const reachableStop of this.initialReachableStops) { @@ -313,16 +307,16 @@ export default class CSAProfile implements IPublicTransportPlanner { } } - if (this.initialReachableStops.length <= 1 && this.initialReachableStops[0].stop.id === geoId) { - if (this.context) { - this.context.emit(EventType.AbortQuery, "No reachable stops at departure location"); + if (this.initialReachableStops.length < 1) { + if (this.eventBus) { + this.eventBus.emit(EventType.AbortQuery, "No reachable stops at departure location"); } return false; } - if (this.context) { - this.context.emit(EventType.InitialReachableStops, this.initialReachableStops); + if (this.eventBus) { + this.eventBus.emit(EventType.InitialReachableStops, this.initialReachableStops); } return true; @@ -360,8 +354,8 @@ export default class CSAProfile implements IPublicTransportPlanner { if (!minimumArrivalTime || tripArrivalTime < minimumArrivalTime) { earliestArrivalTimeByTransfers[amountOfTransfers] = { - "arrivalTime": tripArrivalTime, - "gtfs:trip": tripId, + arrivalTime: tripArrivalTime, + tripId, }; minimumArrivalTime = tripArrivalTime; } @@ -453,6 +447,7 @@ export default class CSAProfile implements IPublicTransportPlanner { ReachableStopsFinderMode.Source, this.query.maximumTransferDuration, this.query.minimumWalkingSpeed, + this.query.profileID, ); reachableStops.forEach((reachableStop: IReachableStop) => { @@ -467,8 +462,8 @@ export default class CSAProfile implements IPublicTransportPlanner { }); } catch (e) { - if (this.context) { - this.context.emitWarning(e); + if (this.eventBus) { + this.eventBus.emit(EventType.Warning, (e)); } } } @@ -482,14 +477,14 @@ export default class CSAProfile implements IPublicTransportPlanner { transferProfile.exitConnection.arrivalStop, ); - this.context.emit(EventType.AddedNewTransferProfile, { + this.eventBus.emit(EventType.AddedNewTransferProfile, { departureStop, arrivalStop, amountOfTransfers, }); } catch (e) { - this.context.emitWarning(e); + this.eventBus.emit(EventType.Warning, (e)); } } @@ -543,7 +538,7 @@ export default class CSAProfile implements IPublicTransportPlanner { newTransferProfile.exitConnection = possibleExitConnection; newTransferProfile.departureTime = departureTime; - if (this.context && this.context.listenerCount(EventType.AddedNewTransferProfile) > 0) { + if (this.eventBus && this.eventBus.listenerCount(EventType.AddedNewTransferProfile) > 0) { this.emitTransferProfile(newTransferProfile, amountOfTransfers); } diff --git a/src/planner/public-transport/JourneyExtractorEarliestArrival.ts b/src/planner/public-transport/JourneyExtractorEarliestArrival.ts index 8277019e..f79bed71 100644 --- a/src/planner/public-transport/JourneyExtractorEarliestArrival.ts +++ b/src/planner/public-transport/JourneyExtractorEarliestArrival.ts @@ -1,35 +1,24 @@ import { AsyncIterator, EmptyIterator, SingletonIterator } from "asynciterator"; import { inject, injectable } from "inversify"; -import Context from "../../Context"; -import ILocation from "../../interfaces/ILocation"; import IPath from "../../interfaces/IPath"; -import IStep from "../../interfaces/IStep"; import ILocationResolver from "../../query-runner/ILocationResolver"; import IResolvedQuery from "../../query-runner/IResolvedQuery"; import TYPES from "../../types"; +import Leg from "../Leg"; import Path from "../Path"; import Step from "../Step"; import IProfileByStop from "./CSA/data-structure/stops/IProfileByStop"; import ITransferProfile from "./CSA/data-structure/stops/ITransferProfile"; import IJourneyExtractor from "./IJourneyExtractor"; -/** - * The earliest arrival journey based on the profiles and query from [[CSAEarliestArrival]]. - * A journey is an [[IPath]] that consist of several [[IStep]]s. - * - */ @injectable() export default class JourneyExtractorEarliestArrival implements IJourneyExtractor { private readonly locationResolver: ILocationResolver; - private context: Context; - constructor( @inject(TYPES.LocationResolver) locationResolver: ILocationResolver, - @inject(TYPES.Context)context?: Context, ) { this.locationResolver = locationResolver; - this.context = context; } public async extractJourneys( @@ -39,51 +28,45 @@ export default class JourneyExtractorEarliestArrival implements IJourneyExtracto const path: Path = Path.create(); const departureStopId: string = query.from[0].id; - let currentStopId: string = query.to[0].id; - let currentProfile: ITransferProfile = profilesByStop[currentStopId]; - - while (currentStopId !== departureStopId && (currentProfile.enterConnection || currentProfile.path)) { - const { enterConnection, exitConnection, path: profilePath } = currentProfile; - - if (profilePath) { - currentStopId = profilePath.getStartLocationId(); - - if (currentStopId === departureStopId) { - const lastStep = path.steps[path.steps.length - 1]; - const timeToAdd = lastStep.startTime.getTime() - profilePath.steps[0].stopTime.getTime(); - - profilePath.addTime(timeToAdd); - } - path.addPath(profilePath); - } - - if (currentProfile.enterConnection && currentProfile.exitConnection) { - const enterLocation: ILocation = await this.locationResolver.resolve(enterConnection.departureStop); - const exitLocation: ILocation = await this.locationResolver.resolve(exitConnection.arrivalStop); - - const step: IStep = Step.createFromConnections( - enterConnection, - exitConnection, - ); - - step.startLocation = enterLocation; - step.stopLocation = exitLocation; - path.addStep(step); - - currentStopId = enterConnection.departureStop; - } - - currentProfile = profilesByStop[currentStopId]; + while (currentStopId !== departureStopId && + profilesByStop[currentStopId] && + profilesByStop[currentStopId].exitConnection) { + + const currentProfile: ITransferProfile = profilesByStop[currentStopId]; + const { enterConnection, exitConnection } = currentProfile; + const promises = [ + this.locationResolver.resolve(enterConnection.departureStop), + this.locationResolver.resolve(exitConnection.arrivalStop), + ]; + const [enterLocation, exitLocation] = await Promise.all(promises); + + const arrivalTime = exitConnection.arrivalTime; + const departureTime = enterConnection.departureTime; + const duration = arrivalTime.getTime() - departureTime.getTime(); + + const step = new Step( + enterLocation, + exitLocation, + { average: duration }, + departureTime, + arrivalTime, + undefined, + enterConnection.id, + exitConnection.id, + ); + + const leg = new Leg(exitConnection.travelMode, [step]); + + path.prependLeg(leg); + currentStopId = enterConnection.departureStop; } - if (!path.steps.length) { + if (!path.legs.length) { return new EmptyIterator(); } - path.reverse(); - return new SingletonIterator(path); } diff --git a/src/planner/public-transport/JourneyExtractorProfile.ts b/src/planner/public-transport/JourneyExtractorProfile.ts index 9a059ea3..430dde1f 100644 --- a/src/planner/public-transport/JourneyExtractorProfile.ts +++ b/src/planner/public-transport/JourneyExtractorProfile.ts @@ -1,8 +1,10 @@ import { ArrayIterator, AsyncIterator } from "asynciterator"; +import { EventEmitter } from "events"; import { inject, injectable } from "inversify"; -import Context from "../../Context"; +import IConnection from "../../entities/connections/connections"; import TravelMode from "../../enums/TravelMode"; -import IConnection from "../../fetcher/connections/IConnection"; +import EventBus from "../../events/EventBus"; +import EventType from "../../events/EventType"; import ILocation from "../../interfaces/ILocation"; import IPath from "../../interfaces/IPath"; import IStep from "../../interfaces/IStep"; @@ -10,6 +12,7 @@ import { DurationMs } from "../../interfaces/units"; import ILocationResolver from "../../query-runner/ILocationResolver"; import IResolvedQuery from "../../query-runner/IResolvedQuery"; import TYPES from "../../types"; +import Leg from "../Leg"; import Path from "../Path"; import Step from "../Step"; import IProfile from "./CSA/data-structure/stops/IProfile"; @@ -29,14 +32,13 @@ export default class JourneyExtractorProfile implements IJourneyExtractor { private readonly locationResolver: ILocationResolver; private bestArrivalTime: number[][] = []; - private context: Context; + private eventBus: EventEmitter; constructor( @inject(TYPES.LocationResolver) locationResolver: ILocationResolver, - @inject(TYPES.Context)context?: Context, ) { this.locationResolver = locationResolver; - this.context = context; + this.eventBus = EventBus.getInstance(); } public async extractJourneys( @@ -79,8 +81,8 @@ export default class JourneyExtractorProfile implements IJourneyExtractor { ); } catch (e) { - if (this.context) { - this.context.emitWarning(e); + if (this.eventBus) { + this.eventBus.emit(EventType.Warning, (e)); } } } @@ -152,14 +154,13 @@ export default class JourneyExtractorProfile implements IJourneyExtractor { if (departureTime !== transferDepartureTime) { let timeToSubtract: DurationMs = 0; - if (path.steps.length > 0) { - timeToSubtract = departureTime - path.steps[path.steps.length - 1].stopTime.getTime(); + if (path.legs.length > 0) { + timeToSubtract = departureTime - path.legs[path.legs.length - 1].getStopTime().getTime(); } const footpath: IStep = Step.create( currentLocation, enterLocation, - TravelMode.Walking, { minimum: transferDepartureTime - departureTime, }, @@ -167,20 +168,23 @@ export default class JourneyExtractorProfile implements IJourneyExtractor { new Date(transferDepartureTime - timeToSubtract), ); - path.addStep(footpath); + const footpathLeg = new Leg(TravelMode.Walking, [footpath]); + path.appendLeg(footpathLeg); } // Public transport step. const step: IStep = Step.createFromConnections(enterConnection, exitConnection); step.startLocation = enterLocation; step.stopLocation = exitLocation; - path.addStep(step); + + const leg = new Leg(exitConnection.travelMode, [step]); + path.appendLeg(leg); currentLocation = exitLocation; remainingTransfers--; // Stop if we already arrived. - if (path.steps[path.steps.length - 1].stopLocation.id === arrivalLocation.id) { + if (path.legs[path.legs.length - 1].getStopLocation().id === arrivalLocation.id) { break; } @@ -213,7 +217,6 @@ export default class JourneyExtractorProfile implements IJourneyExtractor { const footpath: IStep = Step.create( currentLocation, arrivalLocation, - TravelMode.Walking, { minimum: arrivalTime.getTime() - transferArrivalTime.getTime(), }, @@ -221,13 +224,14 @@ export default class JourneyExtractorProfile implements IJourneyExtractor { arrivalTime, ); - path.addStep(footpath); + const footpathLeg = new Leg(TravelMode.Walking, [footpath]); + path.appendLeg(footpathLeg); } } } // Check if path ends in the arrival location. - if (path.steps[path.steps.length - 1].stopLocation.id !== arrivalLocation.id) { + if (path.legs[path.legs.length - 1].getStopLocation().id !== arrivalLocation.id) { // This should never happen. return Promise.reject("Can't reach arrival stop:"); } diff --git a/src/planner/road/RoadPlannerBirdsEye.test.ts b/src/planner/road/RoadPlannerBirdsEye.test.ts index b15577ca..18b329a6 100644 --- a/src/planner/road/RoadPlannerBirdsEye.test.ts +++ b/src/planner/road/RoadPlannerBirdsEye.test.ts @@ -1,5 +1,6 @@ import "jest"; import LDFetch from "ldfetch"; +import RoutableTileRegistry from "../../entities/tiles/registry"; import StopsFetcherLDFetch from "../../fetcher/stops/ld-fetch/StopsFetcherLDFetch"; import IPath from "../../interfaces/IPath"; import LocationResolverDefault from "../../query-runner/LocationResolverDefault"; @@ -13,7 +14,7 @@ const planner: IRoadPlanner = new RoadPlannerBirdsEye(); const stopsFetcher = new StopsFetcherLDFetch(ldFetch); stopsFetcher.setAccessUrl("https://irail.be/stations/NMBS"); -const locationResolver = new LocationResolverDefault(stopsFetcher); +const locationResolver = new LocationResolverDefault(stopsFetcher, new RoutableTileRegistry()); test("[RoadPlannerBirdsEye] distance between stops", async () => { @@ -23,6 +24,7 @@ test("[RoadPlannerBirdsEye] distance between stops", async () => { const iterator = await planner.plan({ from: [kortrijkLocation], // Kortrijk to: [ghentLocation], // Ghent-Sint-Pieters, + profileID: "https://hdelva.be/profile/pedestrian", minimumWalkingSpeed: 3, maximumWalkingSpeed: 6, }); diff --git a/src/planner/road/RoadPlannerBirdsEye.ts b/src/planner/road/RoadPlannerBirdsEye.ts index fdf23eed..573a15b7 100644 --- a/src/planner/road/RoadPlannerBirdsEye.ts +++ b/src/planner/road/RoadPlannerBirdsEye.ts @@ -8,6 +8,7 @@ import { DurationMs, SpeedKmH } from "../../interfaces/units"; import IResolvedQuery from "../../query-runner/IResolvedQuery"; import Geo from "../../util/Geo"; import Units from "../../util/Units"; +import Leg from "../Leg"; import Path from "../Path"; import IRoadPlanner from "./IRoadPlanner"; @@ -70,12 +71,13 @@ export default class RoadPlannerBirdsEye implements IRoadPlanner { return; } - return new Path([{ - startLocation: from, - stopLocation: to, - duration, - distance, - travelMode: TravelMode.Walking, - }]); + return new Path([ + new Leg(TravelMode.Walking, [{ + startLocation: from, + stopLocation: to, + duration, + distance, + }]), + ]); } } diff --git a/src/planner/road/RoadPlannerPathfinding.ts b/src/planner/road/RoadPlannerPathfinding.ts new file mode 100644 index 00000000..ec5f8ad2 --- /dev/null +++ b/src/planner/road/RoadPlannerPathfinding.ts @@ -0,0 +1,178 @@ +import { ArrayIterator, AsyncIterator } from "asynciterator"; +import { EventEmitter } from "events"; +import { inject, injectable, tagged } from "inversify"; +import inBBox from "tiles-in-bbox"; +import Profile from "../../entities/profile/Profile"; +import { RoutableTileCoordinate } from "../../entities/tiles/coordinate"; +import RoutableTileRegistry from "../../entities/tiles/registry"; +import RoutingPhase from "../../enums/RoutingPhase"; +import TravelMode from "../../enums/TravelMode"; +import EventBus from "../../events/EventBus"; +import EventType from "../../events/EventType"; +import IProfileProvider from "../../fetcher/profiles/IProfileProvider"; +import IRoutableTileProvider from "../../fetcher/tiles/IRoutableTileProvider"; +import ILocation from "../../interfaces/ILocation"; +import IPath from "../../interfaces/IPath"; +import IStep from "../../interfaces/IStep"; +import PathfinderProvider from "../../pathfinding/PathfinderProvider"; +import ILocationResolver from "../../query-runner/ILocationResolver"; +import IResolvedQuery from "../../query-runner/IResolvedQuery"; +import TYPES from "../../types"; +import Geo from "../../util/Geo"; +import { toTileCoordinate } from "../../util/Tiles"; +import Leg from "../Leg"; +import Path from "../Path"; +import IRoadPlanner from "./IRoadPlanner"; + +@injectable() +export default class RoadPlannerPathfinding implements IRoadPlanner { + private tileProvider: IRoutableTileProvider; + private pathfinderProvider: PathfinderProvider; + private profileProvider: IProfileProvider; + private locationResolver: ILocationResolver; + private registry: RoutableTileRegistry; + private eventBus: EventEmitter; + + private reachedTiles: Set; + + constructor( + @inject(TYPES.RoutableTileProvider) + @tagged("phase", RoutingPhase.Base) + tileProvider: IRoutableTileProvider, + @inject(TYPES.PathfinderProvider) pathfinderProvider: PathfinderProvider, + @inject(TYPES.ProfileProvider) profileProvider: IProfileProvider, + @inject(TYPES.LocationResolver) locationResolver: ILocationResolver, + @inject(TYPES.RoutableTileRegistry) registry: RoutableTileRegistry, + ) { + this.tileProvider = tileProvider; + this.pathfinderProvider = pathfinderProvider; + this.profileProvider = profileProvider; + this.locationResolver = locationResolver; + this.registry = registry; + this.eventBus = EventBus.getInstance(); + this.reachedTiles = new Set(); + } + + public async plan(query: IResolvedQuery): Promise> { + const { + from: fromLocations, + to: toLocations, + profileID, + } = query; + + const paths = []; + const profile = await this.profileProvider.getProfile(profileID); + + if (fromLocations && toLocations && fromLocations.length && toLocations.length) { + + for (const from of fromLocations) { + for (const to of toLocations) { + + const newPath = await this.getPathBetweenLocations( + from, + to, + profile, + ); + + if (newPath) { + paths.push(newPath); + } + } + } + } + + return new ArrayIterator(paths); + } + + private async getPathBetweenLocations( + from: ILocation, + to: ILocation, + profile: Profile, + ): Promise { + + await Promise.all([ + this.embedLocation(from), + this.embedLocation(to, true), + ]); + + return this._innerPath(from, to, profile); + } + + private async _innerPath( + start: ILocation, + stop: ILocation, + profile: Profile, + ): Promise { + const pathfinder = await this.pathfinderProvider.getShortestPathAlgorithm(profile); + const maxDistance = Geo.getDistanceBetweenLocations(start, stop) * 10 + 1000; + const path = await pathfinder.queryPath(Geo.getId(start), Geo.getId(stop), maxDistance); + + const steps: IStep[] = []; + for (const step of path) { + const to = await this.locationResolver.resolve(step.to); + const from = await this.locationResolver.resolve(step.from); + steps.push({ + startLocation: from, + stopLocation: to, + duration: { average: step.duration }, + distance: step.distance, + }); + } + + const leg = new Leg(TravelMode.Profile, steps); + return new Path([leg]); + } + + private async fetchTile(coordinate: RoutableTileCoordinate) { + const tileId = this.tileProvider.getIdForTileCoords(coordinate); + if (!this.reachedTiles.has(tileId)) { + this.eventBus.emit(EventType.FetchTile, coordinate); + const tile = await this.tileProvider.getByTileCoords(coordinate); + this.reachedTiles.add(tileId); + const boundaryNodes: Set = new Set(); + + for (const nodeId of tile.getNodes()) { + const node = this.registry.getNode(nodeId); + if (!tile.contains(node)) { + boundaryNodes.add(nodeId); + } + } + + const self = this; + for (const profile of await this.profileProvider.getProfiles()) { + const pathfinder = this.pathfinderProvider.getShortestPathAlgorithm(profile); + + for (const nodeId of boundaryNodes) { + pathfinder.setBreakPoint(nodeId, async (on: string) => { + const node = self.registry.getNode(on); + const boundaryTileCoordinate = toTileCoordinate(node.latitude, node.longitude); + await self.fetchTile(boundaryTileCoordinate); + }); + } + } + } + } + + private async embedLocation(from: ILocation, invert = false) { + const zoom = 14; + const padding = 0.005; + + const fromBBox = { + top: from.latitude + padding, + bottom: from.latitude - padding, + left: from.longitude - padding, + right: from.longitude + padding, + }; + + const fromTileCoords = inBBox.tilesInBbox(fromBBox, zoom).map((obj) => { + const coordinate = new RoutableTileCoordinate(zoom, obj.x, obj.y); + this.fetchTile(coordinate); + return coordinate; + }); + + // this won't download anything new + // but we need the tile data to embed the starting location + const fromTileset = await this.tileProvider.getMultipleByTileCoords(fromTileCoords); + await this.pathfinderProvider.embedLocation(from, fromTileset, invert); + } +} diff --git a/src/planner/road/RoadPlannerPathfindingExperimental.ts b/src/planner/road/RoadPlannerPathfindingExperimental.ts new file mode 100644 index 00000000..1b97627c --- /dev/null +++ b/src/planner/road/RoadPlannerPathfindingExperimental.ts @@ -0,0 +1,227 @@ +import { ArrayIterator, AsyncIterator } from "asynciterator"; +import { EventEmitter } from "events"; +import { inject, injectable, tagged } from "inversify"; +import inBBox from "tiles-in-bbox"; +import Profile from "../../entities/profile/Profile"; +import { RoutableTileCoordinate } from "../../entities/tiles/coordinate"; +import { RoutableTileNode } from "../../entities/tiles/node"; +import RoutableTileRegistry from "../../entities/tiles/registry"; +import { RoutableTile } from "../../entities/tiles/tile"; +import RoutingPhase from "../../enums/RoutingPhase"; +import TravelMode from "../../enums/TravelMode"; +import EventBus from "../../events/EventBus"; +import EventType from "../../events/EventType"; +import IProfileProvider from "../../fetcher/profiles/IProfileProvider"; +import IRoutableTileProvider from "../../fetcher/tiles/IRoutableTileProvider"; +import ILocation from "../../interfaces/ILocation"; +import IPath from "../../interfaces/IPath"; +import IStep from "../../interfaces/IStep"; +import PathfinderProvider from "../../pathfinding/PathfinderProvider"; +import ILocationResolver from "../../query-runner/ILocationResolver"; +import IResolvedQuery from "../../query-runner/IResolvedQuery"; +import TYPES from "../../types"; +import Geo from "../../util/Geo"; +import { toTileCoordinate } from "../../util/Tiles"; +import Leg from "../Leg"; +import Path from "../Path"; +import IRoadPlanner from "./IRoadPlanner"; + +@injectable() +export default class RoadPlannerPathfindingExperimental implements IRoadPlanner { + private baseTileProvider: IRoutableTileProvider; + private transitTileProvider: IRoutableTileProvider; + private pathfinderProvider: PathfinderProvider; + private profileProvider: IProfileProvider; + private locationResolver: ILocationResolver; + private registry: RoutableTileRegistry; + private eventBus: EventEmitter; + + // STATEFUL! + // will misbehave when processing several queries concurrently + private reachedTiles: Set; + private localTiles: RoutableTileCoordinate[]; + + constructor( + @inject(TYPES.RoutableTileProvider) + @tagged("phase", RoutingPhase.Base) + baseTileProvider: IRoutableTileProvider, + @inject(TYPES.RoutableTileProvider) + @tagged("phase", RoutingPhase.Transit) + transitTileProvider: IRoutableTileProvider, + @inject(TYPES.PathfinderProvider) pathfinderProvider: PathfinderProvider, + @inject(TYPES.ProfileProvider) profileProvider: IProfileProvider, + @inject(TYPES.LocationResolver) locationResolver: ILocationResolver, + @inject(TYPES.RoutableTileRegistry) registry: RoutableTileRegistry, + ) { + this.baseTileProvider = baseTileProvider; + this.transitTileProvider = transitTileProvider; + this.pathfinderProvider = pathfinderProvider; + this.profileProvider = profileProvider; + this.locationResolver = locationResolver; + this.registry = registry; + this.eventBus = EventBus.getInstance(); + this.reachedTiles = new Set(); + } + + public async plan(query: IResolvedQuery): Promise> { + const { + from: fromLocations, + to: toLocations, + profileID, + } = query; + + const paths = []; + const profile = await this.profileProvider.getProfile(profileID); + + if (fromLocations && toLocations && fromLocations.length && toLocations.length) { + + for (const from of fromLocations) { + for (const to of toLocations) { + + const newPath = await this.getPathBetweenLocations( + from, + to, + profile, + ); + + if (newPath) { + paths.push(newPath); + } + } + } + } + + return new ArrayIterator(paths); + } + + private async getPathBetweenLocations( + from: ILocation, + to: ILocation, + profile: Profile, + ): Promise { + this.localTiles = [ + toTileCoordinate(from.latitude, from.longitude), + toTileCoordinate(to.latitude, to.longitude), + ]; + + await Promise.all([ + this.embedLocation(from), + this.embedLocation(to, true), + ]); + + return this._innerPath(from, to, profile); + } + + private async _innerPath( + start: ILocation, + stop: ILocation, + profile: Profile, + ): Promise { + const pathfinder = await this.pathfinderProvider.getShortestPathAlgorithm(profile); + const maxDistance = Geo.getDistanceBetweenLocations(start, stop) * 5; + const path = await pathfinder.queryPath(Geo.getId(start), Geo.getId(stop), maxDistance); + + const steps: IStep[] = []; + for (const step of path) { + const to = await this.locationResolver.resolve(step.to); + const from = await this.locationResolver.resolve(step.from); + steps.push({ + startLocation: from, + stopLocation: to, + duration: { average: step.duration }, + distance: step.distance, + }); + } + + const leg = new Leg(TravelMode.Profile, steps); + return new Path([leg]); + } + + private pickTile(node: RoutableTileNode) { + let coordinate: RoutableTileCoordinate; + for (let zoom = 8; zoom < 15; zoom++) { + coordinate = toTileCoordinate(node.latitude, node.longitude, zoom); + let ok = true; + for (const localTile of this.localTiles) { + if (coordinate.contains(localTile)) { + ok = false; + break; + } + } + if (ok) { + return coordinate; + } + } + return coordinate; + } + + private async fetchTile(coordinate: RoutableTileCoordinate) { + let local = false; + for (const localTile of this.localTiles) { + if (coordinate.x === localTile.x && coordinate.y === localTile.y && coordinate.zoom === localTile.zoom) { + local = true; + break; + } + } + + const baseTileId = this.baseTileProvider.getIdForTileCoords(coordinate); + const transitTileId = this.transitTileProvider.getIdForTileCoords(coordinate); + + if (!this.reachedTiles.has(transitTileId) && !this.reachedTiles.has(baseTileId)) { + this.eventBus.emit(EventType.FetchTile, coordinate); + let tile: RoutableTile; + if (local) { + tile = await this.baseTileProvider.getByTileCoords(coordinate); + this.reachedTiles.add(baseTileId); + this.reachedTiles.add(transitTileId); + } else { + tile = await this.transitTileProvider.getByTileCoords(coordinate); + this.reachedTiles.add(transitTileId); + } + const boundaryNodes: Set = new Set(); + + for (const nodeId of tile.getNodes()) { + const node = this.registry.getNode(nodeId); + if (!tile.contains(node)) { + boundaryNodes.add(nodeId); + } + } + + const self = this; + for (const profile of await this.profileProvider.getProfiles()) { + const graph = this.pathfinderProvider.getGraphForProfile(profile); + + for (const nodeId of boundaryNodes) { + graph.setBreakPoint(nodeId, async (on: string) => { + const node = self.registry.getNode(on); + const boundaryTileCoordinate = this.pickTile(node); + await self.fetchTile(boundaryTileCoordinate); + }); + } + } + } + } + + private async embedLocation(from: ILocation, invert = false) { + const zoom = 14; + const padding = 0.005; + + const fromBBox = { + top: from.latitude + padding, + bottom: from.latitude - padding, + left: from.longitude - padding, + right: from.longitude + padding, + }; + + const fromTileCoords = inBBox.tilesInBbox(fromBBox, zoom).map((obj) => { + const coordinate = new RoutableTileCoordinate(zoom, obj.x, obj.y); + this.fetchTile(coordinate); + return coordinate; + }); + + // this won't download anything new + // but we need the tile data to embed the starting location + const fromTileset = await this.baseTileProvider.getMultipleByTileCoords(fromTileCoords); + await this.pathfinderProvider.embedLocation(from, fromTileset, invert); + } +} diff --git a/src/planner/stops/IReachableStopsFinder.ts b/src/planner/stops/IReachableStopsFinder.ts index 99ed8105..7b906e09 100644 --- a/src/planner/stops/IReachableStopsFinder.ts +++ b/src/planner/stops/IReachableStopsFinder.ts @@ -1,5 +1,6 @@ import ReachableStopsFinderMode from "../../enums/ReachableStopsFinderMode"; import IStop from "../../fetcher/stops/IStop"; +import ILocation from "../../interfaces/ILocation"; import { DurationMs, SpeedKmH } from "../../interfaces/units"; /** @@ -8,10 +9,11 @@ import { DurationMs, SpeedKmH } from "../../interfaces/units"; */ export default interface IReachableStopsFinder { findReachableStops: ( - sourceOrTargetStop: IStop, + sourceOrTargetStop: ILocation, mode: ReachableStopsFinderMode, maximumDuration: DurationMs, minimumSpeed: SpeedKmH, + profileID: string, ) => Promise; } @@ -21,4 +23,5 @@ export default interface IReachableStopsFinder { export interface IReachableStop { stop: IStop; duration: DurationMs; + id?: string; } diff --git a/src/planner/stops/ReachableStopsFinderDelaunay.ts b/src/planner/stops/ReachableStopsFinderDelaunay.ts new file mode 100644 index 00000000..fa054307 --- /dev/null +++ b/src/planner/stops/ReachableStopsFinderDelaunay.ts @@ -0,0 +1,111 @@ +import { AsyncIterator } from "asynciterator"; +import { Delaunay } from "d3-delaunay"; +import { inject, injectable } from "inversify"; +import ReachableStopsFinderMode from "../../enums/ReachableStopsFinderMode"; +import IStop from "../../fetcher/stops/IStop"; +import IStopsProvider from "../../fetcher/stops/IStopsProvider"; +import ILocation from "../../interfaces/ILocation"; +import IPath from "../../interfaces/IPath"; +import { DurationMs, SpeedKmH } from "../../interfaces/units"; +import IResolvedQuery from "../../query-runner/IResolvedQuery"; +import TYPES from "../../types"; +import Iterators from "../../util/Iterators"; +import IRoadPlanner from "../road/IRoadPlanner"; +import IReachableStopsFinder, { IReachableStop } from "./IReachableStopsFinder"; + +@injectable() +export default class ReachableStopsFinderDelaunay implements IReachableStopsFinder { + private readonly stopsProvider: IStopsProvider; + private readonly roadPlanner: IRoadPlanner; + private triangles: Delaunay; + private trianglePoints: IStop[]; + + constructor( + @inject(TYPES.StopsProvider) stopsProvider: IStopsProvider, + @inject(TYPES.RoadPlanner) roadPlanner: IRoadPlanner, + ) { + this.stopsProvider = stopsProvider; + this.roadPlanner = roadPlanner; + this.prepare(); + } + + public async findReachableStops( + location: ILocation, + mode: ReachableStopsFinderMode, + maximumDuration: DurationMs, + minimumSpeed: SpeedKmH, + profileID: string, + ): Promise { + + const minimumDepartureTime = new Date(); + const maximumArrivalTime = new Date(minimumDepartureTime.getTime() + maximumDuration); + + const baseProp = mode === ReachableStopsFinderMode.Target ? "to" : "from"; + const otherProp = mode === ReachableStopsFinderMode.Target ? "from" : "to"; + + const baseQuery: IResolvedQuery = { + [baseProp]: [location], + minimumDepartureTime, + maximumArrivalTime, + minimumWalkingSpeed: minimumSpeed, + profileID, + }; + + const stopsNearCell: IStop[] = await this.getNearbyStops(location); + const reachableStops: IReachableStop[] = []; + + await Promise.all(stopsNearCell.map(async (possibleTarget: IStop) => { + const query = Object.assign({}, baseQuery, { + [otherProp]: [possibleTarget as ILocation], + }); + + const pathIterator = await this.roadPlanner.plan(query); + + const durationIterator: AsyncIterator = pathIterator.map((path: IPath) => + path.legs.reduce((totalDuration: DurationMs, step) => totalDuration + step.getAverageDuration(), 0), + ); + + const durations = await Iterators.toArray(durationIterator); + if (durations.length) { + const shortestDuration = Math.min(...durations); + reachableStops.push({ stop: possibleTarget, duration: shortestDuration }); + } + })); + + return reachableStops; + } + + private async getNearbyStops(location: ILocation): Promise { + const triangles = await this.triangles; + const cell = triangles.find(location.longitude, location.latitude); + + const result = [this.trianglePoints[cell]]; + + // not including these for now + // may result in large route network queries if the stops network is sparse + /* + const neighbors = triangles.neighbors(cell); + for (const neighbor of neighbors) { + result.push(this.trianglePoints[neighbor]); + } + */ + + return result; + } + + private async prepare() { + this.triangles = this.stopsProvider.getAllStops().then((stops) => { + this.trianglePoints = stops; + + function getX(p: ILocation) { + return p.longitude; + } + + function getY(p: ILocation) { + return p.latitude; + } + + return Delaunay.from(stops, getX, getY); + }); + } +} diff --git a/src/planner/stops/ReachableStopsFinderFootpaths.ts b/src/planner/stops/ReachableStopsFinderFootpaths.ts new file mode 100644 index 00000000..700635cf --- /dev/null +++ b/src/planner/stops/ReachableStopsFinderFootpaths.ts @@ -0,0 +1,51 @@ +import { inject, injectable } from "inversify"; +import ReachableStopsFinderMode from "../../enums/ReachableStopsFinderMode"; +import IFootpathsProvider from "../../fetcher/footpaths/IFootpathsProvider"; +import IStop from "../../fetcher/stops/IStop"; +import IStopsProvider from "../../fetcher/stops/IStopsProvider"; +import { DurationMs, SpeedKmH } from "../../interfaces/units"; +import TYPES from "../../types"; +import Units from "../../util/Units"; +import IReachableStopsFinder, { IReachableStop } from "./IReachableStopsFinder"; + +@injectable() +export default class ReachableStopsFinderFootpaths implements IReachableStopsFinder { + private readonly stopsProvider: IStopsProvider; + private readonly footpathsProvider: IFootpathsProvider; + + constructor( + @inject(TYPES.StopsProvider) stopsProvider: IStopsProvider, + @inject(TYPES.FootpathsProvider) footpathsProvider: IFootpathsProvider, + ) { + this.stopsProvider = stopsProvider; + this.footpathsProvider = footpathsProvider; + } + + public async findReachableStops( + sourceOrTargetStop: IStop, + mode: ReachableStopsFinderMode, + maximumDuration: DurationMs, + minimumSpeed: SpeedKmH, + ): Promise { + + const reachableStops: IReachableStop[] = [{ stop: sourceOrTargetStop, duration: 0 }]; + + const footpaths = await this.footpathsProvider.get(sourceOrTargetStop); + for (const footpath of Object.values(footpaths)) { + let otherStop: IStop; + + if (sourceOrTargetStop.id === footpath.from) { + otherStop = await this.stopsProvider.getStopById(footpath.to); + } else if (sourceOrTargetStop.id === footpath.to) { + otherStop = await this.stopsProvider.getStopById(footpath.from); + } + + if (otherStop) { + const duration = Units.toDuration(footpath.distance, minimumSpeed); + reachableStops.push({stop: otherStop, duration, id: footpath.id}); + } + } + + return reachableStops; + } +} diff --git a/src/planner/stops/ReachableStopsFinderFootpathsVerbose.ts b/src/planner/stops/ReachableStopsFinderFootpathsVerbose.ts new file mode 100644 index 00000000..c8c23faf --- /dev/null +++ b/src/planner/stops/ReachableStopsFinderFootpathsVerbose.ts @@ -0,0 +1,42 @@ +import { inject, injectable } from "inversify"; +import ReachableStopsFinderMode from "../../enums/ReachableStopsFinderMode"; +import EventBus from "../../events/EventBus"; +import EventType from "../../events/EventType"; +import IFootpathsProvider from "../../fetcher/footpaths/IFootpathsProvider"; +import IStop from "../../fetcher/stops/IStop"; +import IStopsProvider from "../../fetcher/stops/IStopsProvider"; +import { DurationMs, SpeedKmH } from "../../interfaces/units"; +import TYPES from "../../types"; +import { IReachableStop } from "./IReachableStopsFinder"; +import ReachableStopsFinderFootpaths from "./ReachableStopsFinderFootpaths"; + +@injectable() +export default class ReachableStopsFinderFootpathsVerbose extends ReachableStopsFinderFootpaths { + private done: Set; + + constructor( + @inject(TYPES.StopsProvider) stopsProvider: IStopsProvider, + @inject(TYPES.FootpathsProvider) footpathsProvider: IFootpathsProvider, + ) { + super(stopsProvider, footpathsProvider); + this.done = new Set(); + } + + public async findReachableStops( + sourceOrTargetStop: IStop, + mode: ReachableStopsFinderMode, + maximumDuration: DurationMs, + minimumSpeed: SpeedKmH, + ): Promise { + const result = await super.findReachableStops(sourceOrTargetStop, mode, maximumDuration, minimumSpeed); + + if (!this.done.has(sourceOrTargetStop.id)) { + this.done.add(sourceOrTargetStop.id); + for (const reachableStop of result) { + EventBus.getInstance().emit(EventType.ReachableStop, sourceOrTargetStop, reachableStop.stop); + } + } + + return result; + } +} diff --git a/src/planner/stops/ReachableStopsFinderRoadPlanner.test.ts b/src/planner/stops/ReachableStopsFinderRoadPlanner.test.ts index 5d83f7b2..5dc1340d 100644 --- a/src/planner/stops/ReachableStopsFinderRoadPlanner.test.ts +++ b/src/planner/stops/ReachableStopsFinderRoadPlanner.test.ts @@ -26,6 +26,7 @@ test("[ReachableStopsFinderRoadPlanner] reachable stops", async () => { ReachableStopsFinderMode.Source, Units.fromHours(1), 5, + "https://hdelva.be/profile/pedestrian", ); expect(reachableStops.length).toBeGreaterThan(1); diff --git a/src/planner/stops/ReachableStopsFinderRoadPlanner.ts b/src/planner/stops/ReachableStopsFinderRoadPlanner.ts index 132171ce..d2e536a0 100644 --- a/src/planner/stops/ReachableStopsFinderRoadPlanner.ts +++ b/src/planner/stops/ReachableStopsFinderRoadPlanner.ts @@ -33,10 +33,11 @@ export default class ReachableStopsFinderRoadPlanner implements IReachableStopsF } public async findReachableStops( - sourceOrTargetStop: IStop, + location: ILocation, mode: ReachableStopsFinderMode, maximumDuration: DurationMs, minimumSpeed: SpeedKmH, + profileID: string, ): Promise { const minimumDepartureTime = new Date(); @@ -46,17 +47,18 @@ export default class ReachableStopsFinderRoadPlanner implements IReachableStopsF const otherProp = mode === ReachableStopsFinderMode.Target ? "from" : "to"; const baseQuery: IResolvedQuery = { - [baseProp]: [sourceOrTargetStop as ILocation], + [baseProp]: [location], minimumDepartureTime, maximumArrivalTime, minimumWalkingSpeed: minimumSpeed, + profileID, }; const allStops: IStop[] = await this.stopsProvider.getAllStops(); const stopsInsideCircleArea: IStop[] = []; for (const stop of allStops) { - const distance = Geo.getDistanceBetweenStops(sourceOrTargetStop, stop); + const distance = Geo.getDistanceBetweenLocations(location, stop); const duration = Units.toDuration(distance, minimumSpeed); if (duration >= 0 && duration <= maximumDuration) { @@ -64,30 +66,27 @@ export default class ReachableStopsFinderRoadPlanner implements IReachableStopsF } } - const reachableStops: IReachableStop[] = [{stop: sourceOrTargetStop, duration: 0}]; + const reachableStops: IReachableStop[] = []; await Promise.all(stopsInsideCircleArea.map(async (possibleTarget: IStop) => { - if (possibleTarget.id !== sourceOrTargetStop.id) { - - const query = Object.assign({}, baseQuery, { - [otherProp]: [possibleTarget as ILocation], - }); - - const pathIterator = await this.roadPlanner.plan(query); - - const durationIterator: AsyncIterator = pathIterator.map((path: IPath) => - // Minimum speed is passed so sum max duration over all steps - path.steps.reduce((totalDuration: DurationMs, step) => totalDuration + step.duration.maximum, 0), - ); - - const sufficientlyShortDuration = await Iterators - .find(durationIterator, (duration: DurationMs) => duration < maximumDuration); - - if (sufficientlyShortDuration) { - reachableStops.push({stop: possibleTarget, duration: sufficientlyShortDuration}); + const query = Object.assign({}, baseQuery, { + [otherProp]: [possibleTarget as ILocation], + }); + + const pathIterator = await this.roadPlanner.plan(query); + + const durationIterator: AsyncIterator = pathIterator.map((path: IPath) => + // Minimum speed is passed so sum max duration over all steps + path.legs.reduce((totalDuration: DurationMs, leg) => totalDuration + leg.getMaximumDuration(), 0), + ); + + const durations = await Iterators.toArray(durationIterator); + if (durations.length) { + const shortestDuration = Math.min(...durations); + if (shortestDuration < maximumDuration) { + reachableStops.push({ stop: possibleTarget, duration: shortestDuration }); } } - })); return reachableStops; diff --git a/src/planner/stops/ReachableStopsFinderRoadPlannerCached.ts b/src/planner/stops/ReachableStopsFinderRoadPlannerCached.ts index f373f29a..ca2fd73c 100644 --- a/src/planner/stops/ReachableStopsFinderRoadPlannerCached.ts +++ b/src/planner/stops/ReachableStopsFinderRoadPlannerCached.ts @@ -2,8 +2,10 @@ import { inject, injectable } from "inversify"; import ReachableStopsFinderMode from "../../enums/ReachableStopsFinderMode"; import IStop from "../../fetcher/stops/IStop"; import IStopsProvider from "../../fetcher/stops/IStopsProvider"; +import ILocation from "../../interfaces/ILocation"; import { DurationMs, SpeedKmH } from "../../interfaces/units"; import TYPES from "../../types"; +import Geo from "../../util/Geo"; import IRoadPlanner from "../road/IRoadPlanner"; import IReachableStopsFinder, { IReachableStop } from "./IReachableStopsFinder"; import ReachableStopsFinderRoadPlanner from "./ReachableStopsFinderRoadPlanner"; @@ -26,13 +28,15 @@ export default class ReachableStopsFinderRoadPlannerCached implements IReachable } public async findReachableStops( - sourceOrTargetStop: IStop, + location: ILocation, mode: ReachableStopsFinderMode, maximumDuration: DurationMs, minimumSpeed: SpeedKmH, + profileID: string, ): Promise { - const cacheKey = `${sourceOrTargetStop.id} ${mode} ${maximumDuration} ${minimumSpeed}`; + const id = location.id || Geo.getId(location); + const cacheKey = `${id} ${mode} ${maximumDuration} ${minimumSpeed}`; const cacheItem = this.reachableStopsCache[cacheKey]; if (cacheItem) { @@ -40,7 +44,7 @@ export default class ReachableStopsFinderRoadPlannerCached implements IReachable } const reachableStops = await this.reachableStopsFinder - .findReachableStops(sourceOrTargetStop, mode, maximumDuration, minimumSpeed); + .findReachableStops(location, mode, maximumDuration, minimumSpeed, profileID); this.reachableStopsCache[cacheKey] = reachableStops; return reachableStops; diff --git a/src/query-runner/IResolvedQuery.ts b/src/query-runner/IResolvedQuery.ts index f8f625dd..a9fc0d94 100644 --- a/src/query-runner/IResolvedQuery.ts +++ b/src/query-runner/IResolvedQuery.ts @@ -9,10 +9,11 @@ import { DurationMs, SpeedKmH } from "../interfaces/units"; export default interface IResolvedQuery { from?: ILocation[]; to?: ILocation[]; + profileID: string; minimumDepartureTime?: Date; maximumArrivalTime?: Date; roadOnly?: boolean; - publicTransportOnly?: boolean; + roadNetworkOnly?: boolean; minimumWalkingSpeed?: SpeedKmH; maximumWalkingSpeed?: SpeedKmH; maximumWalkingDuration?: DurationMs; diff --git a/src/query-runner/LocationResolverConvenience.test.ts b/src/query-runner/LocationResolverConvenience.test.ts index 3da63c76..041d9f41 100644 --- a/src/query-runner/LocationResolverConvenience.test.ts +++ b/src/query-runner/LocationResolverConvenience.test.ts @@ -1,14 +1,16 @@ import "jest"; import LDFetch from "ldfetch"; +import RoutableTileRegistry from "../entities/tiles/registry"; import StopsFetcherLDFetch from "../fetcher/stops/ld-fetch/StopsFetcherLDFetch"; import LocationResolverConvenience from "./LocationResolverConvenience"; const ldFetch = new LDFetch({ headers: { Accept: "application/ld+json" } }); const stopsFetcher = new StopsFetcherLDFetch(ldFetch); +const tileRegistry = new RoutableTileRegistry(); stopsFetcher.setAccessUrl("https://irail.be/stations/NMBS"); -const locationResolver = new LocationResolverConvenience(stopsFetcher); +const locationResolver = new LocationResolverConvenience(stopsFetcher, tileRegistry); describe("[LocationResolverConvenience]", () => { diff --git a/src/query-runner/LocationResolverConvenience.ts b/src/query-runner/LocationResolverConvenience.ts index 992bc859..556619f4 100644 --- a/src/query-runner/LocationResolverConvenience.ts +++ b/src/query-runner/LocationResolverConvenience.ts @@ -1,4 +1,5 @@ import { inject, injectable } from "inversify"; +import RoutableTileRegistry from "../entities/tiles/registry"; import LocationResolverError from "../errors/LocationResolverError"; import IStop from "../fetcher/stops/IStop"; import IStopsProvider from "../fetcher/stops/IStopsProvider"; @@ -20,15 +21,27 @@ export default class LocationResolverConvenience implements ILocationResolver { constructor( @inject(TYPES.StopsProvider) stopsProvider: IStopsProvider, + @inject(TYPES.RoutableTileRegistry) tileRegistry: RoutableTileRegistry, ) { this.stopsProvider = stopsProvider; - this.defaultLocationResolver = new LocationResolverDefault(this.stopsProvider); + this.defaultLocationResolver = new LocationResolverDefault(this.stopsProvider, tileRegistry); } public async resolve(input: ILocation | IStop | string): Promise { - if (typeof input === "string" && !this.isId(input)) { + if (input.includes("geo:")) { + const expression = /geo:([\-0-9.]+),([\-0-9.]+)/; + const result = expression.exec(input); + + if (result && result.length) { + return { + latitude: parseFloat(result[1]), + longitude: parseFloat(result[2]), + }; + } + } + if (!this.allStops) { this.allStops = await this.stopsProvider.getAllStops(); } diff --git a/src/query-runner/LocationResolverDefault.test.ts b/src/query-runner/LocationResolverDefault.test.ts index 1ec1a03d..bf7dd9a6 100644 --- a/src/query-runner/LocationResolverDefault.test.ts +++ b/src/query-runner/LocationResolverDefault.test.ts @@ -1,5 +1,6 @@ import "jest"; import LDFetch from "ldfetch"; +import RoutableTileRegistry from "../entities/tiles/registry"; import StopsFetcherLDFetch from "../fetcher/stops/ld-fetch/StopsFetcherLDFetch"; import LocationResolverDefault from "./LocationResolverDefault"; @@ -8,7 +9,7 @@ const ldFetch = new LDFetch({ headers: { Accept: "application/ld+json" } }); const stopsFetcher = new StopsFetcherLDFetch(ldFetch); stopsFetcher.setAccessUrl("https://irail.be/stations/NMBS"); -const locationResolver = new LocationResolverDefault(stopsFetcher); +const locationResolver = new LocationResolverDefault(stopsFetcher, new RoutableTileRegistry()); test("[LocationResolverDefault] Input {id: 'http://...'}", async () => { diff --git a/src/query-runner/LocationResolverDefault.ts b/src/query-runner/LocationResolverDefault.ts index 88513161..52d75145 100644 --- a/src/query-runner/LocationResolverDefault.ts +++ b/src/query-runner/LocationResolverDefault.ts @@ -1,4 +1,5 @@ import { inject, injectable } from "inversify"; +import RoutableTileRegistry from "../entities/tiles/registry"; import LocationResolverError from "../errors/LocationResolverError"; import IStop from "../fetcher/stops/IStop"; import IStopsProvider from "../fetcher/stops/IStopsProvider"; @@ -16,11 +17,14 @@ import ILocationResolver from "./ILocationResolver"; @injectable() export default class LocationResolverDefault implements ILocationResolver { private readonly stopsProvider: IStopsProvider; + private readonly tileRegistry: RoutableTileRegistry; constructor( @inject(TYPES.StopsProvider) stopsProvider: IStopsProvider, + @inject(TYPES.RoutableTileRegistry) tileRegistry: RoutableTileRegistry, ) { this.stopsProvider = stopsProvider; + this.tileRegistry = tileRegistry; } public async resolve(input: ILocation | IStop | string): Promise { @@ -54,15 +58,14 @@ export default class LocationResolverDefault implements ILocationResolver { } private async resolveById(id: string): Promise { - const stop: IStop = await this.stopsProvider.getStopById(id); + const node = this.tileRegistry.getNode(id); + if (node) { + return node; + } + const stop: IStop = await this.stopsProvider.getStopById(id); if (stop) { - return { - id, - name: stop.name, - latitude: stop.latitude, - longitude: stop.longitude, - }; + return stop; } return Promise.reject(new LocationResolverError(`No fetcher for id ${id}`)); diff --git a/src/query-runner/QueryRunnerDefault.ts b/src/query-runner/QueryRunnerDefault.ts index 829e47da..b666dcd2 100644 --- a/src/query-runner/QueryRunnerDefault.ts +++ b/src/query-runner/QueryRunnerDefault.ts @@ -7,6 +7,7 @@ import ILocation from "../interfaces/ILocation"; import IPath from "../interfaces/IPath"; import IQuery from "../interfaces/IQuery"; import IPublicTransportPlanner from "../planner/public-transport/IPublicTransportPlanner"; +import IRoadPlanner from "../planner/road/IRoadPlanner"; import TYPES from "../types"; import Units from "../util/Units"; import ILocationResolver from "./ILocationResolver"; @@ -14,37 +15,35 @@ import IQueryRunner from "./IQueryRunner"; import IResolvedQuery from "./IResolvedQuery"; /** - * This default query runner only accepts public transport queries (`publicTransportOnly = true`). - * It uses the registered [[IPublicTransportPlanner]] to execute them. - * * The default `minimumDepartureTime` is *now*. The default `maximumArrivalTime` is `minimumDepartureTime + 2 hours`. */ @injectable() export default class QueryRunnerDefault implements IQueryRunner { private locationResolver: ILocationResolver; private publicTransportPlanner: IPublicTransportPlanner; + private roadPlanner: IRoadPlanner; constructor( @inject(TYPES.LocationResolver) locationResolver: ILocationResolver, @inject(TYPES.PublicTransportPlanner) publicTransportPlanner: IPublicTransportPlanner, + @inject(TYPES.RoadPlanner) roadPlanner: IRoadPlanner, ) { this.locationResolver = locationResolver; this.publicTransportPlanner = publicTransportPlanner; + this.roadPlanner = roadPlanner; } public async run(query: IQuery): Promise> { const resolvedQuery: IResolvedQuery = await this.resolveQuery(query); - if (resolvedQuery.publicTransportOnly) { - return this.publicTransportPlanner.plan(resolvedQuery); - + if (resolvedQuery.roadNetworkOnly) { + return this.roadPlanner.plan(resolvedQuery); } else { - throw new InvalidQueryError("Query should have publicTransportOnly = true"); + return this.publicTransportPlanner.plan(resolvedQuery); } } private async resolveEndpoint(endpoint: string | string[] | ILocation | ILocation[]): Promise { - if (Array.isArray(endpoint)) { const promises = (endpoint as Array) .map((singleEndpoint: string | ILocation) => @@ -52,7 +51,6 @@ export default class QueryRunnerDefault implements IQueryRunner { ); return await Promise.all(promises); - } else { return [await this.locationResolver.resolve(endpoint)]; } @@ -71,7 +69,7 @@ export default class QueryRunnerDefault implements IQueryRunner { } = query; // tslint:enable:trailing-comma - const resolvedQuery: IResolvedQuery = Object.assign({}, other); + const resolvedQuery: IResolvedQuery = Object.assign({}, other as IResolvedQuery); resolvedQuery.minimumDepartureTime = minimumDepartureTime || new Date(); @@ -79,10 +77,9 @@ export default class QueryRunnerDefault implements IQueryRunner { resolvedQuery.maximumArrivalTime = maximumArrivalTime; } else { - const newMaximumArrivalTime = new Date(resolvedQuery.minimumDepartureTime); - newMaximumArrivalTime.setHours(newMaximumArrivalTime.getHours() + 2); - - resolvedQuery.maximumArrivalTime = newMaximumArrivalTime; + const { minimumDepartureTime: newDepartureTime } = resolvedQuery; + resolvedQuery.maximumArrivalTime = new Date(newDepartureTime.getTime() + + 12 * 60 * 60 * 1000); } try { diff --git a/src/query-runner/earliest-arrival-first/LinearQueryIterator.ts b/src/query-runner/earliest-arrival-first/LinearQueryIterator.ts deleted file mode 100644 index dddad2d8..00000000 --- a/src/query-runner/earliest-arrival-first/LinearQueryIterator.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { AsyncIterator } from "asynciterator"; -import { DurationMs } from "../../interfaces/units"; -import IResolvedQuery from "../IResolvedQuery"; - -/** - * This AsyncIterator emits [[IResolvedQuery]] instances with linear increasing `maximumArrivalTime`. - */ -export default class LinearQueryIterator extends AsyncIterator { - private readonly baseQuery: IResolvedQuery; - private timespan: DurationMs; - private index: number; - private readonly a: DurationMs; - private readonly b: DurationMs; - - constructor(baseQuery: IResolvedQuery, a: DurationMs, b: DurationMs) { - super(); - - this.baseQuery = baseQuery; - this.index = 1; - this.a = a; - this.b = b; - - this.timespan = a * this.index + b; - - this.readable = true; - } - - public read(): IResolvedQuery { - if (this.closed) { - return null; - } - - const {minimumDepartureTime} = this.baseQuery; - const maximumArrivalTime = new Date(minimumDepartureTime.getTime() + this.timespan); - - this.index++; - this.timespan = this.a * this.index + this.b; - - return Object.assign({}, this.baseQuery, {maximumArrivalTime}); - } - -} diff --git a/src/query-runner/earliest-arrival-first/QueryRunnerEarliestArrivalFirst.test.ts b/src/query-runner/earliest-arrival-first/QueryRunnerEarliestArrivalFirst.test.ts deleted file mode 100644 index d6fe132b..00000000 --- a/src/query-runner/earliest-arrival-first/QueryRunnerEarliestArrivalFirst.test.ts +++ /dev/null @@ -1,111 +0,0 @@ -import "jest"; -import LDFetch from "ldfetch"; -import Context from "../../Context"; -import TravelMode from "../../enums/TravelMode"; -import ConnectionsFetcherLazy from "../../fetcher/connections/lazy/ConnectionsFetcherLazy"; -import StopsFetcherLDFetch from "../../fetcher/stops/ld-fetch/StopsFetcherLDFetch"; -import IPath from "../../interfaces/IPath"; -import IStep from "../../interfaces/IStep"; -import CSAProfile from "../../planner/public-transport/CSAProfile"; -import JourneyExtractorProfile from "../../planner/public-transport/JourneyExtractorProfile"; -import ReachableStopsFinderBirdsEyeCached from "../../planner/stops/ReachableStopsFinderBirdsEyeCached"; -import Units from "../../util/Units"; -import LocationResolverDefault from "../LocationResolverDefault"; -import QueryRunnerEarliestArrivalFirst from "./QueryRunnerEarliestArrivalFirst"; -describe("[QueryRunnerExponential]", () => { - jest.setTimeout(100000); - - let publicTransportResult; - - const query = { - publicTransportOnly: true, - from: "http://irail.be/stations/NMBS/008896925", // Ingelmunster - to: "http://irail.be/stations/NMBS/008892007", // Ghent-Sint-Pieters - minimumDepartureTime: new Date(), - maximumTransferDuration: Units.fromHours(30), - }; - - const createEarliestArrivalQueryRunner = () => { - const ldFetch = new LDFetch({ headers: { Accept: "application/ld+json" } }); - - const connectionFetcher = new ConnectionsFetcherLazy(ldFetch); - connectionFetcher.setTravelMode(TravelMode.Train); - connectionFetcher.setAccessUrl("https://graph.irail.be/sncb/connections"); - - const stopsFetcher = new StopsFetcherLDFetch(ldFetch); - stopsFetcher.setAccessUrl("https://irail.be/stations/NMBS"); - - const locationResolver = new LocationResolverDefault(stopsFetcher); - const reachableStopsFinder = new ReachableStopsFinderBirdsEyeCached(stopsFetcher); - - const context = new Context(); - - const createJourneyExtractor = () => { - return new JourneyExtractorProfile( - locationResolver, - ); - }; - - const createPlanner = () => { - return new CSAProfile( - connectionFetcher, - locationResolver, - reachableStopsFinder, - reachableStopsFinder, - reachableStopsFinder, - createJourneyExtractor(), - ); - }; - - return new QueryRunnerEarliestArrivalFirst( - context, - connectionFetcher, - locationResolver, - createPlanner, - reachableStopsFinder, - reachableStopsFinder, - reachableStopsFinder, - ); - }; - - const result: IPath[] = []; - - beforeAll(async (done) => { - - const queryRunner = createEarliestArrivalQueryRunner(); - - publicTransportResult = await queryRunner.run(query); - - await publicTransportResult.take(3) - .on("data", (path: IPath) => { - result.push(path); - }) - .on("end", () => { - done(); - }); - }); - - it("Correct departure and arrival stop", () => { - checkStops(result, query); - }); -}); - -const checkStops = (result, query) => { - expect(result).toBeDefined(); - expect(result.length).toBeGreaterThanOrEqual(1); - - for (const path of result) { - expect(path.steps).toBeDefined(); - - expect(path.steps.length).toBeGreaterThanOrEqual(1); - - let currentLocation = query.from; - path.steps.forEach((step: IStep) => { - expect(step).toBeDefined(); - expect(currentLocation).toEqual(step.startLocation.id); - currentLocation = step.stopLocation.id; - }); - - expect(query.to).toEqual(currentLocation); - } -}; diff --git a/src/query-runner/earliest-arrival-first/QueryRunnerEarliestArrivalFirst.ts b/src/query-runner/earliest-arrival-first/QueryRunnerEarliestArrivalFirst.ts deleted file mode 100644 index fe4a8774..00000000 --- a/src/query-runner/earliest-arrival-first/QueryRunnerEarliestArrivalFirst.ts +++ /dev/null @@ -1,213 +0,0 @@ -import { AsyncIterator } from "asynciterator"; -import { PromiseProxyIterator } from "asynciterator-promiseproxy"; -import { inject, injectable, interfaces, tagged } from "inversify"; -import Context from "../../Context"; -import Defaults from "../../Defaults"; -import EventType from "../../enums/EventType"; -import ReachableStopsSearchPhase from "../../enums/ReachableStopsSearchPhase"; -import InvalidQueryError from "../../errors/InvalidQueryError"; -import IConnectionsProvider from "../../fetcher/connections/IConnectionsProvider"; -import ILocation from "../../interfaces/ILocation"; -import IPath from "../../interfaces/IPath"; -import IQuery from "../../interfaces/IQuery"; -import { DurationMs } from "../../interfaces/units"; -import Path from "../../planner/Path"; -import CSAEarliestArrival from "../../planner/public-transport/CSAEarliestArrival"; -import IPublicTransportPlanner from "../../planner/public-transport/IPublicTransportPlanner"; -import JourneyExtractorEarliestArrival from "../../planner/public-transport/JourneyExtractorEarliestArrival"; -import IReachableStopsFinder from "../../planner/stops/IReachableStopsFinder"; -import TYPES from "../../types"; -import FilterUniqueIterator from "../../util/iterators/FilterUniqueIterator"; -import FlatMapIterator from "../../util/iterators/FlatMapIterator"; -import Units from "../../util/Units"; -import ILocationResolver from "../ILocationResolver"; -import IQueryRunner from "../IQueryRunner"; -import IResolvedQuery from "../IResolvedQuery"; -import LinearQueryIterator from "./LinearQueryIterator"; - -/** - * The query runner earliest arrival first only accepts public transport queries (`publicTransportOnly = true`). - * - * An earliest Arrival first connection scan is started to determine the maximumTravelDuration and the scanned period - * needed to get at least one result. - * - * The registered [[IPublicTransportPlanner]] is used to execute the sub queries. - * The maximumTravelDuration is set to the earliest arrival travel duration multiplied by 2. - * The scanned period is set by a [[LinearQueryIterator]]. Where parameter a is set to 1.5 hours and b - * is the initially the scanned period. - * - * In the current implementation, the `maximumArrivalTime` is ignored - */ -@injectable() -export default class QueryRunnerEarliestArrivalFirst implements IQueryRunner { - - private readonly context: Context; - private readonly connectionsProvider: IConnectionsProvider; - private readonly locationResolver: ILocationResolver; - private readonly publicTransportPlannerFactory: interfaces.Factory; - - private readonly journeyExtractorEarliestArrival: JourneyExtractorEarliestArrival; - - private readonly initialReachableStopsFinder: IReachableStopsFinder; - private readonly transferReachableStopsFinder: IReachableStopsFinder; - private readonly finalReachableStopsFinder: IReachableStopsFinder; - - constructor( - @inject(TYPES.Context) - context: Context, - @inject(TYPES.ConnectionsProvider) - connectionsProvider: IConnectionsProvider, - @inject(TYPES.LocationResolver) - locationResolver: ILocationResolver, - @inject(TYPES.PublicTransportPlannerFactory) - publicTransportPlannerFactory: interfaces.Factory, - @inject(TYPES.ReachableStopsFinder) - @tagged("phase", ReachableStopsSearchPhase.Initial) - initialReachableStopsFinder: IReachableStopsFinder, - @inject(TYPES.ReachableStopsFinder) - @tagged("phase", ReachableStopsSearchPhase.Transfer) - transferReachableStopsFinder: IReachableStopsFinder, - @inject(TYPES.ReachableStopsFinder) - @tagged("phase", ReachableStopsSearchPhase.Final) - finalReachableStopsFinder: IReachableStopsFinder, - ) { - this.context = context; - this.connectionsProvider = connectionsProvider; - this.locationResolver = locationResolver; - this.publicTransportPlannerFactory = publicTransportPlannerFactory; - - this.initialReachableStopsFinder = initialReachableStopsFinder; - this.transferReachableStopsFinder = transferReachableStopsFinder; - this.finalReachableStopsFinder = finalReachableStopsFinder; - - this.journeyExtractorEarliestArrival = new JourneyExtractorEarliestArrival( - locationResolver, - context, - ); - } - - public async run(query: IQuery): Promise> { - const baseQuery: IResolvedQuery = await this.resolveBaseQuery(query); - - if (baseQuery.publicTransportOnly) { - - const earliestArrivalPlanner = new CSAEarliestArrival( - this.connectionsProvider, - this.locationResolver, - this.initialReachableStopsFinder, - this.transferReachableStopsFinder, - this.finalReachableStopsFinder, - this.journeyExtractorEarliestArrival, - this.context, - ); - - const earliestArrivalIterator = await earliestArrivalPlanner.plan(baseQuery); - - const path: IPath = await new Promise((resolve) => { - earliestArrivalIterator - .take(1) - .on("data", (result: IPath) => { - resolve(result); - }) - .on("end", () => { - resolve(null); - }); - }); - - if (path === null && this.context) { - this.context.emit(EventType.AbortQuery, "This query has no results"); - } - - let initialTimeSpan: DurationMs = Units.fromHours(1); - let travelDuration: DurationMs; - - if (path && path.steps && path.steps.length > 0) { - const firstStep = path.steps[0]; - const lastStep = path.steps[path.steps.length - 1]; - - initialTimeSpan = lastStep.stopTime.getTime() - baseQuery.minimumDepartureTime.getTime(); - travelDuration = lastStep.stopTime.getTime() - firstStep.startTime.getTime(); - } - - baseQuery.maximumTravelDuration = travelDuration * 2; - - const queryIterator = new LinearQueryIterator(baseQuery, Units.fromHours(1.5), initialTimeSpan); - - const subQueryIterator = new FlatMapIterator( - queryIterator, - this.runSubquery.bind(this), - ); - - const prependedIterator = subQueryIterator.prepend([path]); - - return new FilterUniqueIterator(prependedIterator, Path.compareEquals); - - } else { - throw new InvalidQueryError("Query should have publicTransportOnly = true"); - } - } - - private runSubquery(query: IResolvedQuery): AsyncIterator { - this.context.emit(EventType.SubQuery, query); - - const planner = this.publicTransportPlannerFactory() as IPublicTransportPlanner; - - return new PromiseProxyIterator(() => planner.plan(query)); - } - - private async resolveEndpoint(endpoint: string | string[] | ILocation | ILocation[]): Promise { - - if (Array.isArray(endpoint)) { - const promises = (endpoint as Array) - .map((singleEndpoint: string | ILocation) => - this.locationResolver.resolve(singleEndpoint), - ); - - return await Promise.all(promises); - - } else { - return [await this.locationResolver.resolve(endpoint)]; - } - } - - private async resolveBaseQuery(query: IQuery): Promise { - // tslint:disable:trailing-comma - const { - from, to, - minimumWalkingSpeed, maximumWalkingSpeed, walkingSpeed, - maximumWalkingDuration, maximumWalkingDistance, - minimumTransferDuration, maximumTransferDuration, maximumTransferDistance, - maximumTransfers, - minimumDepartureTime, - ...other - } = query; - // tslint:enable:trailing-comma - - const resolvedQuery: IResolvedQuery = Object.assign({}, other); - - resolvedQuery.minimumDepartureTime = minimumDepartureTime || new Date(); - - try { - resolvedQuery.from = await this.resolveEndpoint(from); - resolvedQuery.to = await this.resolveEndpoint(to); - - } catch (e) { - return Promise.reject(new InvalidQueryError(e)); - } - - resolvedQuery.minimumWalkingSpeed = minimumWalkingSpeed || walkingSpeed || Defaults.defaultMinimumWalkingSpeed; - resolvedQuery.maximumWalkingSpeed = maximumWalkingSpeed || walkingSpeed || Defaults.defaultMaximumWalkingSpeed; - - resolvedQuery.maximumWalkingDuration = maximumWalkingDuration || - Units.toDuration(maximumWalkingDistance, resolvedQuery.minimumWalkingSpeed) || Defaults.defaultWalkingDuration; - - resolvedQuery.minimumTransferDuration = minimumTransferDuration || Defaults.defaultMinimumTransferDuration; - resolvedQuery.maximumTransferDuration = maximumTransferDuration || - Units.toDuration(maximumTransferDistance, resolvedQuery.minimumWalkingSpeed) || - Defaults.defaultMaximumTransferDuration; - - resolvedQuery.maximumTransfers = maximumTransfers || Defaults.defaultMaximumTransfers; - - return resolvedQuery; - } -} diff --git a/src/query-runner/exponential/ExponentialQueryIterator.ts b/src/query-runner/exponential/ExponentialQueryIterator.ts index a5525a2b..7b7f08df 100644 --- a/src/query-runner/exponential/ExponentialQueryIterator.ts +++ b/src/query-runner/exponential/ExponentialQueryIterator.ts @@ -29,6 +29,10 @@ export default class ExponentialQueryIterator extends AsyncIterator 2 * 24 * 60 * 60 * 1000) { + this.close(); + } + return Object.assign({}, this.baseQuery, {maximumArrivalTime}); } } diff --git a/src/query-runner/exponential/QueryRunnerExponential.test.ts b/src/query-runner/exponential/QueryRunnerExponential.test.ts index 5a09c0bb..64091e11 100644 --- a/src/query-runner/exponential/QueryRunnerExponential.test.ts +++ b/src/query-runner/exponential/QueryRunnerExponential.test.ts @@ -1,11 +1,13 @@ import "jest"; import LDFetch from "ldfetch"; -import Context from "../../Context"; +import Catalog from "../../Catalog"; +import RoutableTileRegistry from "../../entities/tiles/registry"; import TravelMode from "../../enums/TravelMode"; -import ConnectionsFetcherLazy from "../../fetcher/connections/lazy/ConnectionsFetcherLazy"; +import ConnectionsFetcherRaw from "../../fetcher/connections/ConnectionsFetcherRaw"; +import ConnectionsProviderDefault from "../../fetcher/connections/ConnectionsProviderDefault"; import StopsFetcherLDFetch from "../../fetcher/stops/ld-fetch/StopsFetcherLDFetch"; +import ILeg from "../../interfaces/ILeg"; import IPath from "../../interfaces/IPath"; -import IStep from "../../interfaces/IStep"; import CSAProfile from "../../planner/public-transport/CSAProfile"; import JourneyExtractorProfile from "../../planner/public-transport/JourneyExtractorProfile"; import ReachableStopsFinderBirdsEyeCached from "../../planner/stops/ReachableStopsFinderBirdsEyeCached"; @@ -14,12 +16,11 @@ import LocationResolverDefault from "../LocationResolverDefault"; import QueryRunnerExponential from "./QueryRunnerExponential"; describe("[QueryRunnerExponential]", () => { - jest.setTimeout(100000); + jest.setTimeout(300000); let publicTransportResult; const query = { - publicTransportOnly: true, from: "http://irail.be/stations/NMBS/008896925", // Ingelmunster to: "http://irail.be/stations/NMBS/008892007", // Ghent-Sint-Pieters minimumDepartureTime: new Date(), @@ -29,17 +30,20 @@ describe("[QueryRunnerExponential]", () => { const createExponentialQueryRunner = () => { const ldFetch = new LDFetch({ headers: { Accept: "application/ld+json" } }); - const connectionFetcher = new ConnectionsFetcherLazy(ldFetch); - connectionFetcher.setTravelMode(TravelMode.Train); - connectionFetcher.setAccessUrl("https://graph.irail.be/sncb/connections"); - + const connectionsFetcher = new ConnectionsFetcherRaw(); const stopsFetcher = new StopsFetcherLDFetch(ldFetch); stopsFetcher.setAccessUrl("https://irail.be/stations/NMBS"); - const locationResolver = new LocationResolverDefault(stopsFetcher); - const reachableStopsFinder = new ReachableStopsFinderBirdsEyeCached(stopsFetcher); + const catalog = new Catalog(); + catalog.addConnectionsSource("https://graph.irail.be/sncb/connections", TravelMode.Train); - const context = new Context(); + const connectionProvider = new ConnectionsProviderDefault((travelMode: TravelMode) => { + connectionsFetcher.setTravelMode(travelMode); + return connectionsFetcher; + }, catalog); + + const locationResolver = new LocationResolverDefault(stopsFetcher, new RoutableTileRegistry()); + const reachableStopsFinder = new ReachableStopsFinderBirdsEyeCached(stopsFetcher); const createJourneyExtractor = () => { return new JourneyExtractorProfile( @@ -49,7 +53,7 @@ describe("[QueryRunnerExponential]", () => { const createPlanner = () => { return new CSAProfile( - connectionFetcher, + connectionProvider, locationResolver, reachableStopsFinder, reachableStopsFinder, @@ -58,7 +62,7 @@ describe("[QueryRunnerExponential]", () => { ); }; - return new QueryRunnerExponential(context, locationResolver, createPlanner); + return new QueryRunnerExponential(locationResolver, createPlanner, undefined); }; const result: IPath[] = []; @@ -83,20 +87,20 @@ describe("[QueryRunnerExponential]", () => { }); }); -const checkStops = (result, query) => { +const checkStops = (result: IPath[], query) => { expect(result).toBeDefined(); expect(result.length).toBeGreaterThanOrEqual(1); for (const path of result) { - expect(path.steps).toBeDefined(); + expect(path.legs).toBeDefined(); - expect(path.steps.length).toBeGreaterThanOrEqual(1); + expect(path.legs.length).toBeGreaterThanOrEqual(1); let currentLocation = query.from; - path.steps.forEach((step: IStep) => { - expect(step).toBeDefined(); - expect(currentLocation).toEqual(step.startLocation.id); - currentLocation = step.stopLocation.id; + path.legs.forEach((leg: ILeg) => { + expect(leg).toBeDefined(); + expect(currentLocation).toEqual(leg.getStartLocation().id); + currentLocation = leg.getStopLocation().id; }); expect(query.to).toEqual(currentLocation); diff --git a/src/query-runner/exponential/QueryRunnerExponential.ts b/src/query-runner/exponential/QueryRunnerExponential.ts index c834d12e..780da65e 100644 --- a/src/query-runner/exponential/QueryRunnerExponential.ts +++ b/src/query-runner/exponential/QueryRunnerExponential.ts @@ -1,15 +1,17 @@ import { AsyncIterator } from "asynciterator"; import { PromiseProxyIterator } from "asynciterator-promiseproxy"; +import { EventEmitter } from "events"; import { inject, injectable, interfaces } from "inversify"; -import Context from "../../Context"; import Defaults from "../../Defaults"; -import EventType from "../../enums/EventType"; import InvalidQueryError from "../../errors/InvalidQueryError"; +import EventBus from "../../events/EventBus"; +import EventType from "../../events/EventType"; import ILocation from "../../interfaces/ILocation"; import IPath from "../../interfaces/IPath"; import IQuery from "../../interfaces/IQuery"; import Path from "../../planner/Path"; import IPublicTransportPlanner from "../../planner/public-transport/IPublicTransportPlanner"; +import IRoadPlanner from "../../planner/road/IRoadPlanner"; import TYPES from "../../types"; import FilterUniqueIterator from "../../util/iterators/FilterUniqueIterator"; import FlatMapIterator from "../../util/iterators/FlatMapIterator"; @@ -20,9 +22,6 @@ import IResolvedQuery from "../IResolvedQuery"; import ExponentialQueryIterator from "./ExponentialQueryIterator"; /** - * This exponential query runner only accepts public transport queries (`publicTransportOnly = true`). - * It uses the registered [[IPublicTransportPlanner]] to execute them. - * * To improve the user perceived performance, the query gets split into subqueries * with exponentially increasing time frames: * @@ -36,25 +35,29 @@ import ExponentialQueryIterator from "./ExponentialQueryIterator"; export default class QueryRunnerExponential implements IQueryRunner { private readonly locationResolver: ILocationResolver; private readonly publicTransportPlannerFactory: interfaces.Factory; - private readonly context: Context; + private readonly eventBus: EventEmitter; + private readonly roadPlanner: IRoadPlanner; constructor( - @inject(TYPES.Context) - context: Context, @inject(TYPES.LocationResolver) - locationResolver: ILocationResolver, + locationResolver: ILocationResolver, @inject(TYPES.PublicTransportPlannerFactory) - publicTransportPlannerFactory: interfaces.Factory, + publicTransportPlannerFactory: interfaces.Factory, + @inject(TYPES.RoadPlanner) + roadPlanner: IRoadPlanner, ) { - this.context = context; + this.eventBus = EventBus.getInstance(); this.locationResolver = locationResolver; this.publicTransportPlannerFactory = publicTransportPlannerFactory; + this.roadPlanner = roadPlanner; } public async run(query: IQuery): Promise> { const baseQuery: IResolvedQuery = await this.resolveBaseQuery(query); - if (baseQuery.publicTransportOnly) { + if (baseQuery.roadNetworkOnly) { + return this.roadPlanner.plan(baseQuery); + } else { const queryIterator = new ExponentialQueryIterator(baseQuery, 15 * 60 * 1000); const subqueryIterator = new FlatMapIterator( @@ -63,15 +66,12 @@ export default class QueryRunnerExponential implements IQueryRunner { ); return new FilterUniqueIterator(subqueryIterator, Path.compareEquals); - - } else { - throw new InvalidQueryError("Query should have publicTransportOnly = true"); } } private runSubquery(query: IResolvedQuery): AsyncIterator { // TODO investigate if publicTransportPlanner can be reused or reuse some of its aggregated data - this.context.emit(EventType.SubQuery, query); + this.eventBus.emit(EventType.SubQuery, query); const planner = this.publicTransportPlannerFactory() as IPublicTransportPlanner; @@ -96,7 +96,6 @@ export default class QueryRunnerExponential implements IQueryRunner { private async resolveBaseQuery(query: IQuery): Promise { // tslint:disable:trailing-comma const { - from, to, minimumWalkingSpeed, maximumWalkingSpeed, walkingSpeed, maximumWalkingDuration, maximumWalkingDistance, minimumTransferDuration, maximumTransferDuration, maximumTransferDistance, @@ -106,14 +105,18 @@ export default class QueryRunnerExponential implements IQueryRunner { } = query; // tslint:enable:trailing-comma - const resolvedQuery: IResolvedQuery = Object.assign({}, other); + // make a deep copy of these + let { from, to } = other; + from = JSON.parse(JSON.stringify(from)); + to = JSON.parse(JSON.stringify(to)); + + const resolvedQuery: IResolvedQuery = Object.assign({}, other as IResolvedQuery); resolvedQuery.minimumDepartureTime = minimumDepartureTime || new Date(); try { resolvedQuery.from = await this.resolveEndpoint(from); resolvedQuery.to = await this.resolveEndpoint(to); - } catch (e) { return Promise.reject(new InvalidQueryError(e)); } diff --git a/src/test/test-connections-iterator-2.ts b/src/test/test-connections-iterator-2.ts deleted file mode 100644 index 9172efd9..00000000 --- a/src/test/test-connections-iterator-2.ts +++ /dev/null @@ -1,37 +0,0 @@ -import LDFetch from "ldfetch"; -import TravelMode from "../enums/TravelMode"; -import ConnectionsIteratorLazy from "../fetcher/connections/lazy/ConnectionsIteratorLazy"; - -const ldFetch = new LDFetch({ headers: { Accept: "application/ld+json" } }); - -const upperBoundDate = new Date(); -upperBoundDate.setHours(upperBoundDate.getHours() + 2); - -const config = { - upperBoundDate, - backward: true, -}; - -const iterator = new ConnectionsIteratorLazy( - "https://graph.irail.be/sncb/connections", - TravelMode.Train, - ldFetch, - config, - ); - -let i = 0; - -console.time("ConnectionsIterator"); - -iterator.on("readable", () => { - let connection = iterator.read(); - - while (connection && i++ < 4000) { - - connection = iterator.read(); - } - - if (i > 3999) { - console.timeEnd("ConnectionsIterator"); - } -}); diff --git a/src/types.ts b/src/types.ts index d8835c42..97d8574b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,8 +1,10 @@ import TravelMode from "./enums/TravelMode"; import IConnectionsFetcher from "./fetcher/connections/IConnectionsFetcher"; import IStopsFetcher from "./fetcher/stops/IStopsFetcher"; +import IRoutableTileFetcher from "./fetcher/tiles/IRoutableTileFetcher"; const TYPES = { + EventBus: Symbol("EventBus"), Context: Symbol("Context"), QueryRunner: Symbol("QueryRunner"), LocationResolver: Symbol("LocationResolver"), @@ -15,19 +17,31 @@ const TYPES = { StopsFetcher: Symbol("StopsFetcher"), StopsFetcherFactory: Symbol("StopsFetcherFactory"), + RoutableTileProvider: Symbol("TileProvider"), + RoutableTileFetcher: Symbol("TileFetcher"), + RoutableTileRegistry: Symbol("RoutableTileRegistry"), + + FootpathsProvider: Symbol("FootpathsProvider"), + PublicTransportPlanner: Symbol("PublicTransportPlanner"), PublicTransportPlannerFactory: Symbol("PublicTransportPlannerFactory"), + ProfileFetcher: Symbol("ProfileFetcher"), + ProfileProvider: Symbol("ProfileProvider"), RoadPlanner: Symbol("RoadPlanner"), RoadPlannerFactory: Symbol("RoadPlannerFactory"), + PathfinderProvider: Symbol("PathfinderProvider"), + ShortestPathAlgorithm: Symbol("ShortestPathAlgorithm"), + ShortestPathTreeAlgorithm: Symbol("ShortestPathTreeAlgorithm"), ReachableStopsFinder: Symbol("ReachableStopsFinder"), JourneyExtractor: Symbol("JourneyExtractor"), LDFetch: Symbol("LDFetch"), + LDLoader: Symbol("LDLoader"), Catalog: Symbol("Catalog"), }; export default TYPES; export type StopsFetcherFactory = (accessUrl: string) => IStopsFetcher; -export type ConnectionsFetcherFactory = (accessUrl: string, travelMode: TravelMode) => IConnectionsFetcher; +export type ConnectionsFetcherFactory = (travelMode: TravelMode) => IConnectionsFetcher; diff --git a/src/uri/constants.ts b/src/uri/constants.ts new file mode 100644 index 00000000..4984889e --- /dev/null +++ b/src/uri/constants.ts @@ -0,0 +1,9 @@ +export const XMLS = "http://www.w3.org/2001/XMLSchema"; +export const HYDRA = "http://www.w3.org/ns/hydra/core"; +export const OSM = "https://w3id.org/openstreetmap/terms"; +export const GEO = "http://www.w3.org/2003/01/geo/wgs84_pos"; +export const RDF = "http://www.w3.org/1999/02/22-rdf-syntax-ns"; +export const RDFS = "http://www.w3.org/2000/01/rdf-schema"; +export const ROUTE = "https://w3id.org/routabletiles/terms#"; +export const PLANNER = "https://planner.js.org/terms#"; +export const PROFILE = "https://w3id.org/openplannerteam/profile#"; diff --git a/src/uri/uri.ts b/src/uri/uri.ts new file mode 100644 index 00000000..0aa375f7 --- /dev/null +++ b/src/uri/uri.ts @@ -0,0 +1,19 @@ +export default class URI { + public static inNS(ns: string, id: string): string { + // this probably misses a lot of special cases + // but it'll do for now + const lastChar = ns[ns.length - 1]; + if (lastChar === "/") { + return `${ns}${id}`; + } else if (lastChar === "#") { + return `${ns}${id}`; + } else { + return `${ns}#${id}`; + } + } + + public static fakeExpand(ns: string, id: string): string { + // discards the prefix and places it the specified NS + return this.inNS(ns, id.substring(4)); + } +} diff --git a/src/util/Geo.ts b/src/util/Geo.ts index 6ab118a5..ce075e7d 100644 --- a/src/util/Geo.ts +++ b/src/util/Geo.ts @@ -46,6 +46,10 @@ export default class Geo { * @returns geo id string */ public static getId(location: ILocation): string { + if ("id" in location) { + return location.id; + } + return `geo:${location.latitude},${location.longitude}`; } } diff --git a/src/util/Tiles.ts b/src/util/Tiles.ts new file mode 100644 index 00000000..edd2a82a --- /dev/null +++ b/src/util/Tiles.ts @@ -0,0 +1,15 @@ +import { RoutableTileCoordinate } from "../entities/tiles/coordinate"; + +export function lat_to_tile(lat: number, zoom: number) { + // from https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames + return Math.floor((1 - Math.log(Math.tan(lat * Math.PI / 180) + 1 / Math.cos(lat * Math.PI / 180)) / Math.PI) + / 2 * Math.pow(2, zoom)); +} + +export function long_to_tile(lon: number, zoom: number) { + // from https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames + return Math.floor((lon + 180) / 360 * Math.pow(2, zoom)); +} +export function toTileCoordinate(lat: number, long: number, zoom = 14): RoutableTileCoordinate { + return new RoutableTileCoordinate(zoom, long_to_tile(long, zoom), lat_to_tile(lat, zoom)); +} diff --git a/src/util/UnionFind.ts b/src/util/UnionFind.ts new file mode 100644 index 00000000..d1ab0fd7 --- /dev/null +++ b/src/util/UnionFind.ts @@ -0,0 +1,52 @@ +export default class UnionFind { + private ranks: number[]; + private connections: number[]; + + constructor(size: number) { + this.connections = [...Array(size).keys()]; + this.ranks = [...Array(size).keys()]; + } + + public union(x: number, y: number) { + let xRoot = this.find(x); + let yRoot = this.find(y); + + if (xRoot === yRoot) { + return; + } + + if (this.ranks[xRoot] < this.ranks[yRoot]) { + [xRoot, yRoot] = [yRoot, xRoot]; + } + + this.connections[yRoot] = xRoot; + if (this.ranks[xRoot] === this.ranks[yRoot]) { + this.ranks[xRoot] += 1; + } + } + + public find(val: number) { + if (this.connections[val] !== val) { + this.connections[val] = this.find(this.connections[val]); + } + + return this.connections[val]; + } + + public getClusters() { + const result = {}; + + for (const [index, connection] of this.connections.entries()) { + if (index === connection) { + result[index] = new Set(); + } + } + + for (const index of this.connections.keys()) { + const cluster = this.find(index); + result[cluster].add(index); + } + + return result; + } +} diff --git a/src/util/iterators/MergeIterator.ts b/src/util/iterators/MergeIterator.ts index bba807de..d8d56201 100644 --- a/src/util/iterators/MergeIterator.ts +++ b/src/util/iterators/MergeIterator.ts @@ -20,16 +20,16 @@ export default class MergeIterator extends AsyncIterator { * @param selector * @param condensed When true, undefined values are filtered from the array passed to the selector function */ - constructor(sourceIterators: Array>, selector: (values: T[]) => number, condensed?: boolean) { + constructor(sourceIterators: Array>, selector: (values: T[]) => number, condensed = false) { super(); this.sourceIterators = sourceIterators; this.selector = selector; - this.condensed = condensed; this.values = Array(this.sourceIterators.length).fill(undefined); this.waitingForFill = Array(this.sourceIterators.length).fill(false); this.readable = true; + this.condensed = condensed; this.addListeners(); } @@ -106,7 +106,7 @@ export default class MergeIterator extends AsyncIterator { continue; } - if (this.values[sourceIndex] !== undefined) { + if (this.values[sourceIndex] !== undefined && this.values[sourceIndex] !== null) { filled(); } else { @@ -121,10 +121,9 @@ export default class MergeIterator extends AsyncIterator { const iterator = this.sourceIterators[sourceIndex]; const value = iterator.read(); - if (value) { + if (value || (!iterator.closed && iterator.readable)) { this.values[sourceIndex] = value; filled(); - } else { const shouldWait = !this.waitingForFill[sourceIndex]; @@ -164,7 +163,7 @@ export default class MergeIterator extends AsyncIterator { this.values .forEach((value: T, originalIndex: number) => { - if (value !== undefined) { + if (value !== undefined && value !== null) { values.push(value); indexMap.push(originalIndex); } diff --git a/tsconfig.json b/tsconfig.json index e2adfa36..8275fd62 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,5 +15,9 @@ }, "include": [ "src/**/*" + ], + "exclude": [ + "node_modules", + "**/*.test.ts" ] } diff --git a/webpack.config.js b/webpack.config.js index 0a356e30..d47dfc48 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -14,7 +14,7 @@ const excludeAlias = excludeModules.reduce((alias, moduleName) => { return alias; }, {}); -module.exports = { +const browserConfig = { entry: "./src/index.ts", devtool: "source-map",//"cheap-module-source-map", module: { @@ -36,8 +36,30 @@ module.exports = { output: { filename: "bundle.js", path: path.resolve(__dirname, "dist"), - library: "Planner", + library: "PlannerJS", libraryTarget: "umd", libraryExport: "default" + }, + node: { + fs: "empty" + }, + devServer: { + contentBase: path.join(__dirname, 'dist'), + compress: true, + port: 9000 } }; + +const nodeConfig = { + ...browserConfig, + target: "node", + output: { + filename: "bundle.node.js", + path: path.resolve(__dirname, "dist"), + library: "PlannerJS", + libraryTarget: "umd", + libraryExport: "default" + } +}; + +module.exports = [ browserConfig, nodeConfig ];