diff --git a/.gitignore b/.gitignore index 504afef..a948df5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,43 @@ -node_modules/ -package-lock.json +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ +.kotlin + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ +### node +node_modules + + +/logs diff --git a/GTFS-realtime-example.json b/GTFS-realtime-example.json new file mode 100644 index 0000000..3fdf6ae --- /dev/null +++ b/GTFS-realtime-example.json @@ -0,0 +1,28 @@ +{ + "id": "217990500977445278", + "tripUpdate": { + "trip": { + "tripId": "217990000033906692", + "startDate": "20241009", + "scheduleRelationship": "SCHEDULED" + }, + "stopTimeUpdate": [ + { + "stopSequence": 4, + "arrival": { + "delay": 2580, + "time": "1728498960" + }, + "departure": { + "delay": 2580, + "time": "1728498960" + }, + "stopId": "9022021490014017" + } + ], + "vehicle": { + "id": "9031021301100580" + }, + "timestamp": "1728495864" + } +} diff --git a/MMM-ResRobot.css b/MMM-ResRobot.css index efdf4d4..0af3456 100644 --- a/MMM-ResRobot.css +++ b/MMM-ResRobot.css @@ -1,40 +1,42 @@ -.ResRobot { +.MMM-ResRobot { font-size: 75%; line-height: 65px; display: inline-block; + width: fit-content; -ms-transform: translate(0, -3px); /* IE 9 */ -webkit-transform: translate(0, -3px); /* Safari */ transform: translate(0, -3px); } .ResRobot table { - width: 400px; + /* width: fit-content; */ } .departuretime { - width: 20%; - align: left; padding-right: 10px; } - +/* .departuretype { - width: 10%; - align: right; padding-right: 10px; } +.linetype { + padding-right: 10px; +} + + .lineno { - width: 15%; - align: right; padding-right: 10px; } + + .trackno { width: 10%; - align: right; + text-align: right; padding-right: 10px; } .destination { - align: left; -} + text-align: left; +} */ diff --git a/MMM-ResRobot.js b/MMM-ResRobot.js index 0181e39..d9dcfa7 100644 --- a/MMM-ResRobot.js +++ b/MMM-ResRobot.js @@ -8,7 +8,7 @@ * based on a script from Michael Teeuw http://michaelteeuw.nl * MIT Licensed. */ -Module.register("MMM-ResRobot",{ +Module.register("MMM-ResRobot", { // Define module defaults defaults: { @@ -16,8 +16,24 @@ Module.register("MMM-ResRobot",{ animationSpeed: 2000, fade: true, fadePoint: 0.25, // Start on 1/4th of the list. - apiBase: "https://api.resrobot.se/v2.1/departureBoard?format=json&passlist=0", - apiKey: "", + ResRobot: { + apiBase: "https://api.resrobot.se/v2.1/departureBoard?format=json&passlist=0", + apiKey: "", + directionFlag: "2" + }, + GTFSRegionalRealtime: { + apiKey: "", + operator: 'xt', + stopId: '9022021480123002', + baseUrl: "https://opendata.samtrafiken.se/gtfs-rt/", + updateFreq: { + morning: {start: 6, end: 10, frequency: 60}, // 06:00–10:00 + midday: {start: 10, end: 15, frequency: 120}, // 10:00–15:00 + afternoon: {start: 15, end: 20, frequency: 60}, // 15:00–20:00 + evening: {start: 20, end: 23, frequency: 120}, // 20:00–23:00 + night: {start: 23, end: 6, frequency: 300}, // 23:00–06:00 + } + }, routes: [ {from: "740020749", to: ""}, // Each route has a starting station ID from ResRobot, default: Stockholm Central Station (Metro) ], // and a destination station ID from ResRobot, default: none @@ -46,25 +62,25 @@ Module.register("MMM-ResRobot",{ }, // Define required styles. - getStyles: function() { + getStyles: function () { return ["MMM-ResRobot.css", "font-awesome.css"]; }, // Define required scripts. - getScripts: function() { + getScripts: function () { return ["moment.js"]; }, - // Define required translations. - getTranslations: function() { - return { - en: "translations/en.json", - sv: "translations/sv.json", - }; - }, + // Define required translations. + getTranslations: function () { + return { + en: "translations/en.json", + sv: "translations/sv.json", + }; + }, // Define start sequence. - start: function() { + start: function () { Log.info("Starting module: " + this.name); // Set locale. @@ -73,8 +89,8 @@ Module.register("MMM-ResRobot",{ this.initConfig(); }, - socketNotificationReceived: function(notification, payload) { - Log.log(this.name + " received a socket notification: " + notification + " - Payload: " + payload); + socketNotificationReceived: function (notification, payload) { + //Log.log(this.name + " received a socket notification: " + notification + " - Payload: " + payload); if (notification === "DEPARTURES") { this.departures = payload; this.loaded = true; @@ -83,14 +99,15 @@ Module.register("MMM-ResRobot",{ }, // Init config - initConfig: function() { + initConfig: function () { this.departures = []; + this.delays = []; this.loaded = false; this.sendSocketNotification("CONFIG", this.config); }, // Override dom generator. - getDom: function() { + getDom: function () { var wrapper = document.createElement("div"); if (this.config.routes === "") { @@ -100,7 +117,8 @@ Module.register("MMM-ResRobot",{ } if (!this.loaded) { - wrapper.innerHTML = "Fetching departures ..."; + Log.log(this.name + " is not loaded!!!"); + wrapper.innerHTML = "Hämtar tidtabell..."; wrapper.className = "dimmed light small"; return wrapper; } @@ -115,8 +133,13 @@ Module.register("MMM-ResRobot",{ break; } var departure = this.departures[d]; - if (moment(departure.timestamp).isBefore(cutoff)) { - continue; + + let calculatedDepartureTime = departure.updatedTime + ? moment.unix(departure.updatedTime) + : moment(departure.timestamp); + + if (calculatedDepartureTime.isBefore(cutoff)) { + continue; //this is done in node_helper as well! } n++; @@ -126,13 +149,32 @@ Module.register("MMM-ResRobot",{ var depTimeCell = document.createElement("td"); depTimeCell.className = "departuretime"; depTimeCell.innerHTML = departure.departureTime; - if (departure.waitingTime < this.config.getRelative) { - if (departure.waitingTime > 1) { - depTimeCell.innerHTML = departure.waitingTime + " " + this.translate("MINUTES_SHORT"); + if (departure.waitingTime/60 < this.config.getRelative) { + if (departure.waitingTime > 60 || departure.waitingTime < 0) { + depTimeCell.innerHTML = Math.round(departure.waitingTime / 60) + " " + this.translate("MINUTES_SHORT"); } else { - depTimeCell.innerHTML = this.translate("NOW"); + depTimeCell.innerHTML = "<1 min"; } } + //add GTFS-delay to timetable if pressent! + if (departure.delay && departure.delay !== 0) { + if (departure.delay > 0) { + if (departure.delay < 60 && departure.delay >= 20) { + depTimeCell.innerHTML += ` (+${departure.delay}s)`; + } else if (departure.delay >= 60) { + const delayMinutes = Math.round(departure.delay / 60) + depTimeCell.innerHTML += ` (+${delayMinutes}m)` + } + } else { + if (departure.delay > -60 && departure.delay < -20) { + depTimeCell.innerHTML += ` (${departure.delay}s tidig!)`; + } else if (departure.delay <= -60){ + const delayMinutes = Math.round(departure.delay / 60) + depTimeCell.innerHTML += ` (${-delayMinutes}m tidig!)` + } + } + } + row.appendChild(depTimeCell); var depTypeCell = document.createElement("td"); @@ -142,7 +184,7 @@ Module.register("MMM-ResRobot",{ if (this.config.coloredIcons) { if (this.config.colorTable[departure.type]) { typeSymbol.setAttribute("style", "color:" + this.config.colorTable[departure.type]); - } else { + } else { typeSymbol.setAttribute("style", "color:" + this.config.colorTable[departure.type.charAt(0)]); } } @@ -164,11 +206,11 @@ Module.register("MMM-ResRobot",{ var depToCell = document.createElement("td"); depToCell.className = "to"; depToCell.innerHTML = departure.to; - row.appendChild(depToCell); + //row.appendChild(depToCell); if (this.config.fade && this.config.fadePoint < 1) { if (this.config.fadePoint < 0) { - this.config.fadePoint = 0; + this.config.fadePoint = 0; } var startingPoint = this.config.maximumEntries * this.config.fadePoint; var steps = this.departures.length - startingPoint; @@ -188,9 +230,9 @@ Module.register("MMM-ResRobot",{ /* scheduleUpdate() * Schedule next update. * - * argument delay number - Milliseconds before next update. If empty, 30 seconds is used. + * argument delay number - Milliseconds before next update. If empty, 10 seconds is used. */ - scheduleUpdate: function(delay) { + scheduleUpdate: function (delay) { var nextLoad = 10000; if (typeof delay !== "undefined" && delay >= 0) { nextLoad = delay; @@ -198,7 +240,7 @@ Module.register("MMM-ResRobot",{ var self = this; clearTimeout(this.updateTimer); - this.updateTimer = setTimeout(function() { + this.updateTimer = setTimeout(function () { self.updateDom(); self.scheduleUpdate(10000); }, nextLoad); diff --git a/README.md b/README.md index b536d7a..881cb0f 100644 --- a/README.md +++ b/README.md @@ -30,8 +30,106 @@ uses the ResRobot API for which you do need to obtain an API key, see below. apiKey: "" // Your ResRobot apiKey } }, + + Kalles modified version: + { + module: 'MMM-ResRobot', + position: 'top_left', + header: 'Domarringen', + config: { + routes: [ + { + from: '740019209', + to: '' + } + ], + updateInterval: 30000, + getRelative: 20, + showTrack: false, + ResRobot: { + apiBase: 'https://api.resrobot.se/v2.1/departureBoard?format=json&passlist=0', + apiKey: '', + directionFlag: '2' + }, + GTFSRegionalRealtime: { + apiKey: '', + operator: 'xt', + stopId: '9022021480123002', + baseUrl: 'https://opendata.samtrafiken.se/gtfs-rt/', + updateFreq: { + morning: { + start: 6, + end: 10, + frequency: 60 + }, + midday: { + start: 10, + end: 15, + frequency: 120 + }, + afternoon: { + start: 15, + end: 20, + frequency: 60 + }, + evening: { + start: 20, + end: 23, + frequency: 120 + }, + night: { + start: 23, + end: 6, + frequency: 300 + } + } + } + } + } ``` # Get API key You need to obtain your API key here: http://www.trafiklab.se, you want one for API "ResRobot v2.1". If you have a key for 2.0 you need to get a new one. Registration is free but required. + + +# GTFS realtime-data + +Kalles notes: +1. Skapa ett projekt +2. skapa api-keys för **Stops data**, **ResRobot v2.1** & **GTFS Regional Realtime** +3. Hitta stationsid för aktuell hållplats + 1. ladda ner _stops.xml för hela sverige [se här](https://www.trafiklab.se/api/netex-datasets/stops-data/) + 2. lättast i webläsaren: https://opendata.samtrafiken.se/stopsregister-netex-sweden/sweden.zip?key= - (wget gav 406) + 1. öppna i utforskaren / extrahera, så får du en _stops.xml-fil! + 3. Hitta de **local-stoppoint-gid** som tillhör vald hållplats (två st => en åt varje håll) + 1. lättast: kör regex med perl: + 2. `perl -0777 -ne 'while (/Gävle Domarringen(?:(?!<\/StopPlace>).)*?local-stoppoint-gid<\/Key>\n *\d*:(.*?)<\/Value>\n/sg) { print "hållplats: $1\n" }' data/_stops.xml` + - hållplats: 9022021480123001 (bort från centrum) + - hållplats: 9022021480123002 (mot Rådhuset/centrum) +4. hämta tidtabell med modifierad version av: [MMM-ResRobot](https://github.com/Alvinger/MMM-ResRobot) +5. hämta GTFS-Realtime data filtrera ut "departure" frånd de stopTimeUpdate-poster som har med aktuell stationen att göra. se [stopSequence.json](data/stopSequence.json) +```json +{ + "stopSequence": 17, + "arrival": { + "delay": 63, + "time": "1728504843" + }, + "departure": { + "delay": 63, + "time": "1728504843" + }, + "stopId": "9022021480123002" +} +``` +- jämför med ResRobots tider, time är epoch och redan omräknat med delay som är i sekunder!!! +- https://www.epochconverter.com/ för att konvertera och jämföra i xtrafik-appen +- time = 22:03:59 - delay 119s => tidtabell 22:02:00 +1. sätt sedan delayet på rätt post i tabellen från ResRobot! + - jag hoppas att det går att urskilja 3an och 12an på stopSequence om de har samma tid (vilket stopp i ordningen det är på turen) + trean verkar ha 7 och 12an 17 om jag gissar rätt! + + +fick också den [här](https://github.com/staeco/gtfs-stream/blob/master/src/rt/index.js) streamren att funka manuellt om det behövs + diff --git a/node_helper.js b/node_helper.js index 0390424..fc7c80b 100644 --- a/node_helper.js +++ b/node_helper.js @@ -11,10 +11,14 @@ const Log = require("../../js/logger.js"); const NodeHelper = require("node_helper"); const moment = require("moment"); +const axios = require('axios'); +const gtfs = require('gtfs-stream'); + +let lastGtfsFetch = Date.now() - 60000; module.exports = NodeHelper.create({ // Define start sequence. - start: function() { + start: function () { Log.info("Starting node_helper for module: " + this.name); // Set locale. moment.locale(config.language); @@ -22,12 +26,18 @@ module.exports = NodeHelper.create({ }, // Receive notification - socketNotificationReceived: function(notification, payload) { - Log.info("node_helper for " + this.name + " received a socket notification: " + notification + " - Payload: " + JSON.stringify(payload, null, 2)); + socketNotificationReceived: function (notification, payload) { + // Log.info("node_helper for " + this.name + " received a socket notification: " + notification + " - Payload: " + JSON.stringify(payload, null, 2)); if (notification === "CONFIG") { // && this.started == false) { this.config = payload; this.started = true; this.departures = []; + this.delays = []; + try { + this.getGTFSData() + }catch (e) { + Log.error("failed to getGTFSData for ResResrobot!") + } this.updateDepartures(); } }, @@ -35,19 +45,20 @@ module.exports = NodeHelper.create({ /* updateDepartures() * Check current departures and remove old ones. Requests new departure data if needed. */ - updateDepartures: function() { + updateDepartures: function () { + var self = this; var now = moment(); var cutoff = now.clone().add(moment.duration(this.config.skipMinutes, "minutes")); // Sort current departures by routeId and departure time (descending) - this.departures.sort(function(a, b) { + this.departures.sort(function (a, b) { if (a.routeId < b.routeId) return -1; if (a.routeId > b.routeId) return 1; if (a.timestamp < b.timestamp) return 1; if (a.timestamp > b.timestamp) return -1; return 0; - }); + }); // Loop through current departures (by route) and skip old ones var routeId = ""; @@ -61,8 +72,10 @@ module.exports = NodeHelper.create({ } // Only keep departures if they occur after current time + minutes to skip // If old departure is found then we clear all saved departures for that route - var departureTime = moment(dep.timestamp); - if (departureTime.isAfter(cutoff)) { + let calculatedDepartureTime = dep.updatedTime + ? moment.unix(dep.updatedTime) + : moment(dep.timestamp); + if (calculatedDepartureTime.isAfter(cutoff)) { departures[routeId].push(dep); } else { departures[routeId] = []; @@ -76,9 +89,9 @@ module.exports = NodeHelper.create({ // If a route has departures, save them to output var getRoutes = []; for (var routeId in this.config.routes) { - if (typeof departures[routeId] == 'undefined' || departures[routeId].length == 0) { + if (typeof departures[routeId] == 'undefined' || departures[routeId].length === 0) { // Get current list of departures between from and to - var params = { "id": this.config.routes[routeId].from }; + var params = {"id": this.config.routes[routeId].from}; if (typeof this.config.routes[routeId].to == "string" && this.config.routes[routeId].to !== "") { params["direction"] = this.config.routes[routeId].to; } @@ -87,18 +100,17 @@ module.exports = NodeHelper.create({ } else { for (d in departures[routeId]) { // Recalculate waitingTime - departures[routeId][d].waitingTime = moment(departures[routeId][d].timestamp).diff(now, "minutes"); - Log.debug("WaitingTime: " + departures[routeId][d].waitingTime); + departures[routeId][d].waitingTime = moment(departures[routeId][d].timestamp).diff(now, "seconds"); this.departures.push(departures[routeId][d]); } } } // Array getRoutes contains id and url for each route that we need to retrieve departures for - if (getRoutes.length == 0) { + if (getRoutes.length === 0) { // Output departures and schedule update this.sendDepartures(); } else { - var getRouteDepartures = getRoutes.map( (r) => { + var getRouteDepartures = getRoutes.map((r) => { return (async () => { const response = await fetch(r.url); const json = await response.json(); @@ -107,11 +119,11 @@ module.exports = NodeHelper.create({ return json; })(); }) - Promise.all(getRouteDepartures) - .then( () => { - self.sendDepartures(); - }); + .then(() => { + self.sendDepartures(); + Log.info("ResRobot - Departures sent to clients!") + }); } }, @@ -120,20 +132,26 @@ module.exports = NodeHelper.create({ * * argument data object - departure data in JSON format */ - saveDepartures: function(data) { + saveDepartures: function (data) { var now = moment(); var routeId = data.routeId; for (var i in data.Departure) { var departure = data.Departure[i]; + // Log.info("departure: "); + // Log.info(departure); + if (this.config.ResRobot.directionFlag && departure.directionFlag !== this.config.ResRobot.directionFlag) { + continue; + } var departureTime = moment(departure.date + "T" + departure.time); - var waitingTime = departureTime.diff(now, "minutes"); + var waitingTime = departureTime.diff(now, "seconds"); var departureTransportNumber = departure.ProductAtStop.num; //departure.transportNumber; var departureTo = departure.direction; + var directionFlag = departure.directionFlag var departureType = departure.ProductAtStop.catOutS; //departure.Product.catOutS; // If truncation is requested, truncate ending station at first word break after n characters if (this.config.truncateAfter > 0) { - if (departureTo.indexOf(" ",this.config.truncateAfter) > 0) { - departureTo = departureTo.substring(0, departureTo.indexOf(" ",this.config.truncateAfter)); + if (departureTo.indexOf(" ", this.config.truncateAfter) > 0) { + departureTo = departureTo.substring(0, departureTo.indexOf(" ", this.config.truncateAfter)); } } // If truncation of line number is requested, truncate line number after n characters @@ -150,7 +168,8 @@ module.exports = NodeHelper.create({ line: departureTransportNumber, // Line number/name of departure track: departure.rtTrack, // Track number/name of departure type: departureType, // Short category code for departure - to: departureTo // Destination/Direction + to: departureTo, // Destination/Direction + direction: directionFlag }); } } @@ -158,20 +177,41 @@ module.exports = NodeHelper.create({ /* sendDepartures() * Output departures notification and schedule next update. */ - sendDepartures: function() { + sendDepartures: function () { // Notify the main module that we have a list of departures // Schedule update if (this.departures.length > 0) { // Sort departures by ascending time - this.departures.sort(function(a, b) { + this.departures.sort(function (a, b) { if (a.timestamp < b.timestamp) return -1; if (a.timestamp > b.timestamp) return 1; return 0; - }); + }); + this.addGTFSDelayToDepartures() + //remove douplicates: + this.departures = this.departures.filter((value, index, self) => + index === self.findIndex((obj) => `${obj.timestamp}-${obj.line}` === `${value.timestamp}-${value.line}`) + ) this.sendSocketNotification("DEPARTURES", this.departures); } this.scheduleUpdate(); }, + addGTFSDelayToDepartures: function () { + //TODO: save a map of departure and stopSequences to be used as a double check that the stop corresponds to this delay! + this.departures.forEach(departure => { + const matchingDelay = this.delays.find(delay => { + // check if schedule timestamp is the same as the (delayed time - delay) (this will be wrong if two trips has the same timestamp...!) + return new Date(departure.timestamp).getTime()/1000 === (delay.departure.time - delay.departure.delay); + }); + if (matchingDelay) { + Log.info(`departure ${departure.line} with departuretime: ${departure.departureTime} is delayed: ${matchingDelay.departure.delay}s`) + departure.stopSequence = matchingDelay.stopSequence; + departure.delay = matchingDelay.departure.delay; + departure.updatedTime = matchingDelay.departure.time.toString(); + } + }); + + }, /* createURL() * Generates a base url with api parameters based on the config. @@ -180,9 +220,9 @@ module.exports = NodeHelper.create({ * * return String - URL. */ - createURL: function(params) { - var url = this.config.apiBase; - url +="&accessId=" + encodeURIComponent(this.config.apiKey); + createURL: function (params) { + var url = this.config.ResRobot.apiBase; + url += "&accessId=" + encodeURIComponent(this.config.ResRobot.apiKey); if (this.config.maximumDuration !== "") { url += "&duration=" + encodeURIComponent(this.config.maximumDuration); } @@ -194,21 +234,94 @@ module.exports = NodeHelper.create({ } return url; }, + /* getGTFSData() + * Gets the GTFS-Realtime data to find out if a trip is delayed + */ + getGTFSData: async function () { + if (Date.now() < lastGtfsFetch + 10000) { + Log.info("douplicate calls to getGTFSData()!") + return + } + lastGtfsFetch = Date.now(); + let gtfsConf = this.config.GTFSRegionalRealtime; + const response = await axios.get( + `${gtfsConf.baseUrl}${gtfsConf.operator}/TripUpdates.pb?key=${gtfsConf.apiKey}`, + { + responseType: 'stream', + headers: { + accept: 'application/octet-stream', + 'Accept-encoding': 'br, gzip, deflate', + "If-Modified-Since": "Wed, 09 Oct 2024 10:55:00 GMT", + "If-None-Match": "bfc13a64729c4290ef5b2c2730249c88ca92d82d" + } + } + ); + let nrOfEntities = 0; + this.delays = []; + Log.info("Hämtar GTFS-Realtime data") + response.data.pipe(gtfs.rt()) + .on('data', (entity) => { + //streams one entity at a time! + nrOfEntities += 1; + let stopSeq = entity.tripUpdate.stopTimeUpdate.filter(s => s.stopId === this.config.GTFSRegionalRealtime.stopId) + if (stopSeq.length > 0) { + this.delays.push(stopSeq[0]); //only be one stop at the station per trip... + } + // to get the whole file: + // entities.push(entity); + // console.log(JSON.stringify(feed, null, 2)); + }) + .on('end', () => { + //console.log(JSON.stringify(entities, null, 2)); + // fs.writeFileSync('data/GTFS_Realtime_new.json',JSON.stringify(entities, null, 2), 'utf8'); + Log.info(`delayed trips: ${this.delays.length}`); + this.updateDepartures(); + }) + .on('error', (error) => { + console.log("Error fetching data:", error); + }); + + const updIntervall = this.getGTFSUpdateFrequency() + + clearTimeout(this.updateGtfsTimer); + this.updateGtfsTimer = setTimeout(async () => { + try { + await this.getGTFSData() + }catch (e) { + Log.error("failed to getGTFSData for ResResrobot!") + } + }, updIntervall); + }, + //function to calulate how often to call for realtime-data (max 25_000 calls / 30d) + getGTFSUpdateFrequency: function () { + const now = new Date(); + const hours = now.getHours(); + let updateFreq = this.config.GTFSRegionalRealtime.updateFreq; + for (const key in updateFreq) { + const {start, end, frequency} = updateFreq[key]; + + if ((start <= hours && hours < end) || (start > end && (hours >= start || hours < end))) { + return frequency * 1000; + } + } + }, + +// Användning: /* scheduleUpdate() * Schedule next update. * * argument delay number - Milliseconds before next update. If empty, this.config.updateInterval is used. */ - scheduleUpdate: function(delay) { - var self = this; - var nextLoad = this.config.updateInterval; + scheduleUpdate: function (delay) { + const self = this; + let nextLoad = this.config.updateInterval; if (typeof delay !== "undefined" && delay >= 0) { nextLoad = delay; } clearTimeout(this.updateTimer); - this.updateTimer = setTimeout(function() { + this.updateTimer = setTimeout(function () { self.updateDepartures(); }, nextLoad); } diff --git a/package-lock.json b/package-lock.json index 2bc8e7b..80e6878 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,51 +1,795 @@ { "name": "MMM-ResRobot", "version": "1.0.0", - "lockfileVersion": 1, + "lockfileVersion": 3, "requires": true, - "dependencies": { - "biskviit": { + "packages": { + "": { + "name": "MMM-ResRobot", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "axios": "^1.7.7", + "fetch": "*", + "gtfs-stream": "^2.2.0" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, + "node_modules/@types/long": { + "version": "3.0.32", + "resolved": "https://registry.npmjs.org/@types/long/-/long-3.0.32.tgz", + "integrity": "sha512-ZXyOOm83p7X8p3s0IYM3VeueNmHpkk/yMlP8CLeOnEcu6hIwPH7YjZBvhQkR0ZFS2DqZAxKtJ/M5fcuv3OU5BA==" + }, + "node_modules/@types/node": { + "version": "8.10.66", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", + "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/big-integer": { + "version": "1.6.52", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", + "dependencies": { + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/biskviit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/biskviit/-/biskviit-1.0.1.tgz", "integrity": "sha1-A3oM1LcbnjMf2QoRIt4X3EnkIKc=", - "requires": { + "dependencies": { "psl": "^1.1.7" + }, + "engines": { + "node": ">=1.0.0" + } + }, + "node_modules/bluebird": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", + "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/buffer-indexof-polyfill": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", + "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", + "engines": { + "node": ">=0.2.0" + } + }, + "node_modules/chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", + "dependencies": { + "traverse": ">=0.3.0 <0.4" + }, + "engines": { + "node": "*" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/csv-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/csv-parser/-/csv-parser-3.0.0.tgz", + "integrity": "sha512-s6OYSXAK3IdKqYO33y09jhypG/bSDHPuyCme/IdEHfWpLf/jKcpitVFyOC6UemgGk8v7Q5u2XE0vvwmanxhGlQ==", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "csv-parser": "bin/csv-parser" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "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" + } + }, + "node_modules/duplexer2/node_modules/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==" + }, + "node_modules/duplexer2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/duplexify": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz", + "integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==", + "dependencies": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.2" } }, - "encoding": { + "node_modules/encoding": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", - "requires": { + "dependencies": { "iconv-lite": "~0.4.13" } }, - "fetch": { + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/fetch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fetch/-/fetch-1.1.0.tgz", "integrity": "sha1-CoJ58Gvjf58Ou1Z1YKMKSA2lmi4=", - "requires": { + "dependencies": { "biskviit": "1.0.1", "encoding": "0.1.12" } }, - "iconv-lite": { + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "deprecated": "This package is no longer supported.", + "dependencies": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/gtfs-realtime-bindings": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/gtfs-realtime-bindings/-/gtfs-realtime-bindings-0.0.6.tgz", + "integrity": "sha512-Ef92YIJ6b9LsWGhrJ53KjErFoCj0K4OQfkMtEJ6Vds9BLktIUJ9rJp0FuhXUuino7g2zGQZBFOaH0tsCgXf2OQ==", + "engines": [ + "node >= 0.10.0" + ], + "dependencies": { + "protobufjs": "6.8.6" + } + }, + "node_modules/gtfs-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/gtfs-stream/-/gtfs-stream-2.2.0.tgz", + "integrity": "sha512-f1EOpGjCt/wuvL/8UPfH5gbAMEhc3n2mocV+tT5/12kGa4v3CNlBRUstH7PjK0bchXIXpD2vf9X04RLpe4fnFQ==", + "dependencies": { + "csv-parser": "^3.0.0", + "duplexify": "^4.0.0", + "gtfs-realtime-bindings": "^0.0.6", + "lodash.pickby": "^4.6.0", + "merge2": "^1.2.2", + "pluralize": "^8.0.0", + "pumpify": "^2.0.0", + "remove-bom-stream": "^1.2.0", + "through2": "^4.0.0", + "unzipper": "^0.10.1" + } + }, + "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { + "dependencies": { "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" } }, - "psl": { + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==" + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/listenercount": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", + "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==" + }, + "node_modules/lodash.pickby": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", + "integrity": "sha512-AZV+GsS/6ckvPOVQPXSiFFacKvKB4kOQu6ynt9wz0F3LO4R9Ij4K1ddYsIytDpSgLz88JHd9P+oaLeej5/Sl7Q==" + }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/protobufjs": { + "version": "6.8.6", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.6.tgz", + "integrity": "sha512-eH2OTP9s55vojr3b7NBaF9i4WhWPkv/nq55nznWNp/FomKrLViprUcqnBjHph2tFQ+7KciGPTPsVWGz0SOhL0Q==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^3.0.32", + "@types/node": "^8.9.4", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" }, - "safer-buffer": { + "node_modules/pump": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pumpify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-2.0.1.tgz", + "integrity": "sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==", + "dependencies": { + "duplexify": "^4.1.1", + "inherits": "^2.0.3", + "pump": "^3.0.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/remove-bom-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", + "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", + "dependencies": { + "is-buffer": "^1.1.5", + "is-utf8": "^0.2.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/remove-bom-stream": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", + "integrity": "sha512-wigO8/O08XHb8YPzpDDT+QmRANfW6vLqxfaXm1YXhnFf3AkSLyjfG3GEFg4McZkmgL7KvCj5u2KczkvSP6NfHA==", + "dependencies": { + "remove-bom-buffer": "^3.0.0", + "safe-buffer": "^5.1.0", + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remove-bom-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "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" + } + }, + "node_modules/remove-bom-stream/node_modules/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==" + }, + "node_modules/remove-bom-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/remove-bom-stream/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + }, + "node_modules/stream-shift": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", + "engines": { + "node": "*" + } + }, + "node_modules/unzipper": { + "version": "0.10.14", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.14.tgz", + "integrity": "sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==", + "dependencies": { + "big-integer": "^1.6.17", + "binary": "~0.3.0", + "bluebird": "~3.4.1", + "buffer-indexof-polyfill": "~1.0.0", + "duplexer2": "~0.1.4", + "fstream": "^1.0.12", + "graceful-fs": "^4.2.2", + "listenercount": "~1.0.1", + "readable-stream": "~2.3.6", + "setimmediate": "~1.0.4" + } + }, + "node_modules/unzipper/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "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" + } + }, + "node_modules/unzipper/node_modules/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==" + }, + "node_modules/unzipper/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } } } } diff --git a/package.json b/package.json index 8392ce9..ea743f5 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,8 @@ }, "homepage": "https://github.com/Alvinger/MMM-ResRobot#readme", "dependencies": { - "fetch": "*" + "axios": "^1.7.7", + "fetch": "*", + "gtfs-stream": "^2.2.0" } }