diff --git a/CHANGELOG.md b/CHANGELOG.md index ebad61c7..02453bb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,9 @@ -# MagicMirror² Change Log +# MagicMirror� Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). -❤️ **Donate:** Enjoying MagicMirror²? [Please consider a donation!](https://magicmirror.builders/donate) With your help we can continue to improve the MagicMirror² +?? **Donate:** Enjoying MagicMirror�? [Please consider a donation!](https://magicmirror.builders/donate) With your help we can continue to improve the MagicMirror� ## [2.14.0] - Unreleased (Develop Branch) @@ -12,15 +12,21 @@ _This release is scheduled to be released on 2021-01-01._ ### Added - Added new log level "debug" to the logger. - +- Added new parameter "useKmh" to weather module for displaying wind speed as kmh. +- Chuvash translation. +- Added Weatherbit as a provider to Weather module. - Added Hindi & Gujarati translation. - Chuvash translation. +- Calendar: new options "limitDays" and "coloredEvents" +- Added new option "limitDays" - limit the number of discreet days displayed +- Added new option "customEvents" - use custom symbol/color based on keyword in event title ### Updated - Weather module - forecast now show TODAY and TOMORROW instead of weekday, to make it easier to understand. - Update dependencies to latest versions. - Update dependencies eslint, feedme, simple-git and socket.io to latest versions. +- Update lithuanian translation. ### Deleted @@ -33,17 +39,22 @@ _This release is scheduled to be released on 2021-01-01._ - Rename Greek translation to correct ISO 639-1 alpha-2 code (gr > el). (#2155) - Add a space after icons of sunrise and sunset (#2169) - Fix calendar when no DTEND record found in event, startDate overlay when endDate set (#2177) +- Fix windspeed convertion error in ukmetoffice weather provider (#2189) +- Fix console.debug not having timestamps (#2199) - Fix calendar full day event east of UTC start time (#2200) +- Fix non-fullday recurring rule processing (#2216) +- Catch errors when parsing calendar data with ical (#2022) +- Corrected logic for timeFormat "relative" and "absolute" ## [2.13.0] - 2020-10-01 Special thanks to the following contributors: @bryanzzhu, @bugsounet, @chamakura, @cjbrunner, @easyas314, @larryare, @oemel09, @rejas, @sdetweil & @sthuber90. -ℹ️ **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. +?? **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. ### Added -- `--dry-run` option adde in fetch call within updatenotification node_helper. This is to prevent +- `--dry-run` option added in fetch call within updatenotification node_helper. This is to prevent MagicMirror from consuming any fetch result. Causes conflict with MMPM when attempting to check for updates to MagicMirror and/or MagicMirror modules. - Test coverage with Istanbul, run it with `npm run test:coverage`. @@ -78,7 +89,7 @@ Special thanks to the following contributors: @bryanzzhu, @bugsounet, @chamakura Special thanks to the following contributors: @AndreKoepke, @andrezibaia, @bryanzzhu, @chamakura, @DarthBrento, @Ekristoffe, @khassel, @Legion2, @ndom91, @radokristof, @rejas, @XBCreepinJesus & @ZoneMR. -ℹ️ **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. +?? **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. ### Added @@ -116,7 +127,7 @@ Special thanks to the following contributors: @AndreKoepke, @andrezibaia, @bryan ## [2.11.0] - 2020-04-01 -🚨 READ THIS BEFORE UPDATING 🚨 +?? READ THIS BEFORE UPDATING ?? In the past years the project has grown a lot. This came with a huge downside: poor maintainability. If I let the project continue the way it was, it would eventually crash and burn. More important: I would completely lose the drive and interest to continue the project. Because of this the decision was made to simplify the core by removing all side features like automatic installers and support for exotic platforms. This release (2.11.0) is the first real release that will reflect (parts) of these changes. As a result of this, some things might break. So before you continue make sure to backup your installation. Your config, your modules or better yet: your full MagicMirror folder. In other words: update at your own risk. @@ -177,7 +188,7 @@ For more information regarding this major change, please check issue [#1860](htt Special thanks to @sdetweil for all his great contributions! -ℹ️ **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. +?? **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. ### Added @@ -206,12 +217,12 @@ Special thanks to @sdetweil for all his great contributions! ## [2.9.0] - 2019-10-01 -ℹ️ **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. If you are having issues running Electron, make sure your [Raspbian is up to date](https://www.raspberrypi.org/documentation/raspbian/updating.md). +?? **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. If you are having issues running Electron, make sure your [Raspbian is up to date](https://www.raspberrypi.org/documentation/raspbian/updating.md). ### Added - Spanish translation for "PRECIP". -- Adding a Malay (Malaysian) translation for MagicMirror². +- Adding a Malay (Malaysian) translation for MagicMirror�. - Add test check URLs of vendors 200 and 404 HTTP CODE. - Add tests for new weather module and helper to stub ajax requests. @@ -232,7 +243,7 @@ Special thanks to @sdetweil for all his great contributions! ## [2.8.0] - 2019-07-01 -ℹ️ **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. If you are having issues running Electron, make sure your [Raspbian is up to date](https://www.raspberrypi.org/documentation/raspbian/updating.md). +?? **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. If you are having issues running Electron, make sure your [Raspbian is up to date](https://www.raspberrypi.org/documentation/raspbian/updating.md). ### Added @@ -289,7 +300,7 @@ Fixed `package.json` version number. ## [2.7.0] - 2019-04-01 -ℹ️ **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. If you are having issues running Electron, make sure your [Raspbian is up to date](https://www.raspberrypi.org/documentation/raspbian/updating.md). +?? **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. If you are having issues running Electron, make sure your [Raspbian is up to date](https://www.raspberrypi.org/documentation/raspbian/updating.md). ### Added @@ -346,9 +357,9 @@ Fixed `package.json` version number. ## [2.6.0] - 2019-01-01 -ℹ️ **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. If you are having issues updating, make sure you are running the latest version of Node. +?? **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. If you are having issues updating, make sure you are running the latest version of Node. -### ✨ Experimental ✨ +### ? Experimental ? - New default [module weather](modules/default/weather). This module will eventually replace the current `currentweather` and `weatherforecast` modules. The new module is still pretty experimental, but it's included so you can give it a try and help us improve this module. Please give us you feedback using [this forum post](https://forum.magicmirror.builders/topic/9335/default-weather-module-refactoring). @@ -418,7 +429,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we - Updated Simplified Chinese translation - Swedish translations - Hungarian translations for the updatenotification module -- Updated Norsk bokmål translation +- Updated Norsk bokm�l translation - Updated Norsk nynorsk translation - Consider multi days event as full day events @@ -430,9 +441,9 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we ## [2.4.0] - 2018-07-01 -⚠️ **Warning:** This release includes an updated version of Electron. This requires a Raspberry Pi configuration change to allow the best performance and prevent the CPU from overheating. Please read the information on the [MagicMirror Wiki](https://github.com/michmich/magicmirror/wiki/configuring-the-raspberry-pi#enable-the-open-gl-driver-to-decrease-electrons-cpu-usage). +?? **Warning:** This release includes an updated version of Electron. This requires a Raspberry Pi configuration change to allow the best performance and prevent the CPU from overheating. Please read the information on the [MagicMirror Wiki](https://github.com/michmich/magicmirror/wiki/configuring-the-raspberry-pi#enable-the-open-gl-driver-to-decrease-electrons-cpu-usage). -ℹ️ **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install` +?? **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install` ### Added @@ -446,7 +457,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we - Add regex filtering to calendar module - Customize classes for table - Added option to newsfeed module to only log error parsing a news article if enabled -- Add update translations for Português Brasileiro +- Add update translations for Portugu�s Brasileiro ### Changed @@ -538,7 +549,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we ### Added - Add option to use [Nunjucks](https://mozilla.github.io/nunjucks/) templates in modules. (See `helloworld` module as an example.) -- Add Bulgarian translations for MagicMirror² and Alert module. +- Add Bulgarian translations for MagicMirror� and Alert module. - Add graceful shutdown of modules by calling `stop` function of each `node_helper` on SIGINT before exiting. - Link update subtext to Github diff of current version versus tracking branch. - Add Catalan translation. @@ -870,7 +881,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we ## [2.0.0] - 2016-05-03 -### Initial release of MagicMirror² +### Initial release of MagicMirror� It includes (but is not limited to) the following features: diff --git a/js/logger.js b/js/logger.js index e9e17c52..93a5bb53 100644 --- a/js/logger.js +++ b/js/logger.js @@ -10,7 +10,10 @@ (function (root, factory) { if (typeof exports === "object") { // add timestamps in front of log messages - require("console-stamp")(console, "yyyy-mm-dd HH:MM:ss.l"); + require("console-stamp")(console, { + pattern: "yyyy-mm-dd HH:MM:ss.l", + include: ["debug", "log", "info", "warn", "error"] + }); // Node, CommonJS-like module.exports = factory(root.config); @@ -21,8 +24,8 @@ })(this, function (config) { const logLevel = { debug: Function.prototype.bind.call(console.debug, console), - info: Function.prototype.bind.call(console.info, console), log: Function.prototype.bind.call(console.log, console), + info: Function.prototype.bind.call(console.info, console), warn: Function.prototype.bind.call(console.warn, console), error: Function.prototype.bind.call(console.error, console), group: Function.prototype.bind.call(console.group, console), diff --git a/modules/default/calendar/calendar.js b/modules/default/calendar/calendar.js index b2737586..73af9ecd 100755 --- a/modules/default/calendar/calendar.js +++ b/modules/default/calendar/calendar.js @@ -11,6 +11,7 @@ Module.register("calendar", { defaults: { maximumEntries: 10, // Total Maximum Entries maximumNumberOfDays: 365, + limitDays: 0, // Limit the number of days shown, 0 = no limit displaySymbol: true, defaultSymbol: "calendar", // Fontawesome Symbol see https://fontawesome.com/cheatsheet?from=io showLocation: false, @@ -37,6 +38,7 @@ Module.register("calendar", { hideOngoing: false, colored: false, coloredSymbolOnly: false, + customEvents: [], // Array of {keyword: "", symbol: "", color: ""} where Keyword is a regexp and symbol/color are to be applied for matched tableClass: "small", calendars: [ { @@ -153,6 +155,12 @@ Module.register("calendar", { // Override dom generator. getDom: function () { + // Define second, minute, hour, and day constants + const oneSecond = 1000; // 1,000 milliseconds + const oneMinute = oneSecond * 60; + const oneHour = oneMinute * 60; + const oneDay = oneHour * 24; + var events = this.createEventList(); var wrapper = document.createElement("table"); wrapper.className = this.config.tableClass; @@ -173,6 +181,8 @@ Module.register("calendar", { var currentFadeStep = 0; var lastSeenDate = ""; + var ev; + var needle; for (var e in events) { var event = events[e]; @@ -218,6 +228,19 @@ Module.register("calendar", { symbolWrapper.className = "symbol align-right " + symbolClass; var symbols = this.symbolsForEvent(event); + // If symbols are displayed and custom symbol is set, replace event symbol + if (this.config.displaySymbol && this.config.customEvents.length > 0) { + for (ev in this.config.customEvents) { + if (typeof this.config.customEvents[ev].symbol !== "undefined" && this.config.customEvents[ev].symbol !== "") { + needle = new RegExp(this.config.customEvents[ev].keyword, "gi"); + if (needle.test(event.title)) { + symbols[0] = this.config.customEvents[ev].symbol; + break; + } + } + } + } + for (var i = 0; i < symbols.length; i++) { var symbol = document.createElement("span"); symbol.className = "fa fa-fw fa-" + symbols[i]; @@ -248,6 +271,23 @@ Module.register("calendar", { } } + // Color events if custom color is specified + if (this.config.customEvents.length > 0) { + for (ev in this.config.customEvents) { + if (typeof this.config.customEvents[ev].color !== "undefined" && this.config.customEvents[ev].color !== "") { + needle = new RegExp(this.config.customEvents[ev].keyword, "gi"); + if (needle.test(event.title)) { + eventWrapper.style.cssText = "color:" + this.config.customEvents[ev].color; + titleWrapper.style.cssText = "color:" + this.config.customEvents[ev].color; + if (this.config.displaySymbol) { + symbolWrapper.style.cssText = "color:" + this.config.customEvents[ev].color; + } + break; + } + } + } + } + titleWrapper.innerHTML = this.titleTransform(event.title, this.config.titleReplace, this.config.wrapEvents, this.config.maxTitleLength, this.config.maxTitleLines) + repeatingCountTitle; var titleClass = this.titleClassForUrl(event.url); @@ -280,82 +320,56 @@ Module.register("calendar", { eventWrapper.appendChild(titleWrapper); var now = new Date(); - // Define second, minute, hour, and day variables - var oneSecond = 1000; // 1,000 milliseconds - var oneMinute = oneSecond * 60; - var oneHour = oneMinute * 60; - var oneDay = oneHour * 24; - if (event.fullDayEvent) { - //subtract one second so that fullDayEvents end at 23:59:59, and not at 0:00:00 one the next day - event.endDate -= oneSecond; - if (event.today) { - timeWrapper.innerHTML = this.capFirst(this.translate("TODAY")); - } else if (event.startDate - now < oneDay && event.startDate - now > 0) { - timeWrapper.innerHTML = this.capFirst(this.translate("TOMORROW")); - } else if (event.startDate - now < 2 * oneDay && event.startDate - now > 0) { - if (this.translate("DAYAFTERTOMORROW") !== "DAYAFTERTOMORROW") { - timeWrapper.innerHTML = this.capFirst(this.translate("DAYAFTERTOMORROW")); - } else { + + if (this.config.timeFormat === "absolute") { + // Use dateFormat + timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format(this.config.dateFormat)); + // Add end time if showEnd + if (this.config.showEnd) { + timeWrapper.innerHTML += "-"; + timeWrapper.innerHTML += this.capFirst(moment(event.endDate, "x").format(this.config.dateEndFormat)); + } + // For full day events we use the fullDayEventDateFormat + if (event.fullDayEvent) { + //subtract one second so that fullDayEvents end at 23:59:59, and not at 0:00:00 one the next day + event.endDate -= oneSecond; + timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format(this.config.fullDayEventDateFormat)); + } + if (this.config.getRelative > 0 && event.startDate < now) { + // Ongoing and getRelative is set + timeWrapper.innerHTML = this.capFirst( + this.translate("RUNNING", { + fallback: this.translate("RUNNING") + " {timeUntilEnd}", + timeUntilEnd: moment(event.endDate, "x").fromNow(true) + }) + ); + } else if (this.config.urgency > 0 && event.startDate - now < this.config.urgency * oneDay) { + // Within urgency days + timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow()); + } + if (event.fullDayEvent && this.config.nextDaysRelative) { + // Full days events within the next two days + if (event.today) { + timeWrapper.innerHTML = this.capFirst(this.translate("TODAY")); + } else if (event.startDate - now < oneDay && event.startDate - now > 0) { + timeWrapper.innerHTML = this.capFirst(this.translate("TOMORROW")); + } else if (event.startDate - now < 2 * oneDay && event.startDate - now > 0) { + if (this.translate("DAYAFTERTOMORROW") !== "DAYAFTERTOMORROW") { + timeWrapper.innerHTML = this.capFirst(this.translate("DAYAFTERTOMORROW")); + } + } + } + } else { + // Show relative times + if (event.startDate >= now) { + // Use relative time + timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").calendar()); + if (event.startDate - now < this.config.getRelative * oneHour) { + // If event is within getRelative hours, display 'in xxx' time format or moment.fromNow() timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow()); } } else { - /* Check to see if the user displays absolute or relative dates with their events - * Also check to see if an event is happening within an 'urgency' time frameElement - * For example, if the user set an .urgency of 7 days, those events that fall within that - * time frame will be displayed with 'in xxx' time format or moment.fromNow() - * - * Note: this needs to be put in its own function, as the whole thing repeats again verbatim - */ - if (this.config.timeFormat === "absolute") { - if (this.config.urgency > 1 && event.startDate - now < this.config.urgency * oneDay) { - // This event falls within the config.urgency period that the user has set - timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").from(moment().format("YYYYMMDD"))); - } else { - timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format(this.config.fullDayEventDateFormat)); - } - } else { - timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").from(moment().format("YYYYMMDD"))); - } - } - if (this.config.showEnd) { - timeWrapper.innerHTML += "-"; - timeWrapper.innerHTML += this.capFirst(moment(event.endDate, "x").format(this.config.fullDayEventDateFormat)); - } - } else { - if (event.startDate >= new Date()) { - if (event.startDate - now < 2 * oneDay) { - // This event is within the next 48 hours (2 days) - if (event.startDate - now < this.config.getRelative * oneHour) { - // If event is within 6 hour, display 'in xxx' time format or moment.fromNow() - timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow()); - } else { - if (this.config.timeFormat === "absolute" && !this.config.nextDaysRelative) { - timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format(this.config.dateFormat)); - } else { - // Otherwise just say 'Today/Tomorrow at such-n-such time' - timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").calendar()); - } - } - } else { - /* Check to see if the user displays absolute or relative dates with their events - * Also check to see if an event is happening within an 'urgency' time frameElement - * For example, if the user set an .urgency of 7 days, those events that fall within that - * time frame will be displayed with 'in xxx' time format or moment.fromNow() - * - * Note: this needs to be put in its own function, as the whole thing repeats again verbatim - */ - if (this.config.timeFormat === "absolute") { - if (this.config.urgency > 1 && event.startDate - now < this.config.urgency * oneDay) { - // This event falls within the config.urgency period that the user has set - timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow()); - } else { - timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format(this.config.dateFormat)); - } - } else { - timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow()); - } - } - } else { + // Ongoing event timeWrapper.innerHTML = this.capFirst( this.translate("RUNNING", { fallback: this.translate("RUNNING") + " {timeUntilEnd}", @@ -363,12 +377,7 @@ Module.register("calendar", { }) ); } - if (this.config.showEnd) { - timeWrapper.innerHTML += "-"; - timeWrapper.innerHTML += this.capFirst(moment(event.endDate, "x").format(this.config.dateEndFormat)); - } } - //timeWrapper.innerHTML += ' - '+ moment(event.startDate,'x').format('lll'); timeWrapper.className = "time light " + this.timeClassForUrl(event.url); eventWrapper.appendChild(timeWrapper); } @@ -521,6 +530,35 @@ Module.register("calendar", { events.sort(function (a, b) { return a.startDate - b.startDate; }); + + // Limit the number of days displayed + // If limitDays is set > 0, limit display to that number of days + if (this.config.limitDays > 0) { + var newEvents = []; + var lastDate = today.clone().subtract(1, "days").format("YYYYMMDD"); + var days = 0; + var eventDate; + for (var ev of events) { + eventDate = moment(ev.startDate, "x").format("YYYYMMDD"); + // if date of event is later than lastdate + // check if we already are showing max unique days + if (eventDate > lastDate) { + // if the only entry in the first day is a full day event that day is not counted as unique + if (newEvents.length === 1 && days === 1 && newEvents[0].fullDayEvent) { + days--; + } + days++; + if (days > this.config.limitDays) { + continue; + } else { + lastDate = eventDate; + } + } + newEvents.push(ev); + } + events = newEvents; + } + return events.slice(0, this.config.maximumEntries); }, diff --git a/modules/default/calendar/calendarfetcher.js b/modules/default/calendar/calendarfetcher.js index 7cb4434c..6c268c46 100644 --- a/modules/default/calendar/calendarfetcher.js +++ b/modules/default/calendar/calendarfetcher.js @@ -76,7 +76,18 @@ const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumEn return; } - const data = ical.parseICS(requestData); + let data = []; + + try { + data = ical.parseICS(requestData); + } catch (error) { + fetchFailedCallback(self, error.message); + scheduleTimer(); + return; + } + + Log.debug(" parsed data=" + JSON.stringify(data)); + const newEvents = []; // limitFunction doesn't do much limiting, see comment re: the dates array in rrule section below as to why we need to do the filtering ourselves @@ -87,13 +98,13 @@ const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumEn const eventDate = function (event, time) { return isFullDayEvent(event) ? moment(event[time], "YYYYMMDD") : moment(new Date(event[time])); }; - + Log.debug("there are " + Object.entries(data).length + " calendar entries"); Object.entries(data).forEach(([key, event]) => { const now = new Date(); const today = moment().startOf("day").toDate(); const future = moment().startOf("day").add(maximumNumberOfDays, "days").subtract(1, "seconds").toDate(); // Subtract 1 second so that events that start on the middle of the night will not repeat. let past = today; - + Log.debug("have entries "); if (includePastEvents) { past = moment().startOf("day").subtract(maximumNumberOfDays, "days").toDate(); } @@ -110,7 +121,8 @@ const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumEn if (event.type === "VEVENT") { let startDate = eventDate(event, "start"); let endDate; - // Log.debug("\nevent="+JSON.stringify(event)) + + Log.debug("\nevent=" + JSON.stringify(event)); if (typeof event.end !== "undefined") { endDate = eventDate(event, "end"); } else if (typeof event.duration !== "undefined") { @@ -212,8 +224,15 @@ const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumEn pastLocal = pastMoment.toDate(); futureLocal = futureMoment.toDate(); } else { - pastLocal = pastMoment.subtract(past.getTimezoneOffset(), "minutes").toDate(); - futureLocal = futureMoment.subtract(future.getTimezoneOffset(), "minutes").toDate(); + // if we want past events + if (includePastEvents) { + // use the calculated past time for the between from + pastLocal = pastMoment.toDate(); + } else { + // otherwise use NOW.. cause we shouldnt use any before now + pastLocal = moment().toDate(); //now + } + futureLocal = futureMoment.toDate(); // future } Log.debug(" between=" + pastLocal + " to " + futureLocal); const dates = rule.between(pastLocal, futureLocal, true, limitFunction); @@ -299,6 +318,7 @@ const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumEn } if (showRecurrence === true) { + Log.debug("saving event =" + description); addedEvents++; newEvents.push({ title: recurrenceTitle, @@ -352,7 +372,6 @@ const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumEn } // if the start and end are the same, then make end the 'end of day' value (start is at 00:00:00) if (fullDayEvent && startDate.format("x") === endDate.format("x")) { - //Log.debug("end same as start") endDate = endDate.endOf("day"); } // get correction for date saving and dst change between now and then @@ -376,7 +395,21 @@ const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumEn return a.startDate - b.startDate; }); - events = newEvents.slice(0, maximumEntries); + // include up to maximumEntries current or upcoming events + // If past events should be included, include all past events + const now = moment(); + var entries = 0; + events = []; + for (let ne of newEvents) { + if (moment(ne.endDate, "x").isBefore(now)) { + if (includePastEvents) events.push(ne); + continue; + } + entries++; + // If max events has been saved, skip the rest + if (entries > maximumEntries) break; + events.push(ne); + } self.broadcastEvents(); scheduleTimer(); diff --git a/modules/default/weather/current.njk b/modules/default/weather/current.njk index c838c1e9..240dcdc5 100755 --- a/modules/default/weather/current.njk +++ b/modules/default/weather/current.njk @@ -9,7 +9,11 @@ {% if config.useBeaufort %} {{ current.beaufortWindSpeed() | round }} {% else %} - {{ current.windSpeed | round }} + {% if config.useKmh %} + {{ current.kmhWindSpeed() | round }} + {% else %} + {{ current.windSpeed | round }} + {% endif %} {% endif %} {% if config.showWindDirection %} diff --git a/modules/default/weather/providers/darksky.js b/modules/default/weather/providers/darksky.js index 4ba90105..b2bf4e78 100755 --- a/modules/default/weather/providers/darksky.js +++ b/modules/default/weather/providers/darksky.js @@ -62,7 +62,7 @@ WeatherProvider.register("darksky", { // Implement WeatherDay generator. generateWeatherDayFromCurrentWeather(currentWeatherData) { - const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); currentWeather.date = moment(); currentWeather.humidity = parseFloat(currentWeatherData.currently.humidity); @@ -80,7 +80,7 @@ WeatherProvider.register("darksky", { const days = []; for (const forecast of forecasts) { - const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); weather.date = moment(forecast.time, "X"); weather.minTemperature = forecast.temperatureMin; diff --git a/modules/default/weather/providers/openweathermap.js b/modules/default/weather/providers/openweathermap.js index 12635f1b..2fde7139 100755 --- a/modules/default/weather/providers/openweathermap.js +++ b/modules/default/weather/providers/openweathermap.js @@ -89,11 +89,15 @@ WeatherProvider.register("openweathermap", { * Generate a WeatherObject based on currentWeatherInformation */ generateWeatherObjectFromCurrentWeather(currentWeatherData) { - const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); currentWeather.humidity = currentWeatherData.main.humidity; currentWeather.temperature = currentWeatherData.main.temp; - currentWeather.windSpeed = currentWeatherData.wind.speed; + if (this.config.windUnits === "metric") { + currentWeather.windSpeed = this.config.useKmh ? currentWeatherData.wind.speed * 3.6 : currentWeatherData.wind.speed; + } else { + currentWeather.windSpeed = currentWeatherData.wind.speed; + } currentWeather.windDirection = currentWeatherData.wind.deg; currentWeather.weatherType = this.convertWeatherType(currentWeatherData.weather[0].icon); currentWeather.sunrise = moment(currentWeatherData.sys.sunrise, "X"); @@ -112,7 +116,7 @@ WeatherProvider.register("openweathermap", { return this.fetchForecastDaily(forecasts); } // if weatherEndpoint does not match forecast or forecast/daily, what should be returned? - const days = [new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits)]; + const days = [new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh)]; return days; }, @@ -124,7 +128,7 @@ WeatherProvider.register("openweathermap", { return this.fetchOnecall(data); } // if weatherEndpoint does not match onecall, what should be returned? - const weatherData = { current: new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits), hours: [], days: [] }; + const weatherData = { current: new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh), hours: [], days: [] }; return weatherData; }, @@ -141,7 +145,7 @@ WeatherProvider.register("openweathermap", { let snow = 0; // variable for date let date = ""; - let weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + let weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); for (const forecast of forecasts) { if (date !== moment(forecast.dt, "X").format("YYYY-MM-DD")) { @@ -154,7 +158,7 @@ WeatherProvider.register("openweathermap", { // push weather information to days array days.push(weather); // create new weather-object - weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); minTemp = []; maxTemp = []; @@ -217,7 +221,7 @@ WeatherProvider.register("openweathermap", { const days = []; for (const forecast of forecasts) { - const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); weather.date = moment(forecast.dt, "X"); weather.minTemperature = forecast.temp.min; @@ -263,7 +267,7 @@ WeatherProvider.register("openweathermap", { let precip = false; // get current weather, if requested - const current = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + const current = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); if (data.hasOwnProperty("current")) { current.date = moment(data.current.dt, "X").utcOffset(data.timezone_offset / 60); current.windSpeed = data.current.wind_speed; @@ -295,7 +299,7 @@ WeatherProvider.register("openweathermap", { current.feelsLikeTemp = data.current.feels_like; } - let weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + let weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); // get hourly weather, if requested const hours = []; @@ -331,7 +335,7 @@ WeatherProvider.register("openweathermap", { } hours.push(weather); - weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); } } @@ -370,7 +374,7 @@ WeatherProvider.register("openweathermap", { } days.push(weather); - weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); } } diff --git a/modules/default/weather/providers/ukmetoffice.js b/modules/default/weather/providers/ukmetoffice.js index f1a50074..b71ced88 100755 --- a/modules/default/weather/providers/ukmetoffice.js +++ b/modules/default/weather/providers/ukmetoffice.js @@ -73,7 +73,7 @@ WeatherProvider.register("ukmetoffice", { * Generate a WeatherObject based on currentWeatherInformation */ generateWeatherObjectFromCurrentWeather(currentWeatherData) { - const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); // data times are always UTC let nowUtc = moment.utc(); @@ -124,7 +124,7 @@ WeatherProvider.register("ukmetoffice", { // loop round the (5) periods getting the data // for each period array, Day is [0], Night is [1] for (var j in forecasts.SiteRep.DV.Location.Period) { - const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); // data times are always UTC const dateStr = forecasts.SiteRep.DV.Location.Period[j].value; @@ -208,10 +208,10 @@ WeatherProvider.register("ukmetoffice", { }, /* - * Convert wind speed (from mph) if required + * Convert wind speed (from mph to m/s or km/h) if required */ convertWindSpeed(windInMph) { - return this.windUnits === "metric" ? windInMph * 2.23694 : windInMph; + return this.windUnits === "metric" ? (this.useKmh ? windInMph * 1.60934 : windInMph / 2.23694) : windInMph; }, /* diff --git a/modules/default/weather/providers/ukmetofficedatahub.js b/modules/default/weather/providers/ukmetofficedatahub.js index 505732d3..af2e09c6 100644 --- a/modules/default/weather/providers/ukmetofficedatahub.js +++ b/modules/default/weather/providers/ukmetofficedatahub.js @@ -108,7 +108,7 @@ WeatherProvider.register("ukmetofficedatahub", { // Create a WeatherObject using current weather data (data for the current hour) generateWeatherObjectFromCurrentWeather(currentWeatherData) { - const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); // Extract the actual forecasts let forecastDataHours = currentWeatherData.features[0].properties.timeSeries; @@ -189,7 +189,7 @@ WeatherProvider.register("ukmetofficedatahub", { // Go through each day in the forecasts for (day in forecastDataDays) { - const forecastWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + const forecastWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); // Get date of forecast let forecastDate = moment.utc(forecastDataDays[day].time); @@ -254,7 +254,7 @@ WeatherProvider.register("ukmetofficedatahub", { return windInMpS; } - if (this.config.windUnits == "kph" || this.config.windUnits == "metric") { + if (this.config.windUnits == "kph" || this.config.windUnits == "metric" || this.config.useKmh) { return windInMpS * 3.6; } diff --git a/modules/default/weather/providers/weatherbit.js b/modules/default/weather/providers/weatherbit.js new file mode 100644 index 00000000..6bd3508e --- /dev/null +++ b/modules/default/weather/providers/weatherbit.js @@ -0,0 +1,181 @@ +/* global WeatherProvider, WeatherObject */ + +/* Magic Mirror + * Module: Weather + * Provider: Weatherbit + * + * By Andrew Pometti + * MIT Licensed + * + * This class is a provider for Weatherbit, based on Nicholas Hubbard's class for Dark Sky & Vince Peri's class for Weather.gov. + */ +WeatherProvider.register("weatherbit", { + // Set the name of the provider. + // Not strictly required, but helps for debugging. + providerName: "Weatherbit", + + units: { + imperial: "I", + metric: "M" + }, + + fetchedLocation: function () { + return this.fetchedLocationName || ""; + }, + + fetchCurrentWeather() { + this.fetchData(this.getUrl()) + .then((data) => { + if (!data || !data.data[0] || typeof data.data[0].temp === "undefined") { + // No usable data? + return; + } + + const currentWeather = this.generateWeatherDayFromCurrentWeather(data); + this.setCurrentWeather(currentWeather); + }) + .catch(function (request) { + Log.error("Could not load data ... ", request); + }) + .finally(() => this.updateAvailable()); + }, + + fetchWeatherForecast() { + this.fetchData(this.getUrl()) + .then((data) => { + if (!data || !data.data) { + // No usable data? + return; + } + + const forecast = this.generateWeatherObjectsFromForecast(data.data); + this.setWeatherForecast(forecast); + + this.fetchedLocationName = data.city_name + ", " + data.state_code; + }) + .catch(function (request) { + Log.error("Could not load data ... ", request); + }) + .finally(() => this.updateAvailable()); + }, + + // Create a URL from the config and base URL. + getUrl() { + const units = this.units[this.config.units] || "auto"; + return `${this.config.apiBase}${this.config.weatherEndpoint}?lat=${this.config.lat}&lon=${this.config.lon}&units=${units}&key=${this.config.apiKey}`; + }, + + // Implement WeatherDay generator. + generateWeatherDayFromCurrentWeather(currentWeatherData) { + //Calculate TZ Offset and invert to convert Sunrise/Sunset times to Local + const d = new Date(); + let tzOffset = d.getTimezoneOffset(); + tzOffset = tzOffset * -1; + + const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + + currentWeather.date = moment(currentWeatherData.data[0].ts, "X"); + currentWeather.humidity = parseFloat(currentWeatherData.data[0].rh); + currentWeather.temperature = parseFloat(currentWeatherData.data[0].temp); + currentWeather.windSpeed = parseFloat(currentWeatherData.data[0].wind_spd); + currentWeather.windDirection = currentWeatherData.data[0].wind_dir; + currentWeather.weatherType = this.convertWeatherType(currentWeatherData.data[0].weather.icon); + Log.log("Wx Icon: " + currentWeatherData.data[0].weather.icon); + currentWeather.sunrise = moment(currentWeatherData.data[0].sunrise, "HH:mm").add(tzOffset, "m"); + currentWeather.sunset = moment(currentWeatherData.data[0].sunset, "HH:mm").add(tzOffset, "m"); + + this.fetchedLocationName = currentWeatherData.data[0].city_name + ", " + currentWeatherData.data[0].state_code; + + return currentWeather; + }, + + generateWeatherObjectsFromForecast(forecasts) { + const days = []; + + for (const forecast of forecasts) { + const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + + weather.date = moment(forecast.datetime, "YYYY-MM-DD"); + weather.minTemperature = forecast.min_temp; + weather.maxTemperature = forecast.max_temp; + weather.precipitation = forecast.precip; + weather.weatherType = this.convertWeatherType(forecast.weather.icon); + + days.push(weather); + } + + return days; + }, + + // Map icons from Dark Sky to our icons. + convertWeatherType(weatherType) { + const weatherTypes = { + t01d: "day-thunderstorm", + t01n: "night-alt-thunderstorm", + t02d: "day-thunderstorm", + t02n: "night-alt-thunderstorm", + t03d: "thunderstorm", + t03n: "thunderstorm", + t04d: "day-thunderstorm", + t04n: "night-alt-thunderstorm", + t05d: "day-sleet-storm", + t05n: "night-alt-sleet-storm", + d01d: "day-sprinkle", + d01n: "night-alt-sprinkle", + d02d: "day-sprinkle", + d02n: "night-alt-sprinkle", + d03d: "day-shower", + d03n: "night-alt-shower", + r01d: "day-shower", + r01n: "night-alt-shower", + r02d: "day-rain", + r02n: "night-alt-rain", + r03d: "day-rain", + r03n: "night-alt-rain", + r04d: "day-sprinkle", + r04n: "night-alt-sprinkle", + r05d: "day-shower", + r05n: "night-alt-shower", + r06d: "day-shower", + r06n: "night-alt-shower", + f01d: "day-sleet", + f01n: "night-alt-sleet", + s01d: "day-snow", + s01n: "night-alt-snow", + s02d: "day-snow-wind", + s02n: "night-alt-snow-wind", + s03d: "snowflake-cold", + s03n: "snowflake-cold", + s04d: "day-rain-mix", + s04n: "night-alt-rain-mix", + s05d: "day-sleet", + s05n: "night-alt-sleet", + s06d: "day-snow", + s06n: "night-alt-snow", + a01d: "day-haze", + a01n: "dust", + a02d: "smoke", + a02n: "smoke", + a03d: "day-haze", + a03n: "dust", + a04d: "dust", + a04n: "dust", + a05d: "day-fog", + a05n: "night-fog", + a06d: "fog", + a06n: "fog", + c01d: "day-sunny", + c01n: "night-clear", + c02d: "day-sunny-overcast", + c02n: "night-alt-partly-cloudy", + c03d: "day-cloudy", + c03n: "night-alt-cloudy", + c04d: "cloudy", + c04n: "cloudy", + u00d: "rain-mix", + u00n: "rain-mix" + }; + + return weatherTypes.hasOwnProperty(weatherType) ? weatherTypes[weatherType] : null; + } +}); diff --git a/modules/default/weather/providers/weathergov.js b/modules/default/weather/providers/weathergov.js index 1b28bba1..86837763 100755 --- a/modules/default/weather/providers/weathergov.js +++ b/modules/default/weather/providers/weathergov.js @@ -131,11 +131,11 @@ WeatherProvider.register("weathergov", { * ... object needs data in units based on config! */ generateWeatherObjectFromCurrentWeather(currentWeatherData) { - const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); currentWeather.date = moment(currentWeatherData.timestamp); currentWeather.temperature = this.convertTemp(currentWeatherData.temperature.value); - currentWeather.windSpeed = this.covertSpeed(currentWeatherData.windSpeed.value); + currentWeather.windSpeed = this.convertSpeed(currentWeatherData.windSpeed.value); currentWeather.windDirection = currentWeatherData.windDirection.value; currentWeather.minTemperature = this.convertTemp(currentWeatherData.minTemperatureLast24Hours.value); currentWeather.maxTemperature = this.convertTemp(currentWeatherData.maxTemperatureLast24Hours.value); @@ -179,7 +179,7 @@ WeatherProvider.register("weathergov", { let maxTemp = []; // variable for date let date = ""; - let weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + let weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); weather.precipitation = 0; for (const forecast of forecasts) { @@ -191,7 +191,7 @@ WeatherProvider.register("weathergov", { // push weather information to days array days.push(weather); // create new weather-object - weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits); + weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh); minTemp = []; maxTemp = []; @@ -238,12 +238,16 @@ WeatherProvider.register("weathergov", { return temp; } }, - // conversion to mph - covertSpeed(metSec) { + // conversion to mph or kmh + convertSpeed(metSec) { if (this.config.windUnits === "imperial") { return metSec * 2.23694; } else { - return metSec; + if (this.config.useKmh) { + return metSec * 3.6; + } else { + return metSec; + } } }, // conversion to inches diff --git a/modules/default/weather/weather.js b/modules/default/weather/weather.js index b5a68a52..73ee0e16 100644 --- a/modules/default/weather/weather.js +++ b/modules/default/weather/weather.js @@ -12,16 +12,14 @@ Module.register("weather", { weatherProvider: "openweathermap", roundTemp: false, type: "current", // current, forecast, daily (equivalent to forecast), hourly (only with OpenWeatherMap /onecall endpoint) - lat: 0, lon: 0, location: false, locationID: false, units: config.units, - + useKmh: false, tempUnits: config.units, windUnits: config.units, - updateInterval: 10 * 60 * 1000, // every 10 minutes animationSpeed: 1000, timeFormat: config.timeFormat, @@ -41,20 +39,16 @@ Module.register("weather", { maxEntries: 5, fade: true, fadePoint: 0.25, // Start on 1/4th of the list. - initialLoadDelay: 0, // 0 seconds delay retryDelay: 2500, - apiKey: "", apiSecret: "", apiVersion: "2.5", apiBase: "https://api.openweathermap.org/data/", // TODO: this should not be part of the weather.js file, but should be contained in the openweatherprovider weatherEndpoint: "/weather", - appendLocationNameToHeader: true, calendarClass: "calendar", tableClass: "small", - onlyTemp: false, showPrecipitationAmount: false, colored: false, diff --git a/modules/default/weather/weatherobject.js b/modules/default/weather/weatherobject.js index 0ee42123..3fbbb42a 100755 --- a/modules/default/weather/weatherobject.js +++ b/modules/default/weather/weatherobject.js @@ -10,10 +10,11 @@ * As soon as we start implementing the forecast, mode properties will be added. */ class WeatherObject { - constructor(units, tempUnits, windUnits) { + constructor(units, tempUnits, windUnits, useKmh) { this.units = units; this.tempUnits = tempUnits; this.windUnits = windUnits; + this.useKmh = useKmh; this.date = null; this.windSpeed = null; this.windDirection = null; @@ -67,7 +68,7 @@ class WeatherObject { } beaufortWindSpeed() { - const windInKmh = this.windUnits === "imperial" ? this.windSpeed * 1.609344 : (this.windSpeed * 60 * 60) / 1000; + const windInKmh = this.windUnits === "imperial" ? this.windSpeed * 1.609344 : this.useKmh ? this.windSpeed : (this.windSpeed * 60 * 60) / 1000; const speeds = [1, 5, 11, 19, 28, 38, 49, 61, 74, 88, 102, 117, 1000]; for (const [index, speed] of speeds.entries()) { if (speed > windInKmh) { @@ -77,6 +78,11 @@ class WeatherObject { return 12; } + kmhWindSpeed() { + const windInKmh = this.windUnits === "imperial" ? this.windSpeed * 1.609344 : (this.windSpeed * 60 * 60) / 1000; + return windInKmh; + } + nextSunAction() { return moment().isBetween(this.sunrise, this.sunset) ? "sunset" : "sunrise"; } diff --git a/package-lock.json b/package-lock.json index 4ca1cd13..5c0c466c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -569,13 +569,13 @@ } }, "@stylelint/postcss-markdown": { - "version": "0.36.1", - "resolved": "https://registry.npmjs.org/@stylelint/postcss-markdown/-/postcss-markdown-0.36.1.tgz", - "integrity": "sha512-iDxMBWk9nB2BPi1VFQ+Dc5+XpvODBHw2n3tYpaBZuEAFQlbtF9If0Qh5LTTwSi/XwdbJ2jt+0dis3i8omyggpw==", + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@stylelint/postcss-markdown/-/postcss-markdown-0.36.2.tgz", + "integrity": "sha512-2kGbqUVJUGE8dM+bMzXG/PYUWKkjLIkRLWNh39OaADkiabDRdw8ATFCgbMz5xdIcvwspPAluSL7uY+ZiTWdWmQ==", "dev": true, "requires": { - "remark": "^12.0.0", - "unist-util-find-all-after": "^3.0.1" + "remark": "^13.0.0", + "unist-util-find-all-after": "^3.0.2" } }, "@szmarczak/http-timer": { @@ -643,6 +643,15 @@ "@types/range-parser": "*" } }, + "@types/mdast": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.3.tgz", + "integrity": "sha512-SXPBMnFVQg1s00dlMCc/jCdvPqdE4mXaMMCeRlxLDmTAEoegHT53xKtkDnzDTOcmMHUfcjyf36/YYZ6SxRdnsw==", + "dev": true, + "requires": { + "@types/unist": "*" + } + }, "@types/mime": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", @@ -819,12 +828,16 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true }, "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + "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==", + "requires": { + "color-convert": "^1.9.0" + } }, "anymatch": { "version": "3.1.1", @@ -934,7 +947,8 @@ "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=" + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true }, "array-flatten": { "version": "1.1.1", @@ -1426,21 +1440,23 @@ "camelcase": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "dev": true }, "camelcase-keys": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "dev": true, "requires": { "camelcase": "^2.0.0", "map-obj": "^1.0.0" } }, "caniuse-lite": { - "version": "1.0.30001157", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001157.tgz", - "integrity": "sha512-gOerH9Wz2IRZ2ZPdMfBvyOi3cjaz4O4dgNwPGzx8EhqAs4+2IL/O+fJsbt+znSigujoZG8bVcIAUM/I/E5K3MA==", + "version": "1.0.30001161", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001161.tgz", + "integrity": "sha512-JharrCDxOqPLBULF9/SPa6yMcBRTjZARJ6sc3cuKrPfyIk64JN6kuMINWqA99Xc8uElMFcROliwtz0n9pYej+g==", "dev": true }, "caseless": { @@ -1448,12 +1464,6 @@ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, - "ccount": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.1.0.tgz", - "integrity": "sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==", - "dev": true - }, "chai": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", @@ -1478,15 +1488,13 @@ } }, "chalk": { - "version": "1.1.3", - "resolved": "https://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==", "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" } }, "character-entities": { @@ -1495,12 +1503,6 @@ "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", "dev": true }, - "character-entities-html4": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.4.tgz", - "integrity": "sha512-HRcDxZuZqMx3/a+qrzxdBKBPUpxWEq9xw2OPZ3a/174ihfrQKVsFhqtthBInFy1zZ9GgZyFXOatNujm8M+El3g==", - "dev": true - }, "character-entities-legacy": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", @@ -1683,12 +1685,6 @@ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, - "collapse-white-space": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz", - "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==", - "dev": true - }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", @@ -1756,10 +1752,9 @@ "dev": true }, "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", - "dev": true + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" }, "compress-commons": { "version": "1.2.2", @@ -1811,13 +1806,12 @@ } }, "console-stamp": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/console-stamp/-/console-stamp-0.2.9.tgz", - "integrity": "sha512-jtgd1Fx3Im+pWN54mF269ptunkzF5Lpct2LBTbtyNoK2A4XjcxLM+TQW+e+XE/bLwLQNGRqPqlxm9JMixFntRA==", + "version": "3.0.0-rc4.2", + "resolved": "https://registry.npmjs.org/console-stamp/-/console-stamp-3.0.0-rc4.2.tgz", + "integrity": "sha512-ncGYdZsfDbBYYiaPXr9NHfZbSSkoVzYyh8nHji9/3ovw35Jn4ozo0btcirtfIznXT4xNgBQW+IyTVLISnNumdQ==", "requires": { - "chalk": "^1.1.1", - "dateformat": "^1.0.11", - "merge": "^1.2.0" + "chalk": "^2.4.2", + "dateformat": "^3.0.3" } }, "content-disposition": { @@ -2008,14 +2002,15 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true, "requires": { "array-find-index": "^1.0.1" } }, "danger": { - "version": "10.5.1", - "resolved": "https://registry.npmjs.org/danger/-/danger-10.5.1.tgz", - "integrity": "sha512-M+SnvfD4VKSXwXMRGYR0KPtdl8jYmWqHIlqw1vwB/oTikjCi0nwXFJ7Nw/H3lCPY5NgXDFfJ7UHf8cR7kLNBlQ==", + "version": "10.5.3", + "resolved": "https://registry.npmjs.org/danger/-/danger-10.5.3.tgz", + "integrity": "sha512-64ZjkDQNhQNDfUWOyEG9VgT1yjIY0q5dN5K1ocWrZ5whOySN5GjBX4CxaFrY1+HgQldCXCMSp6Xq+3+vFbUt4g==", "dev": true, "requires": { "@babel/polyfill": "^7.2.5", @@ -2141,13 +2136,9 @@ } }, "dateformat": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", - "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", - "requires": { - "get-stdin": "^4.0.1", - "meow": "^3.3.0" - } + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==" }, "debug": { "version": "4.2.0", @@ -2160,7 +2151,8 @@ "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true }, "decamelize-keys": { "version": "1.1.0", @@ -2556,9 +2548,9 @@ } }, "electron-to-chromium": { - "version": "1.3.592", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.592.tgz", - "integrity": "sha512-kGNowksvqQiPb1pUSQKpd8JFoGPLxYOwduNRCqCxGh/2Q1qE2JdmwouCW41lUzDxOb/2RIV4lR0tVIfboWlO9A==", + "version": "1.3.606", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.606.tgz", + "integrity": "sha512-+/2yPHwtNf6NWKpaYt0KoqdSZ6Qddt6nDfH/pnhcrHq9hSb23e5LFy06Mlf0vF2ykXvj7avJ597psqcbKnG5YQ==", "dev": true }, "emoji-regex": { @@ -2637,6 +2629,7 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, "requires": { "is-arrayish": "^0.2.1" } @@ -2866,9 +2859,9 @@ } }, "eslint-plugin-jsdoc": { - "version": "30.7.7", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-30.7.7.tgz", - "integrity": "sha512-DmVMJC2AbpYX7X1KhnVT1a9ex1AUvG+q9G8i6hzjp3cpjW8vmKQTUmZnRS0//W+7HvMqeb+eXPANdCOzGVVZBQ==", + "version": "30.7.8", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-30.7.8.tgz", + "integrity": "sha512-OWm2AYvXjCl7nRbpcw5xisfSVkpVAyp4lGqL9T+DeK4kaPm6ecnmTc/G5s1PtcRrwbaI8bIWGzwScqv5CdGyxA==", "dev": true, "requires": { "comment-parser": "^0.7.6", @@ -3554,6 +3547,7 @@ "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" @@ -3683,7 +3677,8 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true }, "functional-red-black-tree": { "version": "1.0.1", @@ -3726,7 +3721,8 @@ "get-stdin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=" + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true }, "get-stream": { "version": "4.1.0", @@ -4019,6 +4015,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, "requires": { "function-bind": "^1.1.1" } @@ -4121,7 +4118,8 @@ "hosted-git-info": { "version": "2.8.8", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==" + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true }, "html-encoding-sniffer": { "version": "2.0.1", @@ -4244,9 +4242,9 @@ }, "dependencies": { "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { "ms": "^2.1.1" @@ -4402,6 +4400,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true, "requires": { "repeating": "^2.0.0" } @@ -4556,12 +4555,6 @@ "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", "dev": true }, - "is-alphanumeric": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-alphanumeric/-/is-alphanumeric-1.0.0.tgz", - "integrity": "sha1-Spzvcdr0wAHB2B1j0UDPU/1oifQ=", - "dev": true - }, "is-alphanumerical": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", @@ -4575,7 +4568,8 @@ "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true }, "is-binary-path": { "version": "2.1.0", @@ -4596,6 +4590,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.1.0.tgz", "integrity": "sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==", + "dev": true, "requires": { "has": "^1.0.3" } @@ -4659,7 +4654,8 @@ "is-finite": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", - "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==" + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", + "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", @@ -4738,12 +4734,7 @@ "is-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" - }, - "is-whitespace-character": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz", - "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", "dev": true }, "is-windows": { @@ -4752,12 +4743,6 @@ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true }, - "is-word-character": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz", - "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==", - "dev": true - }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -5128,9 +5113,9 @@ "dev": true }, "known-css-properties": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.19.0.tgz", - "integrity": "sha512-eYboRV94Vco725nKMlpkn3nV2+96p9c3gKXRsYqAJSswSENvBhN7n5L+uDhY58xQa0UukWsDMTGELzmD8Q+wTA==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.20.0.tgz", + "integrity": "sha512-URvsjaA9ypfreqJ2/ylDr5MUERhJZ+DhguoWRr2xgS5C7aGCalXo+ewL+GixgKBfhT2vuL02nbIgNGqVWgTOYw==", "dev": true }, "ky": { @@ -5183,6 +5168,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, "requires": { "graceful-fs": "^4.1.2", "parse-json": "^2.2.0", @@ -5377,6 +5363,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, "requires": { "currently-unhandled": "^0.4.1", "signal-exit": "^3.0.0" @@ -5392,6 +5379,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, "requires": { "yallist": "^4.0.0" } @@ -5434,7 +5422,8 @@ "map-obj": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=" + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true }, "map-visit": { "version": "1.0.0", @@ -5445,21 +5434,6 @@ "object-visit": "^1.0.0" } }, - "markdown-escapes": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz", - "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==", - "dev": true - }, - "markdown-table": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", - "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==", - "dev": true, - "requires": { - "repeat-string": "^1.0.0" - } - }, "matcher": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", @@ -5483,15 +5457,46 @@ "integrity": "sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==", "dev": true }, - "mdast-util-compact": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-compact/-/mdast-util-compact-2.0.1.tgz", - "integrity": "sha512-7GlnT24gEwDrdAwEHrU4Vv5lLWrEer4KOkAiKT9nYstsTad7Oc1TwqT2zIMKRdZF7cTuaf+GA1E4Kv7jJh8mPA==", + "mdast-util-from-markdown": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.1.tgz", + "integrity": "sha512-qJXNcFcuCSPqUF0Tb0uYcFDIq67qwB3sxo9RPdf9vG8T90ViKnksFqdB/Coq2a7sTnxL/Ify2y7aIQXDkQFH0w==", "dev": true, "requires": { - "unist-util-visit": "^2.0.0" + "@types/mdast": "^3.0.0", + "mdast-util-to-string": "^1.0.0", + "micromark": "~2.10.0", + "parse-entities": "^2.0.0" } }, + "mdast-util-to-markdown": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.5.4.tgz", + "integrity": "sha512-0jQTkbWYx0HdEA/h++7faebJWr5JyBoBeiRf0u3F4F3QtnyyGaWIsOwo749kRb1ttKrLLr+wRtOkfou9yB0p6A==", + "dev": true, + "requires": { + "@types/unist": "^2.0.0", + "longest-streak": "^2.0.0", + "mdast-util-to-string": "^2.0.0", + "parse-entities": "^2.0.0", + "repeat-string": "^1.0.0", + "zwitch": "^1.0.0" + }, + "dependencies": { + "mdast-util-to-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", + "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==", + "dev": true + } + } + }, + "mdast-util-to-string": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-1.1.0.tgz", + "integrity": "sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A==", + "dev": true + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -5510,6 +5515,7 @@ "version": "3.7.0", "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "dev": true, "requires": { "camelcase-keys": "^2.0.0", "decamelize": "^1.1.2", @@ -5523,11 +5529,6 @@ "trim-newlines": "^1.0.0" } }, - "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", @@ -5550,6 +5551,16 @@ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" }, + "micromark": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-2.10.1.tgz", + "integrity": "sha512-fUuVF8sC1X7wsCS29SYQ2ZfIZYbTymp0EYr6sab3idFjigFFjGa5UwoniPlV9tAgntjuapW1t9U+S0yDYeGKHQ==", + "dev": true, + "requires": { + "debug": "^4.0.0", + "parse-entities": "^2.0.0" + } + }, "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", @@ -5922,15 +5933,16 @@ } }, "node-releases": { - "version": "1.1.66", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.66.tgz", - "integrity": "sha512-JHEQ1iWPGK+38VLB2H9ef2otU4l8s3yAMt9Xf934r6+ojCYDMHPMqvCc9TnzfeFSP1QEOeU6YZEd3+De0LTCgg==", + "version": "1.1.67", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.67.tgz", + "integrity": "sha512-V5QF9noGFl3EymEwUYzO+3NTDpGfQB4ve6Qfnzf3UNydMhjQRVPR1DZTuvWiLzaFJYw2fmDwAfnRNEVb64hSIg==", "dev": true }, "normalize-package-data": { "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", "resolve": "^1.10.0", @@ -6501,6 +6513,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, "requires": { "error-ex": "^1.2.0" } @@ -6541,6 +6554,7 @@ "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" } @@ -6558,7 +6572,8 @@ "path-parse": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true }, "path-to-regexp": { "version": "0.1.7", @@ -6569,6 +6584,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, "requires": { "graceful-fs": "^4.1.2", "pify": "^2.0.0", @@ -6600,17 +6616,20 @@ "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true }, "pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true }, "pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, "requires": { "pinkie": "^2.0.0" } @@ -6816,9 +6835,9 @@ "optional": true }, "prettier": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.2.tgz", - "integrity": "sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.0.tgz", + "integrity": "sha512-yYerpkvseM4iKD/BXLYUkQV5aKt4tQPqaGW6EsZjzyu0r7sVZZNPJW4Y8MyKmicp6t42XUPcBVA+H6sB3gqndw==", "dev": true }, "prettier-linter-helpers": { @@ -7150,6 +7169,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, "requires": { "load-json-file": "^1.0.0", "normalize-package-data": "^2.3.2", @@ -7160,6 +7180,7 @@ "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" @@ -7198,6 +7219,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "dev": true, "requires": { "indent-string": "^2.1.0", "strip-indent": "^1.0.1" @@ -7240,60 +7262,32 @@ } }, "remark": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/remark/-/remark-12.0.1.tgz", - "integrity": "sha512-gS7HDonkdIaHmmP/+shCPejCEEW+liMp/t/QwmF0Xt47Rpuhl32lLtDV1uKWvGoq+kxr5jSgg5oAIpGuyULjUw==", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/remark/-/remark-13.0.0.tgz", + "integrity": "sha512-HDz1+IKGtOyWN+QgBiAT0kn+2s6ovOxHyPAFGKVE81VSzJ+mq7RwHFledEvB5F1p4iJvOah/LOKdFuzvRnNLCA==", "dev": true, "requires": { - "remark-parse": "^8.0.0", - "remark-stringify": "^8.0.0", - "unified": "^9.0.0" + "remark-parse": "^9.0.0", + "remark-stringify": "^9.0.0", + "unified": "^9.1.0" } }, "remark-parse": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-8.0.3.tgz", - "integrity": "sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-9.0.0.tgz", + "integrity": "sha512-geKatMwSzEXKHuzBNU1z676sGcDcFoChMK38TgdHJNAYfFtsfHDQG7MoJAjs6sgYMqyLduCYWDIWZIxiPeafEw==", "dev": true, "requires": { - "ccount": "^1.0.0", - "collapse-white-space": "^1.0.2", - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-whitespace-character": "^1.0.0", - "is-word-character": "^1.0.0", - "markdown-escapes": "^1.0.0", - "parse-entities": "^2.0.0", - "repeat-string": "^1.5.4", - "state-toggle": "^1.0.0", - "trim": "0.0.1", - "trim-trailing-lines": "^1.0.0", - "unherit": "^1.0.4", - "unist-util-remove-position": "^2.0.0", - "vfile-location": "^3.0.0", - "xtend": "^4.0.1" + "mdast-util-from-markdown": "^0.8.0" } }, "remark-stringify": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-8.1.1.tgz", - "integrity": "sha512-q4EyPZT3PcA3Eq7vPpT6bIdokXzFGp9i85igjmhRyXWmPs0Y6/d2FYwUNotKAWyLch7g0ASZJn/KHHcHZQ163A==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-9.0.0.tgz", + "integrity": "sha512-8x29DpTbVzEc6Dwb90qhxCtbZ6hmj3BxWWDpMhA+1WM4dOEGH5U5/GFe3Be5Hns5MvPSFAr1e2KSVtKZkK5nUw==", "dev": true, "requires": { - "ccount": "^1.0.0", - "is-alphanumeric": "^1.0.0", - "is-decimal": "^1.0.0", - "is-whitespace-character": "^1.0.0", - "longest-streak": "^2.0.1", - "markdown-escapes": "^1.0.0", - "markdown-table": "^2.0.0", - "mdast-util-compact": "^2.0.0", - "parse-entities": "^2.0.0", - "repeat-string": "^1.5.4", - "state-toggle": "^1.0.0", - "stringify-entities": "^3.0.0", - "unherit": "^1.0.4", - "xtend": "^4.0.1" + "mdast-util-to-markdown": "^0.5.0" } }, "remove-trailing-separator": { @@ -7318,6 +7312,7 @@ "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" } @@ -7409,6 +7404,7 @@ "version": "1.18.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz", "integrity": "sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA==", + "dev": true, "requires": { "is-core-module": "^2.0.0", "path-parse": "^1.0.6" @@ -7593,7 +7589,8 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true }, "semver-compare": { "version": "1.0.0", @@ -7736,7 +7733,8 @@ "signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true }, "simple-git": { "version": "2.24.0", @@ -8052,6 +8050,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" @@ -8060,12 +8059,14 @@ "spdx-exceptions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true }, "spdx-expression-parse": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, "requires": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -8074,7 +8075,8 @@ "spdx-license-ids": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz", - "integrity": "sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==" + "integrity": "sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==", + "dev": true }, "specificity": { "version": "0.4.1", @@ -8147,12 +8149,6 @@ "tweetnacl": "~0.14.0" } }, - "state-toggle": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz", - "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==", - "dev": true - }, "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", @@ -8224,21 +8220,11 @@ "safe-buffer": "~5.1.0" } }, - "stringify-entities": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-3.1.0.tgz", - "integrity": "sha512-3FP+jGMmMV/ffZs86MoghGqAoqXAdxLrJP4GUdrDN1aIScYih5tuIO3eF4To5AJZ79KDZ8Fpdy7QJnK8SsL1Vg==", - "dev": true, - "requires": { - "character-entities-html4": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "xtend": "^4.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" } @@ -8247,6 +8233,7 @@ "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" } @@ -8267,6 +8254,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "dev": true, "requires": { "get-stdin": "^4.0.1" } @@ -8283,22 +8271,22 @@ "dev": true }, "stylelint": { - "version": "13.7.2", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-13.7.2.tgz", - "integrity": "sha512-mmieorkfmO+ZA6CNDu1ic9qpt4tFvH2QUB7vqXgrMVHe5ENU69q7YDq0YUg/UHLuCsZOWhUAvcMcLzLDIERzSg==", + "version": "13.8.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-13.8.0.tgz", + "integrity": "sha512-iHH3dv3UI23SLDrH4zMQDjLT9/dDIz/IpoFeuNxZmEx86KtfpjDOscxLTFioQyv+2vQjPlRZnK0UoJtfxLICXQ==", "dev": true, "requires": { "@stylelint/postcss-css-in-js": "^0.37.2", - "@stylelint/postcss-markdown": "^0.36.1", + "@stylelint/postcss-markdown": "^0.36.2", "autoprefixer": "^9.8.6", "balanced-match": "^1.0.0", "chalk": "^4.1.0", "cosmiconfig": "^7.0.0", - "debug": "^4.1.1", + "debug": "^4.2.0", "execall": "^2.0.0", "fast-glob": "^3.2.4", "fastest-levenshtein": "^1.0.12", - "file-entry-cache": "^5.0.1", + "file-entry-cache": "^6.0.0", "get-stdin": "^8.0.0", "global-modules": "^2.0.0", "globby": "^11.0.1", @@ -8307,14 +8295,14 @@ "ignore": "^5.1.8", "import-lazy": "^4.0.0", "imurmurhash": "^0.1.4", - "known-css-properties": "^0.19.0", + "known-css-properties": "^0.20.0", "lodash": "^4.17.20", "log-symbols": "^4.0.0", "mathml-tag-names": "^2.1.3", - "meow": "^7.1.1", + "meow": "^8.0.0", "micromatch": "^4.0.2", "normalize-selector": "^0.2.0", - "postcss": "^7.0.32", + "postcss": "^7.0.35", "postcss-html": "^0.36.0", "postcss-less": "^3.1.4", "postcss-media-query-parser": "^0.2.3", @@ -8322,7 +8310,7 @@ "postcss-safe-parser": "^4.0.2", "postcss-sass": "^0.4.4", "postcss-scss": "^2.1.1", - "postcss-selector-parser": "^6.0.2", + "postcss-selector-parser": "^6.0.4", "postcss-syntax": "^0.36.2", "postcss-value-parser": "^4.1.0", "resolve-from": "^5.0.0", @@ -8333,8 +8321,8 @@ "style-search": "^0.1.0", "sugarss": "^2.0.0", "svg-tags": "^1.0.0", - "table": "^6.0.1", - "v8-compile-cache": "^2.1.1", + "table": "^6.0.3", + "v8-compile-cache": "^2.2.0", "write-file-atomic": "^3.0.3" }, "dependencies": { @@ -8416,6 +8404,15 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "file-entry-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.0.tgz", + "integrity": "sha512-fqoO76jZ3ZnYrXLDRxBR1YvOvc0k844kcOg40bgsPrE25LAb/PDqTY+ho64Xh2c8ZXgIKldchCFHczG2UVRcWA==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -8435,6 +8432,22 @@ "path-exists": "^4.0.0" } }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.0.tgz", + "integrity": "sha512-tW+UkmtNg/jv9CSofAKvgVcO7c2URjhTdW1ZTkcAritblu8tajiYy7YisnIflEwtKssCtOxpnBRoCB7iap0/TA==", + "dev": true + }, "get-stdin": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", @@ -8447,6 +8460,15 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "hosted-git-info": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.7.tgz", + "integrity": "sha512-fWqc0IcuXs+BmE9orLDyVykAG9GJtGLGuZAAqgcckPgv5xad4AcXGIv8galtQvlwutxSlaMcdw7BUtq2EIvqCQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, "ignore": { "version": "5.1.8", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", @@ -8478,9 +8500,9 @@ "dev": true }, "meow": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/meow/-/meow-7.1.1.tgz", - "integrity": "sha512-GWHvA5QOcS412WCo8vwKDlTelGLsCGBVevQB5Kva961rmNfun0PCbv5+xta2kUMFJyR8/oWnn7ddeKdosbAPbA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-8.0.0.tgz", + "integrity": "sha512-nbsTRz2fwniJBFgUkcdISq8y/q9n9VbiHYbfwklFh5V4V2uAcxtKQkDc0yCLPM/kP0d+inZBewn3zJqewHE7kg==", "dev": true, "requires": { "@types/minimist": "^1.2.0", @@ -8488,12 +8510,12 @@ "decamelize-keys": "^1.1.0", "hard-rejection": "^2.1.0", "minimist-options": "4.1.0", - "normalize-package-data": "^2.5.0", + "normalize-package-data": "^3.0.0", "read-pkg-up": "^7.0.1", "redent": "^3.0.0", "trim-newlines": "^3.0.0", - "type-fest": "^0.13.1", - "yargs-parser": "^18.1.3" + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" } }, "micromatch": { @@ -8506,6 +8528,18 @@ "picomatch": "^2.0.5" } }, + "normalize-package-data": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.0.tgz", + "integrity": "sha512-6lUjEI0d3v6kFrtgA/lOx4zHCWULXsFNIjHolnZCKCTLA6m/G625cdn3O7eNmT0iD3jfo6HZ9cdImGZwf21prw==", + "dev": true, + "requires": { + "hosted-git-info": "^3.0.6", + "resolve": "^1.17.0", + "semver": "^7.3.2", + "validate-npm-package-license": "^3.0.1" + } + }, "parse-json": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", @@ -8536,6 +8570,30 @@ "type-fest": "^0.6.0" }, "dependencies": { + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + }, + "normalize-package-data": { + "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", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, "type-fest": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", @@ -8579,6 +8637,21 @@ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + }, "slice-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", @@ -8629,9 +8702,9 @@ } }, "table": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/table/-/table-6.0.3.tgz", - "integrity": "sha512-8321ZMcf1B9HvVX/btKv8mMZahCjn2aYrDlpqHaBFCfnox64edeH9kEid0vTLTRR8gWR2A20aDgeuTTea4sVtw==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/table/-/table-6.0.4.tgz", + "integrity": "sha512-sBT4xRLdALd+NFBvwOz8bw4b15htyythha+q+DVZqy2RS08PPC8O2sZFgJYEY7bJvbCFKccs+WIZ/cd+xxTWCw==", "dev": true, "requires": { "ajv": "^6.12.4", @@ -8655,15 +8728,17 @@ "integrity": "sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA==", "dev": true }, + "type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true + }, "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true } } }, @@ -8716,9 +8791,12 @@ } }, "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } }, "supports-hyperlinks": { "version": "1.0.1", @@ -8964,21 +9042,10 @@ "punycode": "^2.1.0" } }, - "trim": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", - "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=", - "dev": true - }, "trim-newlines": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=" - }, - "trim-trailing-lines": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz", - "integrity": "sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", "dev": true }, "trough": { @@ -9037,7 +9104,8 @@ "type-fest": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", - "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==" + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", + "optional": true }, "type-is": { "version": "1.6.18", @@ -9062,16 +9130,6 @@ "is-typedarray": "^1.0.0" } }, - "unherit": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz", - "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==", - "dev": true, - "requires": { - "inherits": "^2.0.0", - "xtend": "^4.0.0" - } - }, "unified": { "version": "9.2.0", "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz", @@ -9127,15 +9185,6 @@ "integrity": "sha512-bTofCFVx0iQM8Jqb1TBDVRIQW03YkD3p66JOd/aCWuqzlLyUtx1ZAGw/u+Zw+SttKvSVcvTiKYbfrtLoLefykw==", "dev": true }, - "unist-util-remove-position": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz", - "integrity": "sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==", - "dev": true, - "requires": { - "unist-util-visit": "^2.0.0" - } - }, "unist-util-stringify-position": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", @@ -9145,27 +9194,6 @@ "@types/unist": "^2.0.2" } }, - "unist-util-visit": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz", - "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", - "dev": true, - "requires": { - "@types/unist": "^2.0.0", - "unist-util-is": "^4.0.0", - "unist-util-visit-parents": "^3.0.0" - } - }, - "unist-util-visit-parents": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", - "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", - "dev": true, - "requires": { - "@types/unist": "^2.0.0", - "unist-util-is": "^4.0.0" - } - }, "universal-url": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universal-url/-/universal-url-2.0.0.tgz", @@ -9317,6 +9345,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, "requires": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" @@ -9358,12 +9387,6 @@ } } }, - "vfile-location": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-3.2.0.tgz", - "integrity": "sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==", - "dev": true - }, "vfile-message": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", @@ -9796,6 +9819,12 @@ "lodash": "^4.8.0", "readable-stream": "^2.0.0" } + }, + "zwitch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", + "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==", + "dev": true } } } diff --git a/package.json b/package.json index 7234b7f9..3c19299e 100644 --- a/package.json +++ b/package.json @@ -44,9 +44,9 @@ "devDependencies": { "chai": "^4.2.0", "chai-as-promised": "^7.1.1", - "danger": "^10.5.1", + "danger": "^10.5.3", "eslint-config-prettier": "^6.15.0", - "eslint-plugin-jsdoc": "^30.7.7", + "eslint-plugin-jsdoc": "^30.7.8", "eslint-plugin-prettier": "^3.1.4", "express-basic-auth": "^1.2.0", "husky": "^4.3.0", @@ -56,10 +56,10 @@ "mocha-each": "^2.0.1", "mocha-logger": "^1.0.7", "nyc": "^15.1.0", - "prettier": "^2.1.2", + "prettier": "^2.2.0", "pretty-quick": "^3.1.0", "spectron": "^10.0.1", - "stylelint": "^13.7.2", + "stylelint": "^13.8.0", "stylelint-config-prettier": "^8.0.2", "stylelint-config-standard": "^20.0.0", "stylelint-prettier": "^1.1.2" @@ -69,7 +69,7 @@ }, "dependencies": { "colors": "^1.4.0", - "console-stamp": "^0.2.9", + "console-stamp": "^3.0.0-rc4.2", "electron": "^8.5.3", "eslint": "^7.14.0", "express": "^4.17.1", diff --git a/tests/configs/modules/calendar/custom.js b/tests/configs/modules/calendar/custom.js index 2084419d..7bbeb602 100644 --- a/tests/configs/modules/calendar/custom.js +++ b/tests/configs/modules/calendar/custom.js @@ -22,11 +22,11 @@ let config = { config: { calendars: [ { + maximumEntries: 4, + maximumNumberOfDays: 10000, symbol: "birthday-cake", fullDaySymbol: "calendar-day", recurringSymbol: "undo", - maximumEntries: 4, - maximumNumberOfDays: 10000, url: "http://localhost:8080/tests/configs/data/calendar_test_icons.ics" } ] diff --git a/translations/lt.json b/translations/lt.json index 87fbd791..0ab64c3c 100644 --- a/translations/lt.json +++ b/translations/lt.json @@ -9,28 +9,28 @@ "WEEK": "{weekNumber} savaitė", - "N": "N", - "NNE": "NNE", - "NE": "NE", - "ENE": "ENE", - "E": "E", - "ESE": "ESE", - "SE": "SE", - "SSE": "SSE", - "S": "S", - "SSW": "SSW", - "SW": "SW", - "WSW": "WSW", - "W": "W", - "WNW": "WNW", - "NW": "NW", - "NNW": "NNW", + "N": "Š", + "NNE": "ŠŠR", + "NE": "ŠR", + "ENE": "RŠR", + "E": "R", + "ESE": "RPR", + "SE": "PR", + "SSE": "PPR", + "S": "P", + "SSW": "PPV", + "SW": "PV", + "WSW": "VPV", + "W": "V", + "WNW": "VŠV", + "NW": "ŠV", + "NNW": "ŠŠV", "UPDATE_NOTIFICATION": "Galimas MagicMirror² naujinimas.", "UPDATE_NOTIFICATION_MODULE": "Galimas {MODULE_NAME} naujinimas.", "UPDATE_INFO_SINGLE": "Šis įdiegimas atsilieka {COMMIT_COUNT} įsipareigojimu {BRANCH_NAME} šakoje.", "UPDATE_INFO_MULTIPLE": "Šis įdiegimas atsilieka {COMMIT_COUNT} įsipareigojimais {BRANCH_NAME} šakoje.", - "FEELS": "Jaučiasi kaip", + "FEELS": "Jutiminė temp.", "PRECIP": "Krituliai" } diff --git a/translations/ps.json b/translations/ps.json new file mode 100644 index 00000000..f3f8a638 --- /dev/null +++ b/translations/ps.json @@ -0,0 +1,37 @@ +{ + "LOADING": "پیلېدل", + + "TODAY": "نن", + "TOMORROW": "سبا", + "DAYAFTERTOMORROW": "بل سبا", + "RUNNING": "روان", + "EMPTY": "تش", + + "WEEK": "{weekNumber}. اونۍ", + + "N": "N", + "NNE": "NNO", + "NE": "NO", + "ENE": "ONO", + "E": "O", + "ESE": "OSO", + "SE": "SO", + "SSE": "SSO", + "S": "S", + "SSW": "SSW", + "SW": "SW", + "WSW": "WSW", + "W": "W", + "WNW": "WNW", + "NW": "NW", + "NNW": "NNW", + + "MODULE_CONFIG_CHANGED": "د {MODULE_NAME} بڼی تغیر کړی دی. \n هیله دی چی اسناد و ګوری!", + + "UPDATE_NOTIFICATION": "د MagicMirror² نوې نسخه سته ", + "UPDATE_NOTIFICATION_MODULE": "د {MODULE_NAME} نوی نسخه سته", + "UPDATE_INFO_SINGLE": "اوسنی برخه {COMMIT_COUNT} د {BRANCH_NAME} څخه وروسته پاته ده", + "UPDATE_INFO_MULTIPLE": "اوسنی برخه {COMMIT_COUNT} د {BRANCH_NAME} څخه وروسته پاته ده", + + "FEELS": "حس کېږی" +} diff --git a/vendor/package-lock.json b/vendor/package-lock.json index adc372bc..3159313f 100644 --- a/vendor/package-lock.json +++ b/vendor/package-lock.json @@ -4,9 +4,9 @@ "lockfileVersion": 1, "dependencies": { "@fortawesome/fontawesome-free": { - "version": "5.14.0", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.14.0.tgz", - "integrity": "sha512-OfdMsF+ZQgdKHP9jUbmDcRrP0eX90XXrsXIdyjLbkmSBzmMXPABB8eobUJtivaupucYaByz6WNe1PI1JuYm3qA==" + "version": "5.15.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.1.tgz", + "integrity": "sha512-OEdH7SyC1suTdhBGW91/zBfR6qaIhThbcN8PUXtXilY4GYnSBbVqOntdHbC1vXwsDnX0Qix2m2+DSU1J51ybOQ==" }, "a-sync-waterfall": { "version": "1.0.1", @@ -119,14 +119,14 @@ "optional": true }, "moment": { - "version": "2.28.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.28.0.tgz", - "integrity": "sha512-Z5KOjYmnHyd/ukynmFd/WwyXHd7L4J9vTI/nn5Ap9AVUgaAE15VvQ9MOGmJJygEUklupqIrFnor/tjTwRU+tQw==" + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" }, "moment-timezone": { - "version": "0.5.31", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.31.tgz", - "integrity": "sha512-+GgHNg8xRhMXfEbv81iDtrVeTcWt0kWmTEY1XQK14dICTXnWJnT0dxdlPspwqF3keKMVPXwayEsk1DI0AA/jdA==", + "version": "0.5.32", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.32.tgz", + "integrity": "sha512-Z8QNyuQHQAmWucp8Knmgei8YNo28aLjJq6Ma+jy1ZSpSk5nyfRT8xgUbSQvD2+2UajISfenndwvFuH3NGS+nvA==", "requires": { "moment": ">= 2.9.0" } diff --git a/vendor/package.json b/vendor/package.json index 2de60b52..5f7c18c7 100755 --- a/vendor/package.json +++ b/vendor/package.json @@ -10,9 +10,9 @@ "url": "https://github.com/MichMich/MagicMirror/issues" }, "dependencies": { - "@fortawesome/fontawesome-free": "^5.14.0", - "moment": "^2.28.0", - "moment-timezone": "^0.5.31", + "@fortawesome/fontawesome-free": "^5.15.1", + "moment": "^2.29.1", + "moment-timezone": "^0.5.32", "nunjucks": "^3.2.2", "suncalc": "^1.8.0", "weathericons": "^2.1.0"