summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaphael <raphaelkabo@hey.com>2023-05-12 17:03:13 +0100
committerGitHub <noreply@github.com>2023-05-12 17:03:13 +0100
commit67cf89fd0cfdf56c7e6d6d9bdf93d95d679ce2a1 (patch)
treec66bdf874a210997cd1d84942101773ba0175b20
parenta75aad783c117aaef2ec19b6b434be0f0d7e57de (diff)
parent50688f573054f60aa7594672615f11713173c147 (diff)
Merge pull request #95 from lowercasename/typescript
Migrate to TypeScript and PNPM
-rw-r--r--.dockerignore1
-rw-r--r--.eslintrc.json33
-rwxr-xr-x.gitignore7
-rw-r--r--.nvmrc2
-rw-r--r--.prettierignore4
-rw-r--r--.prettierrc.json1
-rw-r--r--.travis.yml4
-rw-r--r--Dockerfile12
-rw-r--r--FEDERATION.md30
-rw-r--r--activitypub.js941
-rwxr-xr-xapp.js54
-rw-r--r--config/api-example.js8
-rw-r--r--config/database-docker.js3
-rw-r--r--config/database-example.js3
-rw-r--r--config/domain-example.js13
-rw-r--r--docker-compose.yml24
-rw-r--r--package-lock.json7925
-rw-r--r--package.json49
-rw-r--r--pnpm-lock.yaml2916
-rwxr-xr-xroutes.js1976
-rw-r--r--src/activitypub.js1283
-rwxr-xr-xsrc/app.js53
-rw-r--r--src/config/api-example.js8
-rw-r--r--src/config/database-docker.js3
-rw-r--r--src/config/database-example.js3
-rw-r--r--src/config/domain-example.js13
-rw-r--r--src/config/gathio.service (renamed from config/gathio.service)0
-rw-r--r--src/helpers.js (renamed from helpers.js)30
-rwxr-xr-xsrc/models/Event.js (renamed from models/Event.js)157
-rwxr-xr-xsrc/models/EventGroup.js (renamed from models/EventGroup.js)28
-rwxr-xr-xsrc/models/Log.js (renamed from models/Log.js)14
-rwxr-xr-xsrc/routes.js2853
-rwxr-xr-xsrc/start.js38
-rwxr-xr-xstart.js32
-rw-r--r--tsconfig.json22
35 files changed, 7397 insertions, 11146 deletions
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..b512c09
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1 @@
+node_modules \ No newline at end of file
diff --git a/.eslintrc.json b/.eslintrc.json
index f1e3d15..d3fb99f 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -1,18 +1,17 @@
{
- "env": {
- "browser": true,
- "es6": true,
- "node": true
- },
- "extends": "eslint:recommended",
- "globals": {
- "Atomics": "readonly",
- "SharedArrayBuffer": "readonly"
- },
- "parserOptions": {
- "ecmaVersion": 2018,
- "sourceType": "module"
- },
- "rules": {
- }
-} \ No newline at end of file
+ "env": {
+ "browser": true,
+ "es6": true,
+ "node": true
+ },
+ "extends": "eslint:recommended",
+ "globals": {
+ "Atomics": "readonly",
+ "SharedArrayBuffer": "readonly"
+ },
+ "parserOptions": {
+ "ecmaVersion": 2018,
+ "sourceType": "module"
+ },
+ "rules": {}
+}
diff --git a/.gitignore b/.gitignore
index 16d3fa8..763f664 100755
--- a/.gitignore
+++ b/.gitignore
@@ -2,9 +2,10 @@
# gathio custom
-config/api.js
-config/database.js
-config/domain.js
+dist
+src/config/api.js
+src/config/database.js
+src/config/domain.js
public/events/*
!public/events/.gitkeep
diff --git a/.nvmrc b/.nvmrc
index 6f7f377..3f430af 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1 +1 @@
-v16
+v18
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..96fa736
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,4 @@
+dist
+public
+views
+pnpm-lock.yaml \ No newline at end of file
diff --git a/.prettierrc.json b/.prettierrc.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/.prettierrc.json
@@ -0,0 +1 @@
+{}
diff --git a/.travis.yml b/.travis.yml
index cdf8b48..d6fe659 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,7 +2,7 @@ language: shell
os: linux
services:
- - docker
+ - docker
script:
- - ./test.sh \ No newline at end of file
+ - ./test.sh
diff --git a/Dockerfile b/Dockerfile
index 5bec270..a11e337 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,8 +1,10 @@
-FROM node:16-alpine
+FROM node:18-alpine
WORKDIR /app
RUN apk add --no-cache python3 build-base
-ADD package.json package-lock.json /app/
-RUN npm install
+ADD package.json pnpm-lock.yaml /app/
+RUN npm install -g pnpm
+RUN pnpm install
COPY . /app/
-RUN cp config/api-example.js config/api.js && cp config/domain-example.js config/domain.js && cp config/database-docker.js config/database.js
-CMD npm start
+RUN cp src/config/api-example.js src/config/api.js && cp src/config/domain-example.js src/config/domain.js && cp src/config/database-docker.js src/config/database.js
+CMD pnpm run build
+CMD pnpm run start
diff --git a/FEDERATION.md b/FEDERATION.md
index fde2d2d..4c3a10b 100644
--- a/FEDERATION.md
+++ b/FEDERATION.md
@@ -6,18 +6,18 @@ This document is meant to be a reference for all the ActivityPub federation-rela
To keep things simple, sometimes you will see things formatted like `Create/Note` or `Delete/Event` or `Undo/Follow`. The thing before the slash is the Activity, and the thing after the slash is the Object inside the Activity, in an `object` property. So these are to be read as follows:
-* `Create/Note`: a `Create` activity containing a `Note` in the `object` field
-* `Delete/Event`: a `Delete` activity containing an `Event` in the `object` field
-* `Undo/Follow`: an `Undo` activity containing a `Follow` in the `object` field
+- `Create/Note`: a `Create` activity containing a `Note` in the `object` field
+- `Delete/Event`: a `Delete` activity containing an `Event` in the `object` field
+- `Undo/Follow`: an `Undo` activity containing a `Follow` in the `object` field
When the word "broadcast" is used in this document, it means to send an Activity to individual inbox of each of the followers of a given Actor.
This document has four main sections:
-* __Federation philosophy__ lays out the general model of how this is intended to federate
-* __General Actor information__ contains the basics of what to expect from our `Actor` objects
-* __Inbox behavior__ lists every incoming ActivityPub activity that the server recognizes, and tells you what it does in response to that activity, including any other ActivityPub activities it sends back out.
-* __Activities triggered from the web app__ tells you what circumstances on the web application cause the server to emit ActivityPub activities. (For example, when an event is updated via the web application, it lets all the ActivityPub followers know that the event has been updated.)
+- **Federation philosophy** lays out the general model of how this is intended to federate
+- **General Actor information** contains the basics of what to expect from our `Actor` objects
+- **Inbox behavior** lists every incoming ActivityPub activity that the server recognizes, and tells you what it does in response to that activity, including any other ActivityPub activities it sends back out.
+- **Activities triggered from the web app** tells you what circumstances on the web application cause the server to emit ActivityPub activities. (For example, when an event is updated via the web application, it lets all the ActivityPub followers know that the event has been updated.)
Please note: there is an unfortunate collision between the English language and the ActivityPub spec that can make this document confusing. When this document uses the word 'event' with a lowercase-e and not in monospace, it refers to the thing that is being tracked in gathio: events that are being organized. When this document uses the word `Event` with a capital E and in monospace, it refers to the [`Event` object defined in the ActivityStreams Vocabulary spec](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-event).
@@ -37,7 +37,7 @@ Every event has an Actor. The Actor looks like this:
```json
{
- "@context":[
+ "@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1"
],
@@ -50,12 +50,12 @@ Every event has an Actor. The Actor looks like this:
"summary": "<p><p>DESCRIPTION</p>\n</p><p>Location: LOCATION.</p><p>Starting DATETIME (human readable).</p>",
"name": "EVENTNAME",
"featured": "https://DOMAIN/EVENTID/featured",
- "publicKey":{
+ "publicKey": {
"id": "https://DOMAIN/EVENTID#main-key",
"owner": "https://DOMAIN/EVENTID",
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nOURPUBLICKEY\n-----END PUBLIC KEY-----\n"
},
- "icon":{
+ "icon": {
"type": "Image",
"mediaType": "image/jpg",
"url": "https://DOMAIN/events/EVENTID.jpg"
@@ -85,7 +85,7 @@ When the server receives a `Follow` Activity, it grabs the `actor` property on t
Assuming we can find the Actor object, then we emit an `Accept` Activity back to the server, containing the full `Follow` that we just parsed. This lets the other server know that we have fully processed the follow request.
-After this, we *also* send a `Create` Activity to the actor's inbox, containing an `Event` object with the information for this event. This is, at the moment, future compatibility for servers that consume `Event` objects. This is sent as a "direct message", directly to the inbox with no `cc` field and not addressing the public timeline.
+After this, we _also_ send a `Create` Activity to the actor's inbox, containing an `Event` object with the information for this event. This is, at the moment, future compatibility for servers that consume `Event` objects. This is sent as a "direct message", directly to the inbox with no `cc` field and not addressing the public timeline.
And finally we send the user a `Create` Activity containing a `Question` object. The `Question` is an invitation to RSVP to the event. Mastodon renders this as a poll to the user, which lets them send back to us a "Yes" RSVP directly from their client UI should they so choose. This is also sent as a "direct message". Some clients like Friendica, simply ignore `Question` objects, which is fine since the user can use built-in RSVP function of Friendica to RSVP anyway (see below).
@@ -102,13 +102,13 @@ The plan is to have this support two ways to RSVP:
1. The user answers the `Question` sent out to the prospective attendee in the form of a `Create/Note` in the style of Mastodon polls. This is mostly a hack for implementations like Mastodon that don't have vocabulary built in to RSVP to `Event`s.
2. The user sends a `Accept/Event` or `Undo/Accept/Event` back to our server. This is for implementations like Friendica that support `Event` and do things like automatically render incoming events in their UI with an RSVP interface. We currently don't accept `Reject/Event` or `TentativeAccept/Event` because gathio has no concept of a "Maybe" or "No" RSVP. It probably should have that in the future, at which case we could meaningfully parse this stuff.
-__The `Question` method__
+**The `Question` method**
If the inbox gets a `Create/Note`, there is a chance that this is a response to a `Question` that we sent a user. So the first thing we do is check its `inReplyTo` property. If it matches the id of a `Question` we sent this user, and this user is still following us, then we fetch the user's profile info. This is to make sure we have their newest `preferredUsername` in their `Actor` object (falling back to `name` and then `actor`), which we will honor as the name we display on the RSVP. We then add this person to our database as an attendee of the event.
Next we confirm that the user has RSVPed. We do this by sending them a `Create/Note` via direct message. The note tells them they RSVPed, and gives them a URL they can click on to instantly un-RSVP if they need to.
-__The `Accept/Event` method__
+**The `Accept/Event` method**
If the inbox gets an `Accept/Event`, then it assumes this is an affirmative RSVP from the actor who sent it. We check to see if the `id` of the `Event` matches the `id` of an `Event` that we sent ot this actor. If it does, then it must be a valid, affirmative RSVP. We then get the `preferredUsername` or `name` from the actor object, and add that actor to the database as an attendee. TODO: support either object URI or embedded object here.
@@ -126,7 +126,7 @@ Since a user can comment on the event via ActivityPub, they should be able to de
### Incoming private messages
-*TODO*: If someone tries to DM the event, we need to reply with a message like "Sorry, this service only supports posting public messages to the event page. Try contacting the event organizer directly if you need to have a private conversation."
+_TODO_: If someone tries to DM the event, we need to reply with a message like "Sorry, this service only supports posting public messages to the event page. Try contacting the event organizer directly if you need to have a private conversation."
## Activities triggered from the web app
@@ -144,7 +144,7 @@ And finally we send an `Update/Event` out with the new event details in the `Eve
### Delete event
-When an event is deleted by its administrator, or the event has been deleted due to it being one week after the event has ended, we send a `Delete/Actor` out to followers. This lets followers know that the event has been deleted, and their server should remove its profile from their database. (On Mastodon this results in an automatic "unfollow", which is good because we want people's follow counts to go back to normal after an event is over and has been deleted.)
+When an event is deleted by its administrator, or the event has been deleted due to it being one week after the event has ended, we send a `Delete/Actor` out to followers. This lets followers know that the event has been deleted, and their server should remove its profile from their database. (On Mastodon this results in an automatic "unfollow", which is good because we want people's follow counts to go back to normal after an event is over and has been deleted.)
We also send a `Delete/Event` out to followers. For an application like Friendica, this removes the event from the calendar of a follower.
diff --git a/activitypub.js b/activitypub.js
deleted file mode 100644
index 442f03c..0000000
--- a/activitypub.js
+++ /dev/null
@@ -1,941 +0,0 @@
-const domain = require('./config/domain.js').domain;
-const contactEmail = require('./config/domain.js').email;
-const siteName = require('./config/domain.js').sitename;
-const isFederated = require('./config/domain.js').isFederated;
-const request = require('request');
-const addToLog = require('./helpers.js').addToLog;
-const crypto = require('crypto');
-// This alphabet (used to generate all event, group, etc. IDs) is missing '-'
-// because ActivityPub doesn't like it in IDs
-const { customAlphabet } = require('nanoid');
-const nanoid = customAlphabet('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_', 21);
-var moment = require('moment-timezone');
-const mongoose = require('mongoose');
-const Event = mongoose.model('Event');
-const EventGroup = mongoose.model('EventGroup');
-var sanitizeHtml = require('sanitize-html');
-
-function createActivityPubActor(eventID, domain, pubkey, description, name, location, imageFilename, startUTC, endUTC, timezone) {
- let actor = {
- '@context': [
- 'https://www.w3.org/ns/activitystreams',
- 'https://w3id.org/security/v1'
- ],
-
- 'id': `https://${domain}/${eventID}`,
- 'type': 'Person',
- 'preferredUsername': `${eventID}`,
- 'inbox': `https://${domain}/activitypub/inbox`,
- 'outbox': `https://${domain}/${eventID}/outbox`,
- 'followers': `https://${domain}/${eventID}/followers`,
- 'summary': `<p>${description}</p>`,
- 'name': name,
- 'featured': `https://${domain}/${eventID}/featured`,
-
- 'publicKey': {
- 'id': `https://${domain}/${eventID}#main-key`,
- 'owner': `https://${domain}/${eventID}`,
- 'publicKeyPem': pubkey
- }
- };
- if (location) {
- actor.summary += `<p>Location: ${location}.</p>`
- }
- let displayDate;
- if (startUTC && timezone) {
- displayDate = moment.tz(startUTC, timezone).format('D MMMM YYYY h:mm a');
- actor.summary += `<p>Starting ${displayDate} ${timezone}.</p>`;
- }
- if (imageFilename) {
- actor.icon = {
- 'type': 'Image',
- 'mediaType': 'image/jpg',
- 'url': `https://${domain}/events/${imageFilename}`,
- };
- }
- return JSON.stringify(actor);
-}
-
-function createActivityPubEvent(name, startUTC, endUTC, timezone, description, location) {
- const guid = crypto.randomBytes(16).toString('hex');
- let eventObject = {
- "@context": "https://www.w3.org/ns/activitystreams",
- 'id': `https://${domain}/${guid}`,
- "name": name,
- "type": "Event",
- "startTime": moment.tz(startUTC, timezone).format(),
- "endTime": moment.tz(endUTC, timezone).format(),
- "content": description,
- "location": location
- }
- return JSON.stringify(eventObject);
-}
-
-function createFeaturedPost(eventID, name, startUTC, endUTC, timezone, description, location) {
- const featured = {
- "@context": "https://www.w3.org/ns/activitystreams",
- "id": `https://${domain}/${eventID}/m/featuredPost`,
- "type": "Note",
- "name": "Test",
- 'cc': 'https://www.w3.org/ns/activitystreams#Public',
- "content": `<p>This is an event that was posted on <a href="https://${domain}/${eventID}">${siteName}</a>. If you follow this account, you'll see updates in your timeline about the event. If your software supports polls, you should get a poll in your DMs asking if you want to RSVP. You can reply and RSVP right from there. If your software has an event calendar built in, you should get an event in your inbox that you can RSVP to like you respond to any event.</p><p>For more information on how to interact with this, <a href="https://github.com/lowercasename/gathio/wiki/Fediverse-Instructions">check out this link</a>.</p>`,
- 'attributedTo': `https://${domain}/${eventID}`,
- }
- return featured;
-}
-
-function updateActivityPubEvent(oldEvent, name, startUTC, endUTC, timezone, description, location) {
- // we want to persist the old ID no matter what happens to the Event itself
- const id = oldEvent.id;
- let eventObject = {
- "@context": "https://www.w3.org/ns/activitystreams",
- 'id': id,
- "name": name,
- "type": "Event",
- "startTime": moment.tz(startUTC, timezone).format(),
- "endTime": moment.tz(endUTC, timezone).format(),
- "content": description,
- "location": location
- }
- return JSON.stringify(eventObject);
-}
-
-
-function updateActivityPubActor(actor, description, name, location, imageFilename, startUTC, endUTC, timezone) {
- if (!actor) return;
- actor.summary = `<p>${description}</p>`;
- actor.name = name;
- if (location) {
- actor.summary += `<p>Location: ${location}.</p>`
- }
- let displayDate;
- if (startUTC && timezone) {
- displayDate = moment.tz(startUTC, timezone).format('D MMMM YYYY h:mm a');
- actor.summary += `<p>Starting ${displayDate} ${timezone}.</p>`;
- }
- if (imageFilename) {
- actor.icon = {
- 'type': 'Image',
- 'mediaType': 'image/jpg',
- 'url': `https://${domain}/events/${imageFilename}`,
- };
- }
- return JSON.stringify(actor);
-}
-
-function signAndSend(message, eventID, targetDomain, inbox, callback) {
- if (!isFederated) return;
- let inboxFragment = inbox.replace('https://' + targetDomain, '');
- // get the private key
- Event.findOne({
- id: eventID
- })
- .then((event) => {
- if (event) {
- const digest = crypto.createHash('sha256').update(JSON.stringify(message)).digest('base64');
- const privateKey = event.privateKey;
- const signer = crypto.createSign('sha256');
- let d = new Date();
- let stringToSign = `(request-target): post ${inboxFragment}\nhost: ${targetDomain}\ndate: ${d.toUTCString()}\ndigest: SHA-256=${digest}`;
- signer.update(stringToSign);
- signer.end();
- const signature = signer.sign(privateKey);
- const signature_b64 = signature.toString('base64');
- const algorithm = 'rsa-sha256';
- let header = `keyId="https://${domain}/${eventID}",algorithm="${algorithm}",headers="(request-target) host date digest",signature="${signature_b64}"`;
- request({
- url: inbox,
- headers: {
- 'Host': targetDomain,
- 'Date': d.toUTCString(),
- 'Signature': header,
- 'Digest': `SHA-256=${digest}`,
- 'Content-Type': 'application/activity+json',
- 'Accept': 'application/activity+json'
- },
- method: 'POST',
- json: true,
- body: message
- }, function (error, response) {
- if (error) {
- callback(error, null, 500);
- }
- else {
- // Add the message to the database
- const messageID = message.id;
- const newMessage = {
- id: message.id,
- content: JSON.stringify(message)
- };
- Event.findOne({
- id: eventID,
- }, function (err, event) {
- if (!event) return;
- event.activityPubMessages.push(newMessage);
- // also add the message's object if it has one
- if (message.object && message.object.id) {
- event.activityPubMessages.push({
- id: message.object.id,
- content: JSON.stringify(message.object)
- });
- }
- event.save()
- .then(() => {
- addToLog("addActivityPubMessage", "success", "ActivityPubMessage added to event " + eventID);
- callback(null, message.id, 200);
- })
- .catch((err) => {
- addToLog("addActivityPubMessage", "error", "Attempt to add ActivityPubMessage to event " + eventID + " failed with error: " + err);
- callback(err, null, 500);
- });
- })
- }
- });
- }
- else {
- callback(`No record found for ${eventID}.`, null, 404);
- }
- });
-}
-
-// this function sends something to the timeline of every follower in the followers array
-// it's also an unlisted public message, meaning non-followers can see the message if they look at
-// the profile but it doesn't spam federated timelines
-function broadcastCreateMessage(apObject, followers, eventID) {
- if (!isFederated) return;
- let guidCreate = crypto.randomBytes(16).toString('hex');
- Event.findOne({
- id: eventID,
- }, function (err, event) {
- if (event) {
- // iterate over followers
- for (const follower of followers) {
- let actorId = follower.actorId;
- let myURL = new URL(actorId);
- let targetDomain = myURL.hostname;
- // get the inbox
- const followerFound = event.followers.find(el => el.actorId === actorId);
- if (followerFound) {
- const actorJson = JSON.parse(follower.actorJson);
- const inbox = actorJson.inbox;
- const createMessage = {
- '@context': ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'],
- 'id': `https://${domain}/${eventID}/m/${guidCreate}`,
- 'type': 'Create',
- 'actor': `https://${domain}/${eventID}`,
- 'to': [actorId],
- 'cc': 'https://www.w3.org/ns/activitystreams#Public',
- 'object': apObject
- };
- signAndSend(createMessage, eventID, targetDomain, inbox, function (err, resp, status) {
- if (err) {
- console.log(`Didn't send to ${actorId}, status ${status} with error ${err}`);
- }
- else {
- console.log('sent to', actorId);
- }
- });
- }
- else {
- console.log(`No follower found with the id ${actorId}`);
- }
- } // end followers
- } // end if event
- else {
- console.log(`No event found with the id ${eventID}`);
- }
- });
-}
-
-
-// sends an Announce for the apObject
-function broadcastAnnounceMessage(apObject, followers, eventID) {
- if (!isFederated) return;
- let guidUpdate = crypto.randomBytes(16).toString('hex');
- Event.findOne({
- id: eventID,
- }, function (err, event) {
- if (event) {
- // iterate over followers
- for (const follower of followers) {
- let actorId = follower.actorId;
- let myURL = new URL(actorId);
- let targetDomain = myURL.hostname;
- // get the inbox
- const followerFound = event.followers.find(el => el.actorId === actorId);
- if (followerFound) {
- const actorJson = JSON.parse(follower.actorJson);
- const inbox = actorJson.inbox;
- const announceMessage = {
- '@context': ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'],
- 'id': `https://${domain}/${eventID}/m/${guidUpdate}`,
- 'cc': 'https://www.w3.org/ns/activitystreams#Public',
- 'type': 'Announce',
- 'actor': `https://${domain}/${eventID}`,
- 'object': apObject,
- 'to': actorId
- };
- signAndSend(announceMessage, eventID, targetDomain, inbox, function (err, resp, status) {
- if (err) {
- console.log(`Didn't send to ${actorId}, status ${status} with error ${err}`);
- }
- else {
- console.log('sent to', actorId);
- }
- });
- }
- else {
- console.log(`No follower found with the id ${actorId}`);
- }
- } // end followers
- } // end if event
- else {
- console.log(`No event found with the id ${eventID}`);
- }
- });
-}
-
-// sends an Update for the apObject
-function broadcastUpdateMessage(apObject, followers, eventID) {
- if (!isFederated) return;
- let guidUpdate = crypto.randomBytes(16).toString('hex');
- // iterate over followers
- Event.findOne({
- id: eventID,
- }, function (err, event) {
- if (event) {
- for (const follower of followers) {
- let actorId = follower.actorId;
- let myURL = new URL(actorId);
- let targetDomain = myURL.hostname;
- // get the inbox
- const followerFound = event.followers.find(el => el.actorId === actorId);
- if (followerFound) {
- const actorJson = JSON.parse(follower.actorJson);
- const inbox = actorJson.inbox;
- const createMessage = {
- '@context': 'https://www.w3.org/ns/activitystreams',
- 'id': `https://${domain}/${eventID}/m/${guidUpdate}`,
- 'type': 'Update',
- 'actor': `https://${domain}/${eventID}`,
- 'object': apObject
- };
- signAndSend(createMessage, eventID, targetDomain, inbox, function (err, resp, status) {
- if (err) {
- console.log(`Didn't send to ${actorId}, status ${status} with error ${err}`);
- }
- else {
- console.log('sent to', actorId);
- }
- });
- }
- else {
- console.log(`No follower found with the id ${actorId}`);
- }
- } // end followers
- }
- else {
- console.log(`No event found with the id ${eventID}`);
- }
- });
-}
-
-function broadcastDeleteMessage(apObject, followers, eventID, callback) {
- callback = callback || function () { };
- if (!isFederated) {
- callback([]);
- return;
- }
- // we need to build an array of promises for each message we're sending, run Promise.all(), and then that will resolve when every message has been sent (or failed)
- // per spec, each promise will execute *as it is built*, which is fine, we just need the guarantee that they are all done
- let promises = [];
-
- let guidUpdate = crypto.randomBytes(16).toString('hex');
- // iterate over followers
- for (const follower of followers) {
- promises.push(new Promise((resolve, reject) => {
- let actorId = follower.actorId;
- let myURL = new URL(actorId);
- let targetDomain = myURL.hostname;
- // get the inbox
- Event.findOne({
- id: eventID,
- }, function (err, event) {
- if (event) {
- const follower = event.followers.find(el => el.actorId === actorId);
- if (follower) {
- const actorJson = JSON.parse(follower.actorJson);
- const inbox = actorJson.inbox;
- const createMessage = {
- '@context': 'https://www.w3.org/ns/activitystreams',
- 'id': `https://${domain}/${eventID}/m/${guidUpdate}`,
- 'type': 'Delete',
- 'actor': `https://${domain}/${eventID}`,
- 'object': apObject
- };
- signAndSend(createMessage, eventID, targetDomain, inbox, function (err, resp, status) {
- if (err) {
- console.log(`Didn't send to ${actorId}, status ${status} with error ${err}`);
- reject(`Didn't send to ${actorId}, status ${status} with error ${err}`);
- }
- else {
- console.log('sent to', actorId);
- resolve('sent to', actorId);
- }
- });
- }
- else {
- console.log(`No follower found with the id ${actorId}`, null, 404);
- reject(`No follower found with the id ${actorId}`, null, 404);
- }
- }
- else {
- console.log(`No event found with the id ${eventID}`, null, 404);
- reject(`No event found with the id ${eventID}`, null, 404);
- }
- }); // end event
- }));
- } // end followers
-
- Promise.all(promises.map(p => p.catch(e => e))).then(statuses => {
- callback(statuses);
- });
-}
-
-// this sends a message "to:" an individual fediverse user
-function sendDirectMessage(apObject, actorId, eventID, callback) {
- if (!isFederated) return;
- callback = callback || function () { };
- const guidCreate = crypto.randomBytes(16).toString('hex');
- const guidObject = crypto.randomBytes(16).toString('hex');
- let d = new Date();
-
- apObject.published = d.toISOString();
- apObject.attributedTo = `https://${domain}/${eventID}`;
- apObject.to = actorId;
- apObject.id = `https://${domain}/${eventID}/m/${guidObject}`;
- apObject.content = unescape(apObject.content)
-
- let createMessage = {
- '@context': 'https://www.w3.org/ns/activitystreams',
- 'id': `https://${domain}/${eventID}/m/${guidCreate}`,
- 'type': 'Create',
- 'actor': `https://${domain}/${eventID}`,
- 'to': [actorId],
- 'object': apObject
- };
-
- let myURL = new URL(actorId);
- let targetDomain = myURL.hostname;
- // get the inbox
- Event.findOne({
- id: eventID,
- }, function (err, event) {
- if (event) {
- const follower = event.followers.find(el => el.actorId === actorId);
- if (follower) {
- const actorJson = JSON.parse(follower.actorJson);
- const inbox = actorJson.inbox;
- signAndSend(createMessage, eventID, targetDomain, inbox, callback);
- }
- else {
- callback(`No follower found with the id ${actorId}`, null, 404);
- }
- }
- else {
- callback(`No event found with the id ${eventID}`, null, 404);
- }
- });
-}
-
-function sendAcceptMessage(thebody, eventID, targetDomain, callback) {
- if (!isFederated) return;
- callback = callback || function () { };
- const guid = crypto.randomBytes(16).toString('hex');
- const actorId = thebody.actor;
- let message = {
- '@context': 'https://www.w3.org/ns/activitystreams',
- 'id': `https://${domain}/${guid}`,
- 'type': 'Accept',
- 'actor': `https://${domain}/${eventID}`,
- 'object': thebody,
- };
- // get the inbox
- Event.findOne({
- id: eventID,
- }, function (err, event) {
- if (event) {
- const follower = event.followers.find(el => el.actorId === actorId);
- if (follower) {
- const actorJson = JSON.parse(follower.actorJson);
- const inbox = actorJson.inbox;
- signAndSend(message, eventID, targetDomain, inbox, callback);
- }
- }
- else {
- callback(`Could not find event ${eventID}`, null, 404);
- }
- });
-}
-
-function _handleFollow(req, res) {
- const myURL = new URL(req.body.actor);
- let targetDomain = myURL.hostname;
- let eventID = req.body.object.replace(`https://${domain}/`, '');
- // Add the user to the DB of accounts that follow the account
- // get the follower's username
- request({
- url: req.body.actor,
- headers: {
- 'Accept': 'application/activity+json',
- 'Content-Type': 'application/activity+json'
- }
- }, function (error, response, body) {
- body = JSON.parse(body)
- const name = body.preferredUsername || body.name || body.attributedTo;
- const newFollower = {
- actorId: req.body.actor,
- followId: req.body.id,
- name: name,
- actorJson: JSON.stringify(body)
- };
- Event.findOne({
- id: eventID,
- }, function (err, event) {
- // if this account is NOT already in our followers list, add it
- if (event && !event.followers.map(el => el.actorId).includes(req.body.actor)) {
- event.followers.push(newFollower);
- event.save()
- .then(() => {
- addToLog("addEventFollower", "success", "Follower added to event " + eventID);
- // Accept the follow request
- sendAcceptMessage(req.body, eventID, targetDomain, function (err, resp, status) {
- if (err) {
- console.log(`Didn't send Accept to ${req.body.actor}, status ${status} with error ${err}`);
- }
- else {
- console.log('sent Accept to', req.body.actor);
- // ALSO send an ActivityPub Event activity since this person is "interested" in the event, as indicated by the Follow
- const jsonEventObject = JSON.parse(event.activityPubEvent);
- // send direct message to user
- sendDirectMessage(jsonEventObject, newFollower.actorId, event.id);
-
- // if users can self-RSVP, send a Question to the new follower
- if (event.usersCanAttend) {
- const jsonObject = {
- "@context": "https://www.w3.org/ns/activitystreams",
- "name": `RSVP to ${event.name}`,
- "type": "Question",
- "content": `<span class=\"h-card\"><a href="${req.body.actor}" class="u-url mention">@<span>${name}</span></a></span> Will you attend ${event.name}? (If you reply "Yes", you'll be listed as an attendee on the event page.)`,
- "oneOf": [
- { "type": "Note", "name": "Yes" },
- ],
- "endTime": event.start.toISOString(),
- "tag": [{ "type": "Mention", "href": req.body.actor, "name": name }]
- }
- // send direct message to user
- sendDirectMessage(jsonObject, req.body.actor, eventID, function (error, response, statuscode) {
- if (error) {
- console.log('Error sending direct message:', error);
- return res.status(statuscode).json(error);
- }
- else {
- return res.status(statuscode).json({ messageid: response });
- }
- });
- }
- }
- });
- })
- .catch((err) => {
- addToLog("addEventFollower", "error", "Attempt to add follower to event " + eventID + " failed with error: " + err);
- return res.status(500).send('Database error, please try again :(');
- });
- }
- else {
- // this person is already a follower so just say "ok"
- return res.status(200);
- }
- })
- }) //end request
-}
-
-function _handleUndoFollow(req, res) {
- // get the record of all followers for this account
- const eventID = req.body.object.object.replace(`https://${domain}/`, '');
- Event.findOne({
- id: eventID,
- }, function (err, event) {
- if (!event) return;
- // check to see if the Follow object's id matches the id we have on record
- // is this even someone who follows us
- const indexOfFollower = event.followers.findIndex(el => el.actorId === req.body.object.actor);
- if (indexOfFollower !== -1) {
- // does the id we have match the id we are being given
- if (event.followers[indexOfFollower].followId === req.body.object.id) {
- // we have a match and can trust the Undo! remove this person from the followers list
- event.followers.splice(indexOfFollower, 1);
- event.save()
- .then(() => {
- addToLog("removeEventFollower", "success", "Follower removed from event " + eventID);
- return res.sendStatus(200);
- })
- .catch((err) => {
- addToLog("removeEventFollower", "error", "Attempt to remove follower from event " + eventID + " failed with error: " + err);
- return res.send('Database error, please try again :(');
- });
- }
- }
- });
-}
-
-function _handleAcceptEvent(req, res) {
- let { name, attributedTo, inReplyTo, to, actor } = req.body;
- if (Array.isArray(to)) {
- to = to[0];
- }
- const eventID = to.replace(`https://${domain}/`, '');
- Event.findOne({
- id: eventID,
- }, function (err, event) {
- if (!event) return;
- // does the id we got match the id of a thing we sent out
- const message = event.activityPubMessages.find(el => el.id === req.body.object);
- if (message) {
- // it's a match
- request({
- url: actor,
- headers: {
- 'Accept': 'application/activity+json',
- 'Content-Type': 'application/activity+json'
- }
- }, function (error, response, body) {
- body = JSON.parse(body)
- // if this account is NOT already in our attendees list, add it
- if (!event.attendees.map(el => el.id).includes(actor)) {
- const attendeeName = body.preferredUsername || body.name || actor;
- const newAttendee = {
- name: attendeeName,
- status: 'attending',
- id: actor,
- number: 1,
- };
- event.attendees.push(newAttendee);
- event.save()
- .then((fullEvent) => {
- addToLog("addEventAttendee", "success", "Attendee added to event " + req.params.eventID);
- // get the new attendee with its hidden id from the full event
- let fullAttendee = fullEvent.attendees.find(el => el.id === actor);
- // send a "click here to remove yourself" link back to the user as a DM
- const jsonObject = {
- "@context": "https://www.w3.org/ns/activitystreams",
- "name": `RSVP to ${event.name}`,
- "type": "Note",
- "content": `<span class=\"h-card\"><a href="${newAttendee.id}" class="u-url mention">@<span>${newAttendee.name}</span></a></span> Thanks for RSVPing! You can remove yourself from the RSVP list by clicking here: <a href="https://${domain}/oneclickunattendevent/${event.id}/${fullAttendee._id}">https://${domain}/oneclickunattendevent/${event.id}/${fullAttendee._id}</a>`,
- "tag": [{ "type": "Mention", "href": newAttendee.id, "name": newAttendee.name }]
- }
- // send direct message to user
- sendDirectMessage(jsonObject, newAttendee.id, event.id);
- return res.sendStatus(200);
- })
- .catch((err) => {
- addToLog("addEventAttendee", "error", "Attempt to add attendee to event " + req.params.eventID + " failed with error: " + err);
- return res.status(500).send('Database error, please try again :(');
- });
- }
- else {
- // it's a duplicate and this person is already rsvped so just say OK
- return res.status(200).send("Attendee is already registered.");
- }
- });
- }
- });
-}
-
-function _handleUndoAcceptEvent(req, res) {
- let { name, attributedTo, inReplyTo, to, actor } = req.body;
- if (Array.isArray(to)) {
- to = to[0];
- }
- const eventID = to.replace(`https://${domain}/`, '');
- Event.findOne({
- id: eventID,
- }, function (err, event) {
- if (!event) return;
- // does the id we got match the id of a thing we sent out
- const message = event.activityPubMessages.find(el => el.id === req.body.object.object);
- if (message) {
- // it's a match
- Event.update(
- { id: eventID },
- { $pull: { attendees: { id: actor } } }
- )
- .then(response => {
- addToLog("oneClickUnattend", "success", "Attendee removed via one click unattend " + req.params.eventID);
- });
- }
- });
-}
-
-function _handleCreateNote(req, res) {
- // figure out what this is in reply to -- it should be addressed specifically to us
- let { name, attributedTo, inReplyTo, to } = req.body.object;
- // if it's an array just grab the first element, since a poll should only broadcast back to the pollster
- if (Array.isArray(to)) {
- to = to[0];
- }
- const eventID = to.replace(`https://${domain}/`, '');
- // make sure this person is actually a follower
- Event.findOne({
- id: eventID,
- }, function (err, event) {
- if (!event) return;
- // is this even someone who follows us
- const indexOfFollower = event.followers.findIndex(el => el.actorId === req.body.object.attributedTo);
- if (indexOfFollower !== -1) {
- // compare the inReplyTo to its stored message, if it exists and it's going to the right follower then this is a valid reply
- const message = event.activityPubMessages.find(el => {
- const content = JSON.parse(el.content);
- return inReplyTo === (content.object && content.object.id);
- });
- if (message) {
- const content = JSON.parse(message.content);
- // check if the message we sent out was sent to the actor this incoming message is attributedTo
- if (content.to[0] === attributedTo) {
- // it's a match, this is a valid poll response, add RSVP to database
- // fetch the profile information of the user
- request({
- url: attributedTo,
- headers: {
- 'Accept': 'application/activity+json',
- 'Content-Type': 'application/activity+json'
- }
- }, function (error, response, body) {
- body = JSON.parse(body)
- // if this account is NOT already in our attendees list, add it
- if (!event.attendees.map(el => el.id).includes(attributedTo)) {
- const attendeeName = body.preferredUsername || body.name || attributedTo;
- const newAttendee = {
- name: attendeeName,
- status: 'attending',
- id: attributedTo,
- number: 1,
- };
- event.attendees.push(newAttendee);
- event.save()
- .then((fullEvent) => {
- addToLog("addEventAttendee", "success", "Attendee added to event " + req.params.eventID);
- // get the new attendee with its hidden id from the full event
- let fullAttendee = fullEvent.attendees.find(el => el.id === attributedTo);
- // send a "click here to remove yourself" link back to the user as a DM
- const jsonObject = {
- "@context": "https://www.w3.org/ns/activitystreams",
- "name": `RSVP to ${event.name}`,
- "type": "Note",
- "content": `<span class=\"h-card\"><a href="${newAttendee.id}" class="u-url mention">@<span>${newAttendee.name}</span></a></span> Thanks for RSVPing! You can remove yourself from the RSVP list by clicking here: <a href="https://${domain}/oneclickunattendevent/${event.id}/${fullAttendee._id}">https://${domain}/oneclickunattendevent/${event.id}/${fullAttendee._id}</a>`,
- "tag": [{ "type": "Mention", "href": newAttendee.id, "name": newAttendee.name }]
- }
- // send direct message to user
- sendDirectMessage(jsonObject, newAttendee.id, event.id);
- return res.sendStatus(200);
- })
- .catch((err) => {
- addToLog("addEventAttendee", "error", "Attempt to add attendee to event " + req.params.eventID + " failed with error: " + err);
- return res.status(500).send('Database error, please try again :(');
- });
- }
- else {
- // it's a duplicate and this person is already rsvped so just say OK
- return res.status(200).send("Attendee is already registered.");
- }
- });
- }
- }
- }
- });
-}
-
-function _handleDelete(req, res) {
- const deleteObjectId = req.body.object.id;
- // find all events with comments from the author
- Event.find({
- "comments.actorId": req.body.actor
- }, function (err, events) {
- if (!events) {
- return res.sendStatus(404);
- }
-
- // find the event with THIS comment from the author
- let eventWithComment = events.find(event => {
- let comments = event.comments;
- return comments.find(comment => {
- if (!comment.activityJson) {
- return false;
- }
- return JSON.parse(comment.activityJson).object.id === req.body.object.id;
- })
- });
-
- if (!eventWithComment) {
- return res.sendStatus(404);
- }
-
- // delete the comment
- // find the index of the comment, it should have an activityJson field because from an AP server you can only delete an AP-originated comment (and of course it needs to be yours)
- let indexOfComment = eventWithComment.comments.findIndex(comment => {
- return comment.activityJson && JSON.parse(comment.activityJson).object.id === req.body.object.id;
- });
- eventWithComment.comments.splice(indexOfComment, 1);
- eventWithComment.save()
- .then(() => {
- addToLog("deleteComment", "success", "Comment deleted from event " + eventWithComment.id);
- return res.sendStatus(200);
- })
- .catch((err) => {
- addToLog("deleteComment", "error", "Attempt to delete comment " + req.body.object.id + "from event " + eventWithComment.id + " failed with error: " + err);
- return res.sendStatus(500);
- });
- });
-}
-
-function _handleCreateNoteComment(req, res) {
- // figure out what this is in reply to -- it should be addressed specifically to us
- let { attributedTo, inReplyTo, to, cc } = req.body.object;
- // normalize cc into an array
- if (typeof cc === 'string') {
- cc = [cc];
- }
- // normalize to into an array
- if (typeof to === 'string') {
- to = [to];
- }
-
- // if this is a public message (in the to or cc fields)
- if (to.includes('https://www.w3.org/ns/activitystreams#Public') || (Array.isArray(cc) && cc.includes('https://www.w3.org/ns/activitystreams#Public'))) {
- // figure out which event(s) of ours it was addressing
- let ourEvents = cc.filter(el => el.includes(`https://${domain}/`))
- .map(el => el.replace(`https://${domain}/`, ''));
- // comments should only be on one event. if more than one, ignore (spam, probably)
- if (ourEvents.length === 1) {
- let eventID = ourEvents[0];
- // add comment
- let commentID = nanoid();
- // get the actor for the commenter
- request({
- url: req.body.actor,
- headers: {
- 'Accept': 'application/activity+json',
- 'Content-Type': 'application/activity+json'
- }
- }, function (error, response, actor) {
- if (!error) {
- const parsedActor = JSON.parse(actor);
- const name = parsedActor.preferredUsername || parsedActor.name || req.body.actor;
- const newComment = {
- id: commentID,
- actorId: req.body.actor,
- activityId: req.body.object.id,
- author: name,
- content: sanitizeHtml(req.body.object.content, { allowedTags: [], allowedAttributes: {} }).replace('@' + eventID, ''),
- timestamp: moment(),
- activityJson: JSON.stringify(req.body),
- actorJson: actor
- };
-
- Event.findOne({
- id: eventID,
- }, function (err, event) {
- if (!event) {
- return res.sendStatus(404);
- }
- if (!event.usersCanComment) {
- return res.sendStatus(200);
- }
- event.comments.push(newComment);
- event.save()
- .then(() => {
- addToLog("addEventComment", "success", "Comment added to event " + eventID);
- const guidObject = crypto.randomBytes(16).toString('hex');
- const jsonObject = req.body.object;
- jsonObject.attributedTo = newComment.actorId;
- broadcastAnnounceMessage(jsonObject, event.followers, eventID)
- return res.sendStatus(200);
- })
- .catch((err) => {
- addToLog("addEventComment", "error", "Attempt to add comment to event " + eventID + " failed with error: " + err);
- res.status(500).send('Database error, please try again :(' + err);
- });
- });
- }
- });
- } // end ourevent
- } // end public message
-}
-
-function processInbox(req, res) {
- if (!isFederated) return res.sendStatus(404);
- try {
- // if a Follow activity hits the inbox
- if (typeof req.body.object === 'string' && req.body.type === 'Follow') {
- _handleFollow(req, res);
- }
- // if an Undo activity with a Follow object hits the inbox
- if (req.body && req.body.type === 'Undo' && req.body.object && req.body.object.type === 'Follow') {
- _handleUndoFollow(req, res);
- }
- // if an Accept activity with the id of the Event we sent out hits the inbox, it is an affirmative RSVP
- if (req.body && req.body.type === 'Accept' && req.body.object && typeof req.body.object === 'string') {
- _handleAcceptEvent(req, res);
- }
- // if an Undo activity containing an Accept containing the id of the Event we sent out hits the inbox, it is an undo RSVP
- if (req.body && req.body.type === 'Undo' && req.body.object && req.body.object.object && typeof req.body.object.object === 'string' && req.body.object.type === 'Accept') {
- _handleUndoAcceptEvent(req, res);
- }
- // if a Create activity with a Note object hits the inbox, and it's a reply, it might be a vote in a poll
- if (req.body && req.body.type === 'Create' && req.body.object && req.body.object.type === 'Note' && req.body.object.inReplyTo && req.body.object.to) {
- _handleCreateNote(req, res);
- }
- // if a Delete activity hits the inbox, it might a deletion of a comment
- if (req.body && req.body.type === 'Delete') {
- _handleDelete(req, res);
- }
- // if we are CC'ed on a public or unlisted Create/Note, then this is a comment to us we should boost (Announce) to our followers
- if (req.body && req.body.type === 'Create' && req.body.object && req.body.object.type === 'Note' && req.body.object.to) {
- _handleCreateNoteComment(req, res);
- } // CC'ed
- }
- catch (e) {
- console.log('Error in processing inbox:', e)
- }
-}
-
-function createWebfinger(eventID, domain) {
- return {
- 'subject': `acct:${eventID}@${domain}`,
-
- 'links': [
- {
- 'rel': 'self',
- 'type': 'application/activity+json',
- 'href': `https://${domain}/${eventID}`
- }
- ]
- };
-}
-
-module.exports = {
- processInbox,
- sendAcceptMessage,
- sendDirectMessage,
- broadcastAnnounceMessage,
- broadcastUpdateMessage,
- broadcastDeleteMessage,
- broadcastCreateMessage,
- signAndSend,
- createActivityPubActor,
- updateActivityPubActor,
- createActivityPubEvent,
- updateActivityPubEvent,
- createFeaturedPost,
- createWebfinger,
-}
diff --git a/app.js b/app.js
deleted file mode 100755
index c6e0647..0000000
--- a/app.js
+++ /dev/null
@@ -1,54 +0,0 @@
-const express = require('express');
-const path = require('path');
-const session = require('express-session');
-const cors = require('cors');
-const routes = require('./routes');
-const hbs = require('express-handlebars');
-const bodyParser = require('body-parser');
-
-const app = express();
-
-// Configuration //
-
-//app.use(cors());
-//app.use(bodyParser.json());
-//app.use(session({ secret: 'slartibartfast', cookie: { maxAge: 60000 }, resave: false, saveUninitialized: false }));
-
-
-// View engine //
-hbsInstance = hbs.create({
- defaultLayout: 'main',
- partialsDir: ['views/partials/'],
- layoutsDir: 'views/layouts/',
- helpers: {
- plural: function(number, text) {
- var singular = number === 1;
- // If no text parameter was given, just return a conditional s.
- if (typeof text !== 'string') return singular ? '' : 's';
- // Split with regex into group1/group2 or group1(group3)
- var match = text.match(/^([^()\/]+)(?:\/(.+))?(?:\((\w+)\))?/);
- // If no match, just append a conditional s.
- if (!match) return text + (singular ? '' : 's');
- // We have a good match, so fire away
- return singular && match[1] // Singular case
- ||
- match[2] // Plural case: 'bagel/bagels' --> bagels
- ||
- match[1] + (match[3] || 's'); // Plural case: 'bagel(s)' or 'bagel' --> bagels
- }
- }
-});
-app.engine('handlebars', hbsInstance.engine);
-app.set('view engine', 'handlebars');
-app.set('hbsInstance', hbsInstance);
-
-// Static files //
-
-app.use(express.static('public'));
-
-// Router //
-app.use(bodyParser.json({ type: "application/activity+json" })); // support json encoded bodies
-app.use(bodyParser.urlencoded({ extended: true }));
-app.use('/', routes);
-
-module.exports = app;
diff --git a/config/api-example.js b/config/api-example.js
deleted file mode 100644
index 9202f0a..0000000
--- a/config/api-example.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// Which of these fields are used depends on the 'mailService' config entry in config/domain.js
-module.exports = {
- 'sendgrid' : '', // If using SendGrid, the Sendgrid API key goes here
- 'smtpServer': '', // If using Nodemailer, your SMTP server hostname goes here
- 'smtpPort': '', // If using Nodemailer, your SMTP server port goes here
- 'smtpUsername': '', // If using Nodemailer, your SMTP server username goes here
- 'smtpPassword': '' // If using Nodemailer, your SMTP password goes here
-};
diff --git a/config/database-docker.js b/config/database-docker.js
deleted file mode 100644
index 7847097..0000000
--- a/config/database-docker.js
+++ /dev/null
@@ -1,3 +0,0 @@
-module.exports = {
- 'url' : 'mongodb://mongo:27017/gathio' // For dockerised MongoDB connection
-};
diff --git a/config/database-example.js b/config/database-example.js
deleted file mode 100644
index 4aa4c4d..0000000
--- a/config/database-example.js
+++ /dev/null
@@ -1,3 +0,0 @@
-module.exports = {
- 'url' : 'mongodb://localhost:27017/gathio' // For local MongoDB connection
-};
diff --git a/config/domain-example.js b/config/domain-example.js
deleted file mode 100644
index 19c797a..0000000
--- a/config/domain-example.js
+++ /dev/null
@@ -1,13 +0,0 @@
-module.exports = {
- // Your domain goes here. If there is a port it should be 'domain:port', but otherwise just 'domain'
- 'domain' : 'localhost:3000' ,
- 'port': '3000',
- 'email': 'contact@example.com',
- 'mailService': 'nodemailer', // Which mail service to use to send emails to attendees. Options are 'nodemailer' or 'sendgrid'. Configure settings for the mail service in config/api.js.z
- 'sitename': 'gathio',
- 'isFederated': true,
- // If left blank, this defaults to https://yourdomain.com/images/gathio-email-logo.gif. Set a full URL here to change it to your own logo (or just change the file itself)
- 'logo_url': '',
- // Show a Ko-Fi box to donate money to Raphael Kabo (Gathio's creator) on the front page
- 'showKofi': false,
-};
diff --git a/docker-compose.yml b/docker-compose.yml
index 44026c8..334bc3d 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,16 +1,16 @@
-version: '3'
+version: "3"
volumes:
- mongodb_data_db:
+ mongodb_data_db:
services:
- gathio:
- build: .
- links:
- - mongo
- ports:
- - 3000:3000
- mongo:
- image: mongo:latest
- volumes:
- - mongodb_data_db:/data/db \ No newline at end of file
+ gathio:
+ build: .
+ links:
+ - mongo
+ ports:
+ - 3000:3000
+ mongo:
+ image: mongo:latest
+ volumes:
+ - mongodb_data_db:/data/db
diff --git a/package-lock.json b/package-lock.json
deleted file mode 100644
index b19767b..0000000
--- a/package-lock.json
+++ /dev/null
@@ -1,7925 +0,0 @@
-{
- "name": "gathio",
- "version": "1.3.0",
- "lockfileVersion": 2,
- "requires": true,
- "packages": {
- "": {
- "name": "gathio",
- "version": "1.3.0",
- "license": "GPL-3.0-or-later",
- "dependencies": {
- "@sendgrid/mail": "^6.5.5",
- "body-parser": "^1.18.3",
- "cors": "^2.8.5",
- "dotenv": "^6.1.0",
- "express": "^4.16.4",
- "express-fileupload": "^1.1.9",
- "express-handlebars": "^6.0.5",
- "express-jwt": "^8.4.0",
- "express-session": "^1.17.1",
- "express-validator": "^6.14.0",
- "generate-rsa-keypair": "^0.2.1",
- "greenlock": "^2.8.8",
- "greenlock-express": "^2.7.18",
- "ical": "^0.6.0",
- "ical-generator": "^1.11.0",
- "jimp": "^0.16.1",
- "jsonwebtoken": "^9.0.0",
- "marked": "^4.0.10",
- "moment-timezone": "^0.5.31",
- "mongoose": "^5.9.18",
- "multer": "^1.4.5-lts.1",
- "nanoid": "^3.1.9",
- "niceware": "^3.0.0",
- "node-schedule": "^1.3.1",
- "nodemailer": "^6.4.8",
- "randomstring": "^1.1.5",
- "request": "^2.88.2",
- "sanitize-html": "^2.6.1"
- },
- "devDependencies": {
- "eslint": "^8.4.1",
- "nodemon": "^2.0.15"
- },
- "engines": {
- "node": ">=16.16.0"
- }
- },
- "node_modules/@babel/runtime": {
- "version": "7.20.13",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz",
- "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==",
- "dependencies": {
- "regenerator-runtime": "^0.13.11"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@eslint/eslintrc": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz",
- "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==",
- "dev": true,
- "dependencies": {
- "ajv": "^6.12.4",
- "debug": "^4.3.2",
- "espree": "^9.4.0",
- "globals": "^13.19.0",
- "ignore": "^5.2.0",
- "import-fresh": "^3.2.1",
- "js-yaml": "^4.1.0",
- "minimatch": "^3.1.2",
- "strip-json-comments": "^3.1.1"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/@eslint/eslintrc/node_modules/debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "dev": true,
- "dependencies": {
- "ms": "2.1.2"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/@eslint/eslintrc/node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- },
- "node_modules/@humanwhocodes/config-array": {
- "version": "0.11.8",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
- "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==",
- "dev": true,
- "dependencies": {
- "@humanwhocodes/object-schema": "^1.2.1",
- "debug": "^4.1.1",
- "minimatch": "^3.0.5"
- },
- "engines": {
- "node": ">=10.10.0"
- }
- },
- "node_modules/@humanwhocodes/config-array/node_modules/debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "dev": true,
- "dependencies": {
- "ms": "2.1.2"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/@humanwhocodes/config-array/node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- },
- "node_modules/@humanwhocodes/module-importer": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
- "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
- "dev": true,
- "engines": {
- "node": ">=12.22"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/nzakas"
- }
- },
- "node_modules/@humanwhocodes/object-schema": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
- "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
- "dev": true
- },
- "node_modules/@jimp/bmp": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/bmp/-/bmp-0.16.2.tgz",
- "integrity": "sha512-4g9vW45QfMoGhLVvaFj26h4e7cC+McHUQwyFQmNTLW4FfC1OonN9oUr2m/FEDGkTYKR7aqdXR5XUqqIkHWLaFw==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2",
- "bmp-js": "^0.1.0"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
- }
- },
- "node_modules/@jimp/core": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/core/-/core-0.16.2.tgz",
- "integrity": "sha512-dp7HcyUMzjXphXYodI6PaXue+I9PXAavbb+AN+1XqFbotN22Z12DosNPEyy+UhLY/hZiQQqUkEaJHkvV31rs+w==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2",
- "any-base": "^1.1.0",
- "buffer": "^5.2.0",
- "exif-parser": "^0.1.12",
- "file-type": "^9.0.0",
- "load-bmfont": "^1.3.1",
- "mkdirp": "^0.5.1",
- "phin": "^2.9.1",
- "pixelmatch": "^4.0.2",
- "tinycolor2": "^1.4.1"
- }
- },
- "node_modules/@jimp/custom": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/custom/-/custom-0.16.2.tgz",
- "integrity": "sha512-GtNwOs4hcVS2GIbqRUf42rUuX07oLB92cj7cqxZb0ZGWwcwhnmSW0TFLAkNafXmqn9ug4VTpNvcJSUdiuECVKg==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/core": "^0.16.2"
- }
- },
- "node_modules/@jimp/gif": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/gif/-/gif-0.16.2.tgz",
- "integrity": "sha512-TMdyT9Q0paIKNtT7c5KzQD29CNCsI/t8ka28jMrBjEK7j5RRTvBfuoOnHv7pDJRCjCIqeUoaUSJ7QcciKic6CA==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2",
- "gifwrap": "^0.9.2",
- "omggif": "^1.0.9"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
- }
- },
- "node_modules/@jimp/jpeg": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/jpeg/-/jpeg-0.16.2.tgz",
- "integrity": "sha512-BW5gZydgq6wdIwHd+3iUNgrTklvoQc/FUKSj9meM6A0FU21lUaansRX5BDdJqHkyXJLnnlDGwDt27J+hQuBAVw==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2",
- "jpeg-js": "^0.4.2"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
- }
- },
- "node_modules/@jimp/plugin-blit": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-0.16.2.tgz",
- "integrity": "sha512-Z31rRfV80gC/r+B/bOPSVVpJEWXUV248j7MdnMOFLu4vr8DMqXVo9jYqvwU/s4LSTMAMXqm4Jg6E/jQfadPKAg==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
- }
- },
- "node_modules/@jimp/plugin-blur": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-0.16.2.tgz",
- "integrity": "sha512-ShkJCAzRI+1fAKPuLLgEkixpSpVmKTYaKEFROUcgmrv9AansDXGNCupchqVMTdxf8zPyW8rR1ilvG3OJobufLQ==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
- }
- },
- "node_modules/@jimp/plugin-circle": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-circle/-/plugin-circle-0.16.2.tgz",
- "integrity": "sha512-6T4z/48F4Z5+YwAVCLOvXQcyGmo0E3WztxCz6XGQf66r4JJK78+zcCDYZFLMx0BGM0091FogNK4QniP8JaOkrA==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
- }
- },
- "node_modules/@jimp/plugin-color": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-0.16.2.tgz",
- "integrity": "sha512-6oBV0g0J17/7E+aTquvUsgSc85nUbUi+64tIK5eFIDzvjhlqhjGNJYlc46KJMCWIs61qRJayQoZdL/iT/iQuGQ==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2",
- "tinycolor2": "^1.4.1"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
- }
- },
- "node_modules/@jimp/plugin-contain": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-0.16.2.tgz",
- "integrity": "sha512-pLcxO3hVN3LCEhMNvpZ9B7xILHVlS433Vv16zFFJxLRqZdYvPLsc+ZzJhjAiHHuEjVblQrktHE3LGeQwGJPo0w==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5",
- "@jimp/plugin-blit": ">=0.3.5",
- "@jimp/plugin-resize": ">=0.3.5",
- "@jimp/plugin-scale": ">=0.3.5"
- }
- },
- "node_modules/@jimp/plugin-cover": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-0.16.2.tgz",
- "integrity": "sha512-gzWM7VvYeI8msyiwbUZxH+sGQEgO6Vd6adGxZ0CeKX00uQOe5lDzxb1Wjx7sHcJGz8a/5fmAuwz7rdDtpDUbkw==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5",
- "@jimp/plugin-crop": ">=0.3.5",
- "@jimp/plugin-resize": ">=0.3.5",
- "@jimp/plugin-scale": ">=0.3.5"
- }
- },
- "node_modules/@jimp/plugin-crop": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-0.16.2.tgz",
- "integrity": "sha512-qCd3hfMEE+Z2EuuyXewgXRTtKJGIerWzc1zLEJztsUkPz5i73IGgkOL+mrNutZwGaXZbm+8SwUaGb46sxAO6Tw==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
- }
- },
- "node_modules/@jimp/plugin-displace": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-0.16.2.tgz",
- "integrity": "sha512-6nXdvNNjCdD95v2o3/jPeur903dz08lG4Y8gmr5oL2yVv9LSSbMonoXYrR/ASesdyXqGdXJLU4NL+yZs4zUqbQ==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
- }
- },
- "node_modules/@jimp/plugin-dither": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-0.16.2.tgz",
- "integrity": "sha512-DERpIzy21ZanMkVsD0Tdy8HQLbD1E41OuvIzaMRoW4183PA6AgGNlrQoFTyXmzjy6FTy1SxaQgTEdouInAWZ9Q==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
- }
- },
- "node_modules/@jimp/plugin-fisheye": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-fisheye/-/plugin-fisheye-0.16.2.tgz",
- "integrity": "sha512-Df7PsGIwiIpQu3EygYCnaJyTfOwvwtYV3cmYJS7yFLtdiFUuod+hlSo5GkwEPLAy+QBxhUbDuUqnsWo4NQtbiQ==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
- }
- },
- "node_modules/@jimp/plugin-flip": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-0.16.2.tgz",
- "integrity": "sha512-+2uC8ioVQUr06mnjSWraskz2L33nJHze35LkQ8ZNsIpoZLkgvfiWatqAs5bj+1jGI/9kxoCFAaT1Is0f+a4/rw==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5",
- "@jimp/plugin-rotate": ">=0.3.5"
- }
- },
- "node_modules/@jimp/plugin-gaussian": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-gaussian/-/plugin-gaussian-0.16.2.tgz",
- "integrity": "sha512-2mnuDSg4ZEH8zcJig7DZZf4st/cYmQ5UYJKP76iGhZ+6JDACk6uejwAgT5xHecNhkVAaXMdCybA2eknH/9OE1w==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
- }
- },
- "node_modules/@jimp/plugin-invert": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-invert/-/plugin-invert-0.16.2.tgz",
- "integrity": "sha512-xFvHbVepTY/nus+6yXiYN1iq+UBRkT0MdnObbiQPstUrAsz0Imn6MWISsnAyMvcNxHGrxaxjuU777JT/esM0gg==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
- }
- },
- "node_modules/@jimp/plugin-mask": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-0.16.2.tgz",
- "integrity": "sha512-AbdO85xxhfgEDdxYKpUotEI9ixiCMaIpfYHD5a5O/VWeimz2kuwhcrzlHGiyq1kKAgRcl0WEneTCZAHVSyvPKA==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
- }
- },
- "node_modules/@jimp/plugin-normalize": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-normalize/-/plugin-normalize-0.16.2.tgz",
- "integrity": "sha512-+ItBWFwmB0Od7OfOtTYT1gm543PpHUgU8/DN55z83l1JqS0OomDJAe7BmCppo2405TN6YtVm/csXo7p4iWd/SQ==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
- }
- },
- "node_modules/@jimp/plugin-print": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-0.16.2.tgz",
- "integrity": "sha512-ifTGEeJ5UZTCiqC70HMeU3iXk/vsOmhWiwVGOXSFXhFeE8ZpDWvlmBsrMYnRrJGuaaogHOIrrQPI+kCdDBSBIQ==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2",
- "load-bmfont": "^1.4.0"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5",
- "@jimp/plugin-blit": ">=0.3.5"
- }
- },
- "node_modules/@jimp/plugin-resize": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-0.16.2.tgz",
- "integrity": "sha512-gE4N9l6xuwzacFZ2EPCGZCJ/xR+aX2V7GdMndIl/6kYIw5/eib1SFuF9AZLvIPSFuE1FnGo8+vT0pr++SSbhYg==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
- }
- },
- "node_modules/@jimp/plugin-rotate": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-0.16.2.tgz",
- "integrity": "sha512-/CTEYkR1HrgmnE0VqPhhbBARbDAfFX590LWGIpxcYIYsUUGQCadl+8Qo4UX13FH0Nt8UHEtPA+O2x08uPYg9UA==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5",
- "@jimp/plugin-blit": ">=0.3.5",
- "@jimp/plugin-crop": ">=0.3.5",
- "@jimp/plugin-resize": ">=0.3.5"
- }
- },
- "node_modules/@jimp/plugin-scale": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-scale/-/plugin-scale-0.16.2.tgz",
- "integrity": "sha512-3inuxfrlquyLaqFdiiiQNJUurR0WbvN5wAf1qcYX2LubG1AG8grayYD6H7XVoxfUGTZXh1kpmeirEYlqA2zxcw==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5",
- "@jimp/plugin-resize": ">=0.3.5"
- }
- },
- "node_modules/@jimp/plugin-shadow": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-shadow/-/plugin-shadow-0.16.2.tgz",
- "integrity": "sha512-Q0aIs2/L6fWMcEh9Ms73u34bT1hyUMw/oxaVoIzOLo6/E8YzCs2Bi63H0/qaPS0MQpEppI++kvosPbblABY79w==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5",
- "@jimp/plugin-blur": ">=0.3.5",
- "@jimp/plugin-resize": ">=0.3.5"
- }
- },
- "node_modules/@jimp/plugin-threshold": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-threshold/-/plugin-threshold-0.16.2.tgz",
- "integrity": "sha512-gyOwmBgjtMPvcuyOhkP6dOGWbQdaTfhcBRN22mYeI/k/Wh/Zh1OI21F6eKLApsVRmg15MoFnkrCz64RROC34sw==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5",
- "@jimp/plugin-color": ">=0.8.0",
- "@jimp/plugin-resize": ">=0.8.0"
- }
- },
- "node_modules/@jimp/plugins": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugins/-/plugins-0.16.2.tgz",
- "integrity": "sha512-zCvYtCgctmC0tkYEu+y+kSwSIZBsNznqJ3/3vkpzxdyjd6wCfNY5Qc/68MPrLc1lmdeGo4cOOTYHG7Vc6myzRw==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/plugin-blit": "^0.16.2",
- "@jimp/plugin-blur": "^0.16.2",
- "@jimp/plugin-circle": "^0.16.2",
- "@jimp/plugin-color": "^0.16.2",
- "@jimp/plugin-contain": "^0.16.2",
- "@jimp/plugin-cover": "^0.16.2",
- "@jimp/plugin-crop": "^0.16.2",
- "@jimp/plugin-displace": "^0.16.2",
- "@jimp/plugin-dither": "^0.16.2",
- "@jimp/plugin-fisheye": "^0.16.2",
- "@jimp/plugin-flip": "^0.16.2",
- "@jimp/plugin-gaussian": "^0.16.2",
- "@jimp/plugin-invert": "^0.16.2",
- "@jimp/plugin-mask": "^0.16.2",
- "@jimp/plugin-normalize": "^0.16.2",
- "@jimp/plugin-print": "^0.16.2",
- "@jimp/plugin-resize": "^0.16.2",
- "@jimp/plugin-rotate": "^0.16.2",
- "@jimp/plugin-scale": "^0.16.2",
- "@jimp/plugin-shadow": "^0.16.2",
- "@jimp/plugin-threshold": "^0.16.2",
- "timm": "^1.6.1"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
- }
- },
- "node_modules/@jimp/png": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/png/-/png-0.16.2.tgz",
- "integrity": "sha512-sFOtOSz/tzDwXEChFQ/Nxe+0+vG3Tj0eUxnZVDUG/StXE9dI8Bqmwj3MIa0EgK5s+QG3YlnDOmlPUa4JqmeYeQ==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2",
- "pngjs": "^3.3.3"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
- }
- },
- "node_modules/@jimp/tiff": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/tiff/-/tiff-0.16.2.tgz",
- "integrity": "sha512-ADcdqmtZF+U2YoaaHTzFX8D6NFpmN4WZUT0BPMerEuY7Cq8QoLYU22z2h034FrVW+Rbi1b3y04sB9iDiQAlf2w==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "utif": "^2.0.1"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
- }
- },
- "node_modules/@jimp/types": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/types/-/types-0.16.2.tgz",
- "integrity": "sha512-0Ue5Sq0XnDF6TirisWv5E+8uOnRcd8vRLuwocJOhF76NIlcQrz+5r2k2XWKcr3d+11n28dHLXW5TKSqrUopxhA==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/bmp": "^0.16.2",
- "@jimp/gif": "^0.16.2",
- "@jimp/jpeg": "^0.16.2",
- "@jimp/png": "^0.16.2",
- "@jimp/tiff": "^0.16.2",
- "timm": "^1.6.1"
- },
- "peerDependencies": {
- "@jimp/custom": ">=0.3.5"
- }
- },
- "node_modules/@jimp/utils": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-0.16.2.tgz",
- "integrity": "sha512-XENrPvmigiXZQ8E2nxJqO6UVvWBLzbNwyYi3Y8Q1IECoYhYI3kgOQ0fmy4G269Vz1V0omh1bNmC42r4OfXg1Jg==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "regenerator-runtime": "^0.13.3"
- }
- },
- "node_modules/@nodelib/fs.scandir": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
- "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
- "dev": true,
- "dependencies": {
- "@nodelib/fs.stat": "2.0.5",
- "run-parallel": "^1.1.9"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@nodelib/fs.stat": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
- "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
- "dev": true,
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@nodelib/fs.walk": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
- "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
- "dev": true,
- "dependencies": {
- "@nodelib/fs.scandir": "2.1.5",
- "fastq": "^1.6.0"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@root/mkdirp": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@root/mkdirp/-/mkdirp-1.0.0.tgz",
- "integrity": "sha512-hxGAYUx5029VggfG+U9naAhQkoMSXtOeXtbql97m3Hi6/sQSRL/4khKZPyOF6w11glyCOU38WCNLu9nUcSjOfA=="
- },
- "node_modules/@root/request": {
- "version": "1.9.2",
- "resolved": "https://registry.npmjs.org/@root/request/-/request-1.9.2.tgz",
- "integrity": "sha512-wVaL9yVV9oDR9UNbPZa20qgY+4Ch6YN8JUkaE4el/uuS5dmhD8Lusm/ku8qJVNtmQA56XLzEDCRS6/vfpiHK2A=="
- },
- "node_modules/@sendgrid/client": {
- "version": "6.5.5",
- "resolved": "https://registry.npmjs.org/@sendgrid/client/-/client-6.5.5.tgz",
- "integrity": "sha512-Nbfgo94gbWSL8PIgJfuHoifyOJJepvV8NQkkglctAEfb1hyozKhrzE6v1kPG/z4j0RodaTtXD5LJj/t0q/VhLA==",
- "dependencies": {
- "@sendgrid/helpers": "^6.5.5",
- "@types/request": "^2.48.4",
- "request": "^2.88.0"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@sendgrid/helpers": {
- "version": "6.5.5",
- "resolved": "https://registry.npmjs.org/@sendgrid/helpers/-/helpers-6.5.5.tgz",
- "integrity": "sha512-uRFEanalfss5hDsuzVXZ1wm7i7eEXHh1py80piOXjobiQ+MxmtR19EU+gDSXZ+uMcEehBGhxnb7QDNN0q65qig==",
- "dependencies": {
- "chalk": "^2.0.1",
- "deepmerge": "^4.2.2"
- },
- "engines": {
- "node": ">= 6.0.0"
- }
- },
- "node_modules/@sendgrid/mail": {
- "version": "6.5.5",
- "resolved": "https://registry.npmjs.org/@sendgrid/mail/-/mail-6.5.5.tgz",
- "integrity": "sha512-DSu8oTPI0BJFH60jMOG9gM+oeNMoRALFmdAYg2PIXpL+Zbxd7L2GzQZtmf1jLy/8UBImkbB3D74TjiOBiLRK1w==",
- "dependencies": {
- "@sendgrid/client": "^6.5.5",
- "@sendgrid/helpers": "^6.5.5"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@types/bson": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.5.tgz",
- "integrity": "sha512-vVLwMUqhYJSQ/WKcE60eFqcyuWse5fGH+NMAXHuKrUAPoryq3ATxk5o4bgYNtg5aOM4APVg7Hnb3ASqUYG0PKg==",
- "dependencies": {
- "@types/node": "*"
- }
- },
- "node_modules/@types/caseless": {
- "version": "0.12.2",
- "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz",
- "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w=="
- },
- "node_modules/@types/jsonwebtoken": {
- "version": "9.0.1",
- "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.1.tgz",
- "integrity": "sha512-c5ltxazpWabia/4UzhIoaDcIza4KViOQhdbjRlfcIGVnsE3c3brkz9Z+F/EeJIECOQP7W7US2hNE930cWWkPiw==",
- "dependencies": {
- "@types/node": "*"
- }
- },
- "node_modules/@types/mongodb": {
- "version": "3.6.20",
- "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.20.tgz",
- "integrity": "sha512-WcdpPJCakFzcWWD9juKoZbRtQxKIMYF/JIAM4JrNHrMcnJL6/a2NWjXxW7fo9hxboxxkg+icff8d7+WIEvKgYQ==",
- "dependencies": {
- "@types/bson": "*",
- "@types/node": "*"
- }
- },
- "node_modules/@types/node": {
- "version": "18.11.18",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz",
- "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA=="
- },
- "node_modules/@types/request": {
- "version": "2.48.8",
- "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.8.tgz",
- "integrity": "sha512-whjk1EDJPcAR2kYHRbFl/lKeeKYTi05A15K9bnLInCVroNDCtXce57xKdI0/rQaA3K+6q0eFyUBPmqfSndUZdQ==",
- "dependencies": {
- "@types/caseless": "*",
- "@types/node": "*",
- "@types/tough-cookie": "*",
- "form-data": "^2.5.0"
- }
- },
- "node_modules/@types/tough-cookie": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz",
- "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw=="
- },
- "node_modules/abbrev": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
- "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
- "dev": true
- },
- "node_modules/accepts": {
- "version": "1.3.8",
- "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
- "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
- "dependencies": {
- "mime-types": "~2.1.34",
- "negotiator": "0.6.3"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/acme": {
- "version": "1.3.5",
- "resolved": "https://registry.npmjs.org/acme/-/acme-1.3.5.tgz",
- "integrity": "sha512-KIFVyMho7y3RxRSTzkuX031TmfXwzl0ioy8+r2pnfLz6YWFQ5q7a/cYUDTgIbrFMPe/syY26Qv1DOdHQ5ARWcw==",
- "dependencies": {
- "acme-v2": "^1.8.6"
- }
- },
- "node_modules/acme-dns-01-cli": {
- "version": "3.0.7",
- "resolved": "https://registry.npmjs.org/acme-dns-01-cli/-/acme-dns-01-cli-3.0.7.tgz",
- "integrity": "sha512-Aa4bUpq6ftX1VODiShOetOY5U0tsXY5EV7+fQwme3Q8Y9rjYBArBXHgFCAVKtK1AF+Ev8pIuF6Z42hzMFa73/w=="
- },
- "node_modules/acme-v2": {
- "version": "1.8.6",
- "resolved": "https://registry.npmjs.org/acme-v2/-/acme-v2-1.8.6.tgz",
- "integrity": "sha512-LWdicUYHTGDtYX7LlgsQurmM9txwfAFydg7mQLPKHrFMnNNtfJEtHC2fWfr+pFGNb3XKIbvyFUoyFB6cOmWRpA==",
- "hasInstallScript": true,
- "dependencies": {
- "@root/request": "^1.3.11",
- "rsa-compat": "^2.0.8"
- }
- },
- "node_modules/acorn": {
- "version": "8.8.2",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
- "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
- "dev": true,
- "bin": {
- "acorn": "bin/acorn"
- },
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/acorn-jsx": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
- "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
- "dev": true,
- "peerDependencies": {
- "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
- }
- },
- "node_modules/ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "dependencies": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/epoberezkin"
- }
- },
- "node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dependencies": {
- "color-convert": "^1.9.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/any-base": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/any-base/-/any-base-1.1.0.tgz",
- "integrity": "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg=="
- },
- "node_modules/anymatch": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
- "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
- "dev": true,
- "dependencies": {
- "normalize-path": "^3.0.0",
- "picomatch": "^2.0.4"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/append-field": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
- "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw=="
- },
- "node_modules/argparse": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "dev": true
- },
- "node_modules/array-flatten": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
- "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
- },
- "node_modules/array-uniq": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.2.tgz",
- "integrity": "sha512-GVYjmpL05al4dNlKJm53mKE4w9OOLiuVHWorsIA3YVz+Hu0hcn6PtE3Ydl0EqU7v+7ABC4mjjWsnLUxbpno+CA==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/asn1": {
- "version": "0.2.6",
- "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
- "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
- "dependencies": {
- "safer-buffer": "~2.1.0"
- }
- },
- "node_modules/assert-plus": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
- "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==",
- "engines": {
- "node": ">=0.8"
- }
- },
- "node_modules/asynckit": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
- },
- "node_modules/aws-sign2": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
- "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==",
- "engines": {
- "node": "*"
- }
- },
- "node_modules/aws4": {
- "version": "1.12.0",
- "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz",
- "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg=="
- },
- "node_modules/balanced-match": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
- },
- "node_modules/base64-js": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
- "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ]
- },
- "node_modules/bcrypt-pbkdf": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
- "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
- "dependencies": {
- "tweetnacl": "^0.14.3"
- }
- },
- "node_modules/binary-extensions": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
- "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/binary-search": {
- "version": "1.3.6",
- "resolved": "https://registry.npmjs.org/binary-search/-/binary-search-1.3.6.tgz",
- "integrity": "sha512-nbE1WxOTTrUWIfsfZ4aHGYu5DOuNkbxGokjV6Z2kxfJK3uaAb8zNK1muzOeipoLHZjInT4Br88BHpzevc681xA=="
- },
- "node_modules/bl": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz",
- "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==",
- "dependencies": {
- "readable-stream": "^2.3.5",
- "safe-buffer": "^5.1.1"
- }
- },
- "node_modules/bluebird": {
- "version": "3.5.1",
- "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
- "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA=="
- },
- "node_modules/bmp-js": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz",
- "integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw=="
- },
- "node_modules/body-parser": {
- "version": "1.20.1",
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
- "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
- "dependencies": {
- "bytes": "3.1.2",
- "content-type": "~1.0.4",
- "debug": "2.6.9",
- "depd": "2.0.0",
- "destroy": "1.2.0",
- "http-errors": "2.0.0",
- "iconv-lite": "0.4.24",
- "on-finished": "2.4.1",
- "qs": "6.11.0",
- "raw-body": "2.5.1",
- "type-is": "~1.6.18",
- "unpipe": "1.0.0"
- },
- "engines": {
- "node": ">= 0.8",
- "npm": "1.2.8000 || >= 1.4.16"
- }
- },
- "node_modules/brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "dev": true,
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "node_modules/braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
- "dev": true,
- "dependencies": {
- "fill-range": "^7.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/bson": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz",
- "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==",
- "engines": {
- "node": ">=0.6.19"
- }
- },
- "node_modules/buffer": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
- "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "dependencies": {
- "base64-js": "^1.3.1",
- "ieee754": "^1.1.13"
- }
- },
- "node_modules/buffer-equal": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz",
- "integrity": "sha512-RgSV6InVQ9ODPdLWJ5UAqBqJBOg370Nz6ZQtRzpt6nUjc8v0St97uJ4PYC6NztqIScrAXafKM3mZPMygSe1ggA==",
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/buffer-equal-constant-time": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
- "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
- },
- "node_modules/buffer-from": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
- "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
- },
- "node_modules/busboy": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
- "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
- "dependencies": {
- "streamsearch": "^1.1.0"
- },
- "engines": {
- "node": ">=10.16.0"
- }
- },
- "node_modules/bytes": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
- "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/call-bind": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
- "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
- "dependencies": {
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/callsites": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
- "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/caseless": {
- "version": "0.12.0",
- "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
- "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw=="
- },
- "node_modules/cert-info": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/cert-info/-/cert-info-1.5.1.tgz",
- "integrity": "sha512-eoQC/yAgW3gKTKxjzyClvi+UzuY97YCjcl+lSqbsGIy7HeGaWxCPOQFivhUYm27hgsBMhsJJFya3kGvK6PMIcQ==",
- "bin": {
- "cert-info": "bin/cert-info.js"
- }
- },
- "node_modules/chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dependencies": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/chokidar": {
- "version": "3.5.3",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
- "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
- "dev": true,
- "funding": [
- {
- "type": "individual",
- "url": "https://paulmillr.com/funding/"
- }
- ],
- "dependencies": {
- "anymatch": "~3.1.2",
- "braces": "~3.0.2",
- "glob-parent": "~5.1.2",
- "is-binary-path": "~2.1.0",
- "is-glob": "~4.0.1",
- "normalize-path": "~3.0.0",
- "readdirp": "~3.6.0"
- },
- "engines": {
- "node": ">= 8.10.0"
- },
- "optionalDependencies": {
- "fsevents": "~2.3.2"
- }
- },
- "node_modules/chokidar/node_modules/glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dev": true,
- "dependencies": {
- "is-glob": "^4.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dependencies": {
- "color-name": "1.1.3"
- }
- },
- "node_modules/color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
- },
- "node_modules/combined-stream": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
- "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
- "dependencies": {
- "delayed-stream": "~1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
- "dev": true
- },
- "node_modules/concat-stream": {
- "version": "1.6.2",
- "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
- "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
- "engines": [
- "node >= 0.8"
- ],
- "dependencies": {
- "buffer-from": "^1.0.0",
- "inherits": "^2.0.3",
- "readable-stream": "^2.2.2",
- "typedarray": "^0.0.6"
- }
- },
- "node_modules/content-disposition": {
- "version": "0.5.4",
- "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
- "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
- "dependencies": {
- "safe-buffer": "5.2.1"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/content-type": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
- "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/cookie": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
- "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/cookie-signature": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
- "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
- },
- "node_modules/core-util-is": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
- "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
- },
- "node_modules/cors": {
- "version": "2.8.5",
- "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
- "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
- "dependencies": {
- "object-assign": "^4",
- "vary": "^1"
- },
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/cron-parser": {
- "version": "2.18.0",
- "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-2.18.0.tgz",
- "integrity": "sha512-s4odpheTyydAbTBQepsqd2rNWGa2iV3cyo8g7zbI2QQYGLVsfbhmwukayS1XHppe02Oy1fg7mg6xoaraVJeEcg==",
- "dependencies": {
- "is-nan": "^1.3.0",
- "moment-timezone": "^0.5.31"
- },
- "engines": {
- "node": ">=0.8"
- }
- },
- "node_modules/cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "dev": true,
- "dependencies": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/dashdash": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
- "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==",
- "dependencies": {
- "assert-plus": "^1.0.0"
- },
- "engines": {
- "node": ">=0.10"
- }
- },
- "node_modules/debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dependencies": {
- "ms": "2.0.0"
- }
- },
- "node_modules/deep-is": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
- "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
- "dev": true
- },
- "node_modules/deepmerge": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.0.tgz",
- "integrity": "sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/define-properties": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz",
- "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==",
- "dependencies": {
- "has-property-descriptors": "^1.0.0",
- "object-keys": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/delayed-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
- "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/denque": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz",
- "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==",
- "engines": {
- "node": ">=0.10"
- }
- },
- "node_modules/depd": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
- "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/destroy": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
- "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
- "engines": {
- "node": ">= 0.8",
- "npm": "1.2.8000 || >= 1.4.16"
- }
- },
- "node_modules/doctrine": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
- "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
- "dev": true,
- "dependencies": {
- "esutils": "^2.0.2"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/dom-serializer": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
- "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
- "dependencies": {
- "domelementtype": "^2.3.0",
- "domhandler": "^5.0.2",
- "entities": "^4.2.0"
- },
- "funding": {
- "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
- }
- },
- "node_modules/dom-walk": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz",
- "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w=="
- },
- "node_modules/domelementtype": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
- "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/fb55"
- }
- ]
- },
- "node_modules/domhandler": {
- "version": "5.0.3",
- "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
- "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
- "dependencies": {
- "domelementtype": "^2.3.0"
- },
- "engines": {
- "node": ">= 4"
- },
- "funding": {
- "url": "https://github.com/fb55/domhandler?sponsor=1"
- }
- },
- "node_modules/domutils": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
- "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==",
- "dependencies": {
- "dom-serializer": "^2.0.0",
- "domelementtype": "^2.3.0",
- "domhandler": "^5.0.1"
- },
- "funding": {
- "url": "https://github.com/fb55/domutils?sponsor=1"
- }
- },
- "node_modules/dotenv": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz",
- "integrity": "sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/ecc-jsbn": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
- "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==",
- "dependencies": {
- "jsbn": "~0.1.0",
- "safer-buffer": "^2.1.0"
- }
- },
- "node_modules/ecdsa-sig-formatter": {
- "version": "1.0.11",
- "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
- "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
- "dependencies": {
- "safe-buffer": "^5.0.1"
- }
- },
- "node_modules/eckles": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/eckles/-/eckles-1.4.1.tgz",
- "integrity": "sha512-auWyk/k8oSkVHaD4RxkPadKsLUcIwKgr/h8F7UZEueFDBO7BsE4y+H6IMUDbfqKIFPg/9MxV6KcBdJCmVVcxSA==",
- "bin": {
- "eckles": "bin/eckles.js"
- }
- },
- "node_modules/ee-first": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
- "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
- },
- "node_modules/encodeurl": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
- "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/entities": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
- "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==",
- "engines": {
- "node": ">=0.12"
- },
- "funding": {
- "url": "https://github.com/fb55/entities?sponsor=1"
- }
- },
- "node_modules/escape-html": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
- "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
- },
- "node_modules/escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/eslint": {
- "version": "8.33.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.33.0.tgz",
- "integrity": "sha512-WjOpFQgKK8VrCnAtl8We0SUOy/oVZ5NHykyMiagV1M9r8IFpIJX7DduK6n1mpfhlG7T1NLWm2SuD8QB7KFySaA==",
- "dev": true,
- "dependencies": {
- "@eslint/eslintrc": "^1.4.1",
- "@humanwhocodes/config-array": "^0.11.8",
- "@humanwhocodes/module-importer": "^1.0.1",
- "@nodelib/fs.walk": "^1.2.8",
- "ajv": "^6.10.0",
- "chalk": "^4.0.0",
- "cross-spawn": "^7.0.2",
- "debug": "^4.3.2",
- "doctrine": "^3.0.0",
- "escape-string-regexp": "^4.0.0",
- "eslint-scope": "^7.1.1",
- "eslint-utils": "^3.0.0",
- "eslint-visitor-keys": "^3.3.0",
- "espree": "^9.4.0",
- "esquery": "^1.4.0",
- "esutils": "^2.0.2",
- "fast-deep-equal": "^3.1.3",
- "file-entry-cache": "^6.0.1",
- "find-up": "^5.0.0",
- "glob-parent": "^6.0.2",
- "globals": "^13.19.0",
- "grapheme-splitter": "^1.0.4",
- "ignore": "^5.2.0",
- "import-fresh": "^3.0.0",
- "imurmurhash": "^0.1.4",
- "is-glob": "^4.0.0",
- "is-path-inside": "^3.0.3",
- "js-sdsl": "^4.1.4",
- "js-yaml": "^4.1.0",
- "json-stable-stringify-without-jsonify": "^1.0.1",
- "levn": "^0.4.1",
- "lodash.merge": "^4.6.2",
- "minimatch": "^3.1.2",
- "natural-compare": "^1.4.0",
- "optionator": "^0.9.1",
- "regexpp": "^3.2.0",
- "strip-ansi": "^6.0.1",
- "strip-json-comments": "^3.1.0",
- "text-table": "^0.2.0"
- },
- "bin": {
- "eslint": "bin/eslint.js"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/eslint-scope": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
- "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
- "dev": true,
- "dependencies": {
- "esrecurse": "^4.3.0",
- "estraverse": "^5.2.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- }
- },
- "node_modules/eslint-utils": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
- "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
- "dev": true,
- "dependencies": {
- "eslint-visitor-keys": "^2.0.0"
- },
- "engines": {
- "node": "^10.0.0 || ^12.0.0 || >= 14.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/mysticatea"
- },
- "peerDependencies": {
- "eslint": ">=5"
- }
- },
- "node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
- "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
- "dev": true,
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/eslint-visitor-keys": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
- "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
- "dev": true,
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- }
- },
- "node_modules/eslint/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/eslint/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/eslint/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/eslint/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/eslint/node_modules/debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "dev": true,
- "dependencies": {
- "ms": "2.1.2"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/eslint/node_modules/escape-string-regexp": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
- "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/eslint/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/eslint/node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- },
- "node_modules/eslint/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/espree": {
- "version": "9.4.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz",
- "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==",
- "dev": true,
- "dependencies": {
- "acorn": "^8.8.0",
- "acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^3.3.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/esquery": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
- "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
- "dev": true,
- "dependencies": {
- "estraverse": "^5.1.0"
- },
- "engines": {
- "node": ">=0.10"
- }
- },
- "node_modules/esrecurse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
- "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
- "dev": true,
- "dependencies": {
- "estraverse": "^5.2.0"
- },
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
- "dev": true,
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/esutils": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
- "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/etag": {
- "version": "1.8.1",
- "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
- "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/exif-parser": {
- "version": "0.1.12",
- "resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz",
- "integrity": "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw=="
- },
- "node_modules/express": {
- "version": "4.18.2",
- "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
- "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
- "dependencies": {
- "accepts": "~1.3.8",
- "array-flatten": "1.1.1",
- "body-parser": "1.20.1",
- "content-disposition": "0.5.4",
- "content-type": "~1.0.4",
- "cookie": "0.5.0",
- "cookie-signature": "1.0.6",
- "debug": "2.6.9",
- "depd": "2.0.0",
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "etag": "~1.8.1",
- "finalhandler": "1.2.0",
- "fresh": "0.5.2",
- "http-errors": "2.0.0",
- "merge-descriptors": "1.0.1",
- "methods": "~1.1.2",
- "on-finished": "2.4.1",
- "parseurl": "~1.3.3",
- "path-to-regexp": "0.1.7",
- "proxy-addr": "~2.0.7",
- "qs": "6.11.0",
- "range-parser": "~1.2.1",
- "safe-buffer": "5.2.1",
- "send": "0.18.0",
- "serve-static": "1.15.0",
- "setprototypeof": "1.2.0",
- "statuses": "2.0.1",
- "type-is": "~1.6.18",
- "utils-merge": "1.0.1",
- "vary": "~1.1.2"
- },
- "engines": {
- "node": ">= 0.10.0"
- }
- },
- "node_modules/express-fileupload": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/express-fileupload/-/express-fileupload-1.4.0.tgz",
- "integrity": "sha512-RjzLCHxkv3umDeZKeFeMg8w7qe0V09w3B7oGZprr/oO2H/ISCgNzuqzn7gV3HRWb37GjRk429CCpSLS2KNTqMQ==",
- "dependencies": {
- "busboy": "^1.6.0"
- },
- "engines": {
- "node": ">=12.0.0"
- }
- },
- "node_modules/express-handlebars": {
- "version": "6.0.7",
- "resolved": "https://registry.npmjs.org/express-handlebars/-/express-handlebars-6.0.7.tgz",
- "integrity": "sha512-iYeMFpc/hMD+E6FNAZA5fgWeXnXr4rslOSPkeEV6TwdmpJ5lEXuWX0u9vFYs31P2MURctQq2batR09oeNj0LIg==",
- "dependencies": {
- "glob": "^8.1.0",
- "graceful-fs": "^4.2.10",
- "handlebars": "^4.7.7"
- },
- "engines": {
- "node": ">=v12.22.9"
- }
- },
- "node_modules/express-jwt": {
- "version": "8.4.0",
- "resolved": "https://registry.npmjs.org/express-jwt/-/express-jwt-8.4.0.tgz",
- "integrity": "sha512-AvIkHI6+wuwHQTgfnl4kEPWeMKo5yw4FnXJJK+jf/PRWAflmuJKTs06ENRNJ6sCQceIUVqAi/fy8Nav8alnv0w==",
- "dependencies": {
- "@types/jsonwebtoken": "^9",
- "express-unless": "^2.1.3",
- "jsonwebtoken": "^9.0.0"
- },
- "engines": {
- "node": ">= 8.0.0"
- }
- },
- "node_modules/express-session": {
- "version": "1.17.3",
- "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.3.tgz",
- "integrity": "sha512-4+otWXlShYlG1Ma+2Jnn+xgKUZTMJ5QD3YvfilX3AcocOAbIkVylSWEklzALe/+Pu4qV6TYBj5GwOBFfdKqLBw==",
- "dependencies": {
- "cookie": "0.4.2",
- "cookie-signature": "1.0.6",
- "debug": "2.6.9",
- "depd": "~2.0.0",
- "on-headers": "~1.0.2",
- "parseurl": "~1.3.3",
- "safe-buffer": "5.2.1",
- "uid-safe": "~2.1.5"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/express-session/node_modules/cookie": {
- "version": "0.4.2",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
- "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/express-unless": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/express-unless/-/express-unless-2.1.3.tgz",
- "integrity": "sha512-wj4tLMyCVYuIIKHGt0FhCtIViBcwzWejX0EjNxveAa6dG+0XBCQhMbx+PnkLkFCxLC69qoFrxds4pIyL88inaQ=="
- },
- "node_modules/express-validator": {
- "version": "6.14.3",
- "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-6.14.3.tgz",
- "integrity": "sha512-c4b9NMdhskfcLbH/FchsSfCt4Vb14gKzcotG9zLS+VoOJDox57aGhCL+kmAu7cl+ytaSed+HD5jdJhel8DQsdg==",
- "dependencies": {
- "lodash": "^4.17.21",
- "validator": "^13.7.0"
- },
- "engines": {
- "node": ">= 8.0.0"
- }
- },
- "node_modules/extend": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
- "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
- },
- "node_modules/extsprintf": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
- "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==",
- "engines": [
- "node >=0.6.0"
- ]
- },
- "node_modules/fast-deep-equal": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
- },
- "node_modules/fast-json-stable-stringify": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
- },
- "node_modules/fast-levenshtein": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
- "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
- "dev": true
- },
- "node_modules/fastq": {
- "version": "1.15.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
- "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
- "dev": true,
- "dependencies": {
- "reusify": "^1.0.4"
- }
- },
- "node_modules/file-entry-cache": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
- "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
- "dev": true,
- "dependencies": {
- "flat-cache": "^3.0.4"
- },
- "engines": {
- "node": "^10.12.0 || >=12.0.0"
- }
- },
- "node_modules/file-type": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/file-type/-/file-type-9.0.0.tgz",
- "integrity": "sha512-Qe/5NJrgIOlwijpq3B7BEpzPFcgzggOTagZmkXQY4LA6bsXKTUstK7Wp12lEJ/mLKTpvIZxmIuRcLYWT6ov9lw==",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "dev": true,
- "dependencies": {
- "to-regex-range": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/finalhandler": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
- "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
- "dependencies": {
- "debug": "2.6.9",
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "on-finished": "2.4.1",
- "parseurl": "~1.3.3",
- "statuses": "2.0.1",
- "unpipe": "~1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/find-up": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
- "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
- "dev": true,
- "dependencies": {
- "locate-path": "^6.0.0",
- "path-exists": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/flat-cache": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
- "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
- "dev": true,
- "dependencies": {
- "flatted": "^3.1.0",
- "rimraf": "^3.0.2"
- },
- "engines": {
- "node": "^10.12.0 || >=12.0.0"
- }
- },
- "node_modules/flatted": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
- "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
- "dev": true
- },
- "node_modules/forever-agent": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
- "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==",
- "engines": {
- "node": "*"
- }
- },
- "node_modules/form-data": {
- "version": "2.5.1",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
- "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
- "dependencies": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.6",
- "mime-types": "^2.1.12"
- },
- "engines": {
- "node": ">= 0.12"
- }
- },
- "node_modules/forwarded": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
- "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/fresh": {
- "version": "0.5.2",
- "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
- "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
- },
- "node_modules/fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "dev": true,
- "hasInstallScript": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
- "node_modules/function-bind": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
- },
- "node_modules/generate-rsa-keypair": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/generate-rsa-keypair/-/generate-rsa-keypair-0.2.1.tgz",
- "integrity": "sha512-vxLfzfy6WbMLtkKV4AJtg7QH0ZqGGNkSYM6S0Q72Z70QXsztLklKFtX15te3YLIqmiQAYi3g3MWsTfXd6djkpg==",
- "hasInstallScript": true,
- "engines": {
- "node": ">=8.6.0"
- }
- },
- "node_modules/get-intrinsic": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
- "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
- "dependencies": {
- "function-bind": "^1.1.1",
- "has": "^1.0.3",
- "has-symbols": "^1.0.3"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/getpass": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
- "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==",
- "dependencies": {
- "assert-plus": "^1.0.0"
- }
- },
- "node_modules/gifwrap": {
- "version": "0.9.4",
- "resolved": "https://registry.npmjs.org/gifwrap/-/gifwrap-0.9.4.tgz",
- "integrity": "sha512-MDMwbhASQuVeD4JKd1fKgNgCRL3fGqMM4WaqpNhWO0JiMOAjbQdumbs4BbBZEy9/M00EHEjKN3HieVhCUlwjeQ==",
- "dependencies": {
- "image-q": "^4.0.0",
- "omggif": "^1.0.10"
- }
- },
- "node_modules/glob": {
- "version": "8.1.0",
- "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
- "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^5.0.1",
- "once": "^1.3.0"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/glob-parent": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
- "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
- "dev": true,
- "dependencies": {
- "is-glob": "^4.0.3"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/glob/node_modules/brace-expansion": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
- "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
- },
- "node_modules/glob/node_modules/minimatch": {
- "version": "5.1.6",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
- "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
- "dependencies": {
- "brace-expansion": "^2.0.1"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/global": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz",
- "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==",
- "dependencies": {
- "min-document": "^2.19.0",
- "process": "^0.11.10"
- }
- },
- "node_modules/globals": {
- "version": "13.20.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
- "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
- "dev": true,
- "dependencies": {
- "type-fest": "^0.20.2"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/graceful-fs": {
- "version": "4.2.10",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
- "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="
- },
- "node_modules/grapheme-splitter": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
- "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
- "dev": true
- },
- "node_modules/greenlock": {
- "version": "2.8.8",
- "resolved": "https://registry.npmjs.org/greenlock/-/greenlock-2.8.8.tgz",
- "integrity": "sha512-U2pqxXXf0naeZc2363Xe174C6/T9lXGZYQjXBqa/PMb1CYRQuHwXlAqFEUu75JkxyHAzFGj/uliqSyQwIc91Yg==",
- "dependencies": {
- "acme": "^1.3.5",
- "acme-dns-01-cli": "^3.0.0",
- "acme-v2": "^1.8.6",
- "cert-info": "^1.5.1",
- "greenlock-store-fs": "^3.0.2",
- "keypairs": "^1.2.14",
- "le-challenge-fs": "^2.0.2",
- "le-sni-auto": "^2.1.9",
- "le-store-certbot": "^2.2.3",
- "rsa-compat": "^2.0.8"
- },
- "engines": {
- "node": ">=4.5"
- }
- },
- "node_modules/greenlock-express": {
- "version": "2.7.18",
- "resolved": "https://registry.npmjs.org/greenlock-express/-/greenlock-express-2.7.18.tgz",
- "integrity": "sha512-8gOSo4twkd4Fdmc45jfHMCXdsYnYutcUGDKZ+FRZH8XQc712glqYNrWaeWThmh0QQ/ZEiV+WGROtAdGrY5sGlQ==",
- "dependencies": {
- "greenlock": "^2.8.8",
- "redirect-https": "^1.1.5"
- }
- },
- "node_modules/greenlock-store-fs": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/greenlock-store-fs/-/greenlock-store-fs-3.2.2.tgz",
- "integrity": "sha512-92ejLB4DyV4qv/2b6VLGF2nKfYQeIfg3o+e/1cIoYLjlIaUFdbBXkzLTRozFlHsQPZt2ALi5qYrpC9IwH7GK8A==",
- "dependencies": {
- "@root/mkdirp": "^1.0.0",
- "safe-replace": "^1.1.0"
- }
- },
- "node_modules/handlebars": {
- "version": "4.7.7",
- "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz",
- "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==",
- "dependencies": {
- "minimist": "^1.2.5",
- "neo-async": "^2.6.0",
- "source-map": "^0.6.1",
- "wordwrap": "^1.0.0"
- },
- "bin": {
- "handlebars": "bin/handlebars"
- },
- "engines": {
- "node": ">=0.4.7"
- },
- "optionalDependencies": {
- "uglify-js": "^3.1.4"
- }
- },
- "node_modules/har-schema": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
- "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/har-validator": {
- "version": "5.1.5",
- "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
- "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
- "deprecated": "this library is no longer supported",
- "dependencies": {
- "ajv": "^6.12.3",
- "har-schema": "^2.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/has": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
- "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
- "dependencies": {
- "function-bind": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4.0"
- }
- },
- "node_modules/has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/has-property-descriptors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
- "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
- "dependencies": {
- "get-intrinsic": "^1.1.1"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-symbols": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
- "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/htmlparser2": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz",
- "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==",
- "funding": [
- "https://github.com/fb55/htmlparser2?sponsor=1",
- {
- "type": "github",
- "url": "https://github.com/sponsors/fb55"
- }
- ],
- "dependencies": {
- "domelementtype": "^2.3.0",
- "domhandler": "^5.0.2",
- "domutils": "^3.0.1",
- "entities": "^4.3.0"
- }
- },
- "node_modules/http-errors": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
- "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
- "dependencies": {
- "depd": "2.0.0",
- "inherits": "2.0.4",
- "setprototypeof": "1.2.0",
- "statuses": "2.0.1",
- "toidentifier": "1.0.1"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/http-signature": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
- "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==",
- "dependencies": {
- "assert-plus": "^1.0.0",
- "jsprim": "^1.2.2",
- "sshpk": "^1.7.0"
- },
- "engines": {
- "node": ">=0.8",
- "npm": ">=1.3.7"
- }
- },
- "node_modules/ical": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/ical/-/ical-0.6.0.tgz",
- "integrity": "sha512-P7R3uMhFnLY7Tfiz+2uZIninThWIoUM5BVO4f9ZsV36GYqoBkIg6RbkrBhmWCvcuK1vLzljLaNtpWeGM/5ZHRg==",
- "dependencies": {
- "request": "^2.88.0",
- "rrule": "2.4.1"
- }
- },
- "node_modules/ical-generator": {
- "version": "1.15.4",
- "resolved": "https://registry.npmjs.org/ical-generator/-/ical-generator-1.15.4.tgz",
- "integrity": "sha512-drXe4RLkfNlvDvdy/E6BUI9p+01L3ySK1ufNEYI9TxNKG9ZA3G60QWoZvD1dtmH4scwDxYu6/sZBPJvYVNrj8A==",
- "dependencies": {
- "moment-timezone": "^0.5.32"
- },
- "engines": {
- "node": ">=6.0.0"
- },
- "peerDependencies": {
- "@types/node": ">= 8.0.0"
- }
- },
- "node_modules/iconv-lite": {
- "version": "0.4.24",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
- "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
- "dependencies": {
- "safer-buffer": ">= 2.1.2 < 3"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/ieee754": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
- "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ]
- },
- "node_modules/ignore": {
- "version": "5.2.4",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
- "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
- "dev": true,
- "engines": {
- "node": ">= 4"
- }
- },
- "node_modules/ignore-by-default": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
- "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
- "dev": true
- },
- "node_modules/image-q": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/image-q/-/image-q-4.0.0.tgz",
- "integrity": "sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw==",
- "dependencies": {
- "@types/node": "16.9.1"
- }
- },
- "node_modules/image-q/node_modules/@types/node": {
- "version": "16.9.1",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.1.tgz",
- "integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g=="
- },
- "node_modules/import-fresh": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
- "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
- "dev": true,
- "dependencies": {
- "parent-module": "^1.0.0",
- "resolve-from": "^4.0.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/imurmurhash": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
- "dev": true,
- "engines": {
- "node": ">=0.8.19"
- }
- },
- "node_modules/inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
- "dependencies": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "node_modules/inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
- },
- "node_modules/ipaddr.js": {
- "version": "1.9.1",
- "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
- "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/is-binary-path": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
- "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
- "dev": true,
- "dependencies": {
- "binary-extensions": "^2.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/is-extglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-function": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz",
- "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ=="
- },
- "node_modules/is-glob": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
- "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "dev": true,
- "dependencies": {
- "is-extglob": "^2.1.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-nan": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz",
- "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==",
- "dependencies": {
- "call-bind": "^1.0.0",
- "define-properties": "^1.1.3"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true,
- "engines": {
- "node": ">=0.12.0"
- }
- },
- "node_modules/is-path-inside": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
- "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/is-plain-object": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
- "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-typedarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
- "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
- },
- "node_modules/isarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
- },
- "node_modules/isexe": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
- "dev": true
- },
- "node_modules/isstream": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
- "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g=="
- },
- "node_modules/jimp": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/jimp/-/jimp-0.16.2.tgz",
- "integrity": "sha512-UpItBk81a92f8oEyoGYbO3YK4QcM0hoIyuGHmShoF9Ov63P5Qo7Q/X2xsAgnODmSuDJFOtrPtJd5GSWW4LKdOQ==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "@jimp/custom": "^0.16.2",
- "@jimp/plugins": "^0.16.2",
- "@jimp/types": "^0.16.2",
- "regenerator-runtime": "^0.13.3"
- }
- },
- "node_modules/jpeg-js": {
- "version": "0.4.4",
- "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz",
- "integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg=="
- },
- "node_modules/js-sdsl": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz",
- "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==",
- "dev": true,
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/js-sdsl"
- }
- },
- "node_modules/js-yaml": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
- "dev": true,
- "dependencies": {
- "argparse": "^2.0.1"
- },
- "bin": {
- "js-yaml": "bin/js-yaml.js"
- }
- },
- "node_modules/jsbn": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
- "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg=="
- },
- "node_modules/json-schema": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
- "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="
- },
- "node_modules/json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
- },
- "node_modules/json-stable-stringify-without-jsonify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
- "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
- "dev": true
- },
- "node_modules/json-stringify-safe": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
- "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="
- },
- "node_modules/jsonwebtoken": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz",
- "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==",
- "dependencies": {
- "jws": "^3.2.2",
- "lodash": "^4.17.21",
- "ms": "^2.1.1",
- "semver": "^7.3.8"
- },
- "engines": {
- "node": ">=12",
- "npm": ">=6"
- }
- },
- "node_modules/jsonwebtoken/node_modules/ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
- },
- "node_modules/jsonwebtoken/node_modules/semver": {
- "version": "7.3.8",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
- "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/jsprim": {
- "version": "1.4.2",
- "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
- "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==",
- "dependencies": {
- "assert-plus": "1.0.0",
- "extsprintf": "1.3.0",
- "json-schema": "0.4.0",
- "verror": "1.10.0"
- },
- "engines": {
- "node": ">=0.6.0"
- }
- },
- "node_modules/jwa": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
- "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
- "dependencies": {
- "buffer-equal-constant-time": "1.0.1",
- "ecdsa-sig-formatter": "1.0.11",
- "safe-buffer": "^5.0.1"
- }
- },
- "node_modules/jws": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
- "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
- "dependencies": {
- "jwa": "^1.4.1",
- "safe-buffer": "^5.0.1"
- }
- },
- "node_modules/kareem": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.2.tgz",
- "integrity": "sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ=="
- },
- "node_modules/keypairs": {
- "version": "1.2.14",
- "resolved": "https://registry.npmjs.org/keypairs/-/keypairs-1.2.14.tgz",
- "integrity": "sha512-ZoZfZMygyB0QcjSlz7Rh6wT2CJasYEHBPETtmHZEfxuJd7bnsOG5AdtPZqHZBT+hoHvuWCp/4y8VmvTvH0Y9uA==",
- "dependencies": {
- "eckles": "^1.4.1",
- "rasha": "^1.2.4"
- },
- "bin": {
- "keypairs-install": "bin/keypairs.js"
- }
- },
- "node_modules/le-challenge-fs": {
- "version": "2.0.9",
- "resolved": "https://registry.npmjs.org/le-challenge-fs/-/le-challenge-fs-2.0.9.tgz",
- "integrity": "sha512-stzI6rxd+aXGxBl87QJKKY/i/wl3uz6EoWzX2xSazJvCPSYBQys1RVNgOcf0SfUQPh6TBCFJFSJkiR4mznb4sg==",
- "dependencies": {
- "@root/mkdirp": "^1.0.0"
- }
- },
- "node_modules/le-sni-auto": {
- "version": "2.1.9",
- "resolved": "https://registry.npmjs.org/le-sni-auto/-/le-sni-auto-2.1.9.tgz",
- "integrity": "sha512-QmQHNwQDi/56GY8+qczFZ06FZbxaeJQjbjEhwwQHhkJ9IHhIQFkPfCT/OyDfLj4gqLIrg5ZX8CemxxVZnLEYfg=="
- },
- "node_modules/le-store-certbot": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/le-store-certbot/-/le-store-certbot-2.2.3.tgz",
- "integrity": "sha512-c4ACR+v+JKMiAOOshLh6gdCKA7wIWR16+mROMLpQjq3rXJ3Vm8FaBHe2H+crT+flP+g7FmciAwUlfOJEJpIuCQ==",
- "dependencies": {
- "@root/mkdirp": "^1.0.0",
- "pyconf": "^1.1.7",
- "safe-replace": "^1.1.0"
- }
- },
- "node_modules/levn": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
- "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
- "dev": true,
- "dependencies": {
- "prelude-ls": "^1.2.1",
- "type-check": "~0.4.0"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/load-bmfont": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.4.1.tgz",
- "integrity": "sha512-8UyQoYmdRDy81Brz6aLAUhfZLwr5zV0L3taTQ4hju7m6biuwiWiJXjPhBJxbUQJA8PrkvJ/7Enqmwk2sM14soA==",
- "dependencies": {
- "buffer-equal": "0.0.1",
- "mime": "^1.3.4",
- "parse-bmfont-ascii": "^1.0.3",
- "parse-bmfont-binary": "^1.0.5",
- "parse-bmfont-xml": "^1.1.4",
- "phin": "^2.9.1",
- "xhr": "^2.0.1",
- "xtend": "^4.0.0"
- }
- },
- "node_modules/locate-path": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
- "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
- "dev": true,
- "dependencies": {
- "p-locate": "^5.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
- },
- "node_modules/lodash.merge": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
- "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
- "dev": true
- },
- "node_modules/long-timeout": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/long-timeout/-/long-timeout-0.1.1.tgz",
- "integrity": "sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w=="
- },
- "node_modules/lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/luxon": {
- "version": "1.28.1",
- "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.1.tgz",
- "integrity": "sha512-gYHAa180mKrNIUJCbwpmD0aTu9kV0dREDrwNnuyFAsO1Wt0EVYSZelPnJlbj9HplzXX/YWXHFTL45kvZ53M0pw==",
- "optional": true,
- "engines": {
- "node": "*"
- }
- },
- "node_modules/marked": {
- "version": "4.2.12",
- "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.12.tgz",
- "integrity": "sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw==",
- "bin": {
- "marked": "bin/marked.js"
- },
- "engines": {
- "node": ">= 12"
- }
- },
- "node_modules/media-typer": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
- "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/memory-pager": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
- "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
- "optional": true
- },
- "node_modules/merge-descriptors": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
- "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
- },
- "node_modules/methods": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
- "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/mime": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
- "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
- "bin": {
- "mime": "cli.js"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/mime-types": {
- "version": "2.1.35",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
- "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "dependencies": {
- "mime-db": "1.52.0"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/min-document": {
- "version": "2.19.0",
- "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",
- "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==",
- "dependencies": {
- "dom-walk": "^0.1.0"
- }
- },
- "node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/minimist": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
- "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/mkdirp": {
- "version": "0.5.6",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
- "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
- "dependencies": {
- "minimist": "^1.2.6"
- },
- "bin": {
- "mkdirp": "bin/cmd.js"
- }
- },
- "node_modules/moment": {
- "version": "2.29.4",
- "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
- "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
- "engines": {
- "node": "*"
- }
- },
- "node_modules/moment-timezone": {
- "version": "0.5.40",
- "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.40.tgz",
- "integrity": "sha512-tWfmNkRYmBkPJz5mr9GVDn9vRlVZOTe6yqY92rFxiOdWXbjaR0+9LwQnZGGuNR63X456NqmEkbskte8tWL5ePg==",
- "dependencies": {
- "moment": ">= 2.9.0"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/mongodb": {
- "version": "3.7.3",
- "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.3.tgz",
- "integrity": "sha512-Psm+g3/wHXhjBEktkxXsFMZvd3nemI0r3IPsE0bU+4//PnvNWKkzhZcEsbPcYiWqe8XqXJJEg4Tgtr7Raw67Yw==",
- "dependencies": {
- "bl": "^2.2.1",
- "bson": "^1.1.4",
- "denque": "^1.4.1",
- "optional-require": "^1.1.8",
- "safe-buffer": "^5.1.2"
- },
- "engines": {
- "node": ">=4"
- },
- "optionalDependencies": {
- "saslprep": "^1.0.0"
- },
- "peerDependenciesMeta": {
- "aws4": {
- "optional": true
- },
- "bson-ext": {
- "optional": true
- },
- "kerberos": {
- "optional": true
- },
- "mongodb-client-encryption": {
- "optional": true
- },
- "mongodb-extjson": {
- "optional": true
- },
- "snappy": {
- "optional": true
- }
- }
- },
- "node_modules/mongodb/node_modules/optional-require": {
- "version": "1.1.8",
- "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.1.8.tgz",
- "integrity": "sha512-jq83qaUb0wNg9Krv1c5OQ+58EK+vHde6aBPzLvPPqJm89UQWsvSuFy9X/OSNJnFeSOKo7btE0n8Nl2+nE+z5nA==",
- "dependencies": {
- "require-at": "^1.0.6"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/mongoose": {
- "version": "5.13.15",
- "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.15.tgz",
- "integrity": "sha512-cxp1Gbb8yUWkaEbajdhspSaKzAvsIvOtRlYD87GN/P2QEUhpd6bIvebi36T6M0tIVAMauNaK9SPA055N3PwF8Q==",
- "dependencies": {
- "@types/bson": "1.x || 4.0.x",
- "@types/mongodb": "^3.5.27",
- "bson": "^1.1.4",
- "kareem": "2.3.2",
- "mongodb": "3.7.3",
- "mongoose-legacy-pluralize": "1.0.2",
- "mpath": "0.8.4",
- "mquery": "3.2.5",
- "ms": "2.1.2",
- "optional-require": "1.0.x",
- "regexp-clone": "1.0.0",
- "safe-buffer": "5.2.1",
- "sift": "13.5.2",
- "sliced": "1.0.1"
- },
- "engines": {
- "node": ">=4.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/mongoose"
- }
- },
- "node_modules/mongoose-legacy-pluralize": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz",
- "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==",
- "peerDependencies": {
- "mongoose": "*"
- }
- },
- "node_modules/mongoose/node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
- },
- "node_modules/mpath": {
- "version": "0.8.4",
- "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.8.4.tgz",
- "integrity": "sha512-DTxNZomBcTWlrMW76jy1wvV37X/cNNxPW1y2Jzd4DZkAaC5ZGsm8bfGfNOthcDuRJujXLqiuS6o3Tpy0JEoh7g==",
- "engines": {
- "node": ">=4.0.0"
- }
- },
- "node_modules/mquery": {
- "version": "3.2.5",
- "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.5.tgz",
- "integrity": "sha512-VjOKHHgU84wij7IUoZzFRU07IAxd5kWJaDmyUzQlbjHjyoeK5TNeeo8ZsFDtTYnSgpW6n/nMNIHvE3u8Lbrf4A==",
- "dependencies": {
- "bluebird": "3.5.1",
- "debug": "3.1.0",
- "regexp-clone": "^1.0.0",
- "safe-buffer": "5.1.2",
- "sliced": "1.0.1"
- },
- "engines": {
- "node": ">=4.0.0"
- }
- },
- "node_modules/mquery/node_modules/debug": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
- "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
- "dependencies": {
- "ms": "2.0.0"
- }
- },
- "node_modules/mquery/node_modules/safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
- },
- "node_modules/ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
- },
- "node_modules/multer": {
- "version": "1.4.5-lts.1",
- "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz",
- "integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==",
- "dependencies": {
- "append-field": "^1.0.0",
- "busboy": "^1.0.0",
- "concat-stream": "^1.5.2",
- "mkdirp": "^0.5.4",
- "object-assign": "^4.1.1",
- "type-is": "^1.6.4",
- "xtend": "^4.0.0"
- },
- "engines": {
- "node": ">= 6.0.0"
- }
- },
- "node_modules/nanoid": {
- "version": "3.3.4",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
- "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
- "bin": {
- "nanoid": "bin/nanoid.cjs"
- },
- "engines": {
- "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
- }
- },
- "node_modules/natural-compare": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
- "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
- "dev": true
- },
- "node_modules/negotiator": {
- "version": "0.6.3",
- "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
- "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/neo-async": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
- "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
- },
- "node_modules/niceware": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/niceware/-/niceware-3.0.0.tgz",
- "integrity": "sha512-DbeDuqe836Ba4S9vjim4jTbbqmjCMwuAXFCVdh4QAvbmLOhmIQs84IakYrcXd/87VCsj1XKhSmmg7bAmwAEh5A==",
- "dependencies": {
- "binary-search": "^1.3.6",
- "randombytes": "^2.0.6"
- }
- },
- "node_modules/node-schedule": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/node-schedule/-/node-schedule-1.3.3.tgz",
- "integrity": "sha512-uF9Ubn6luOPrcAYKfsXWimcJ1tPFtQ8I85wb4T3NgJQrXazEzojcFZVk46ZlLHby3eEJChgkV/0T689IsXh2Gw==",
- "dependencies": {
- "cron-parser": "^2.18.0",
- "long-timeout": "0.1.1",
- "sorted-array-functions": "^1.3.0"
- }
- },
- "node_modules/nodemailer": {
- "version": "6.9.1",
- "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.1.tgz",
- "integrity": "sha512-qHw7dOiU5UKNnQpXktdgQ1d3OFgRAekuvbJLcdG5dnEo/GtcTHRYM7+UfJARdOFU9WUQO8OiIamgWPmiSFHYAA==",
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/nodemon": {
- "version": "2.0.20",
- "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz",
- "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==",
- "dev": true,
- "dependencies": {
- "chokidar": "^3.5.2",
- "debug": "^3.2.7",
- "ignore-by-default": "^1.0.1",
- "minimatch": "^3.1.2",
- "pstree.remy": "^1.1.8",
- "semver": "^5.7.1",
- "simple-update-notifier": "^1.0.7",
- "supports-color": "^5.5.0",
- "touch": "^3.1.0",
- "undefsafe": "^2.0.5"
- },
- "bin": {
- "nodemon": "bin/nodemon.js"
- },
- "engines": {
- "node": ">=8.10.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/nodemon"
- }
- },
- "node_modules/nodemon/node_modules/debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "dev": true,
- "dependencies": {
- "ms": "^2.1.1"
- }
- },
- "node_modules/nodemon/node_modules/ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
- "dev": true
- },
- "node_modules/nopt": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
- "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==",
- "dev": true,
- "dependencies": {
- "abbrev": "1"
- },
- "bin": {
- "nopt": "bin/nopt.js"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/normalize-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
- "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/oauth-sign": {
- "version": "0.9.0",
- "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
- "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
- "engines": {
- "node": "*"
- }
- },
- "node_modules/object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/object-inspect": {
- "version": "1.12.3",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
- "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/object-keys": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
- "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/omggif": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/omggif/-/omggif-1.0.10.tgz",
- "integrity": "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw=="
- },
- "node_modules/on-finished": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
- "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
- "dependencies": {
- "ee-first": "1.1.1"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/on-headers": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
- "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
- "dependencies": {
- "wrappy": "1"
- }
- },
- "node_modules/optional-require": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz",
- "integrity": "sha512-RV2Zp2MY2aeYK5G+B/Sps8lW5NHAzE5QClbFP15j+PWmP+T9PxlJXBOOLoSAdgwFvS4t0aMR4vpedMkbHfh0nA==",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/optionator": {
- "version": "0.9.1",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
- "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
- "dev": true,
- "dependencies": {
- "deep-is": "^0.1.3",
- "fast-levenshtein": "^2.0.6",
- "levn": "^0.4.1",
- "prelude-ls": "^1.2.1",
- "type-check": "^0.4.0",
- "word-wrap": "^1.2.3"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "dependencies": {
- "yocto-queue": "^0.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/p-locate": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
- "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
- "dev": true,
- "dependencies": {
- "p-limit": "^3.0.2"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/pako": {
- "version": "1.0.11",
- "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
- "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
- },
- "node_modules/parent-module": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
- "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
- "dev": true,
- "dependencies": {
- "callsites": "^3.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/parse-bmfont-ascii": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/parse-bmfont-ascii/-/parse-bmfont-ascii-1.0.6.tgz",
- "integrity": "sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA=="
- },
- "node_modules/parse-bmfont-binary": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/parse-bmfont-binary/-/parse-bmfont-binary-1.0.6.tgz",
- "integrity": "sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA=="
- },
- "node_modules/parse-bmfont-xml": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/parse-bmfont-xml/-/parse-bmfont-xml-1.1.4.tgz",
- "integrity": "sha512-bjnliEOmGv3y1aMEfREMBJ9tfL3WR0i0CKPj61DnSLaoxWR3nLrsQrEbCId/8rF4NyRF0cCqisSVXyQYWM+mCQ==",
- "dependencies": {
- "xml-parse-from-string": "^1.0.0",
- "xml2js": "^0.4.5"
- }
- },
- "node_modules/parse-headers": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz",
- "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA=="
- },
- "node_modules/parse-srcset": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz",
- "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q=="
- },
- "node_modules/parseurl": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
- "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/path-key": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/path-to-regexp": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
- "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
- },
- "node_modules/performance-now": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
- "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
- },
- "node_modules/phin": {
- "version": "2.9.3",
- "resolved": "https://registry.npmjs.org/phin/-/phin-2.9.3.tgz",
- "integrity": "sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA=="
- },
- "node_modules/picocolors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
- "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
- },
- "node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
- "dev": true,
- "engines": {
- "node": ">=8.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
- },
- "node_modules/pixelmatch": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz",
- "integrity": "sha512-J8B6xqiO37sU/gkcMglv6h5Jbd9xNER7aHzpfRdNmV4IbQBzBpe4l9XmbG+xPF/znacgu2jfEw+wHffaq/YkXA==",
- "dependencies": {
- "pngjs": "^3.0.0"
- },
- "bin": {
- "pixelmatch": "bin/pixelmatch"
- }
- },
- "node_modules/pngjs": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz",
- "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==",
- "engines": {
- "node": ">=4.0.0"
- }
- },
- "node_modules/postcss": {
- "version": "8.4.21",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz",
- "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==",
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/postcss/"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/postcss"
- }
- ],
- "dependencies": {
- "nanoid": "^3.3.4",
- "picocolors": "^1.0.0",
- "source-map-js": "^1.0.2"
- },
- "engines": {
- "node": "^10 || ^12 || >=14"
- }
- },
- "node_modules/prelude-ls": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
- "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
- "dev": true,
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/process": {
- "version": "0.11.10",
- "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
- "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
- "engines": {
- "node": ">= 0.6.0"
- }
- },
- "node_modules/process-nextick-args": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
- "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
- },
- "node_modules/proxy-addr": {
- "version": "2.0.7",
- "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
- "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
- "dependencies": {
- "forwarded": "0.2.0",
- "ipaddr.js": "1.9.1"
- },
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/psl": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
- "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag=="
- },
- "node_modules/pstree.remy": {
- "version": "1.1.8",
- "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
- "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
- "dev": true
- },
- "node_modules/punycode": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
- "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/pyconf": {
- "version": "1.1.7",
- "resolved": "https://registry.npmjs.org/pyconf/-/pyconf-1.1.7.tgz",
- "integrity": "sha512-v4clh33m68sjtMsh8XMpjhGWb/MQODAYZ1y7ORG5Qv58UK25OddoB+oXyexgDkK8ttFui/lZm2sQDgA2Ftjfkw==",
- "dependencies": {
- "safe-replace": "^1.0.2"
- }
- },
- "node_modules/qs": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
- "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
- "dependencies": {
- "side-channel": "^1.0.4"
- },
- "engines": {
- "node": ">=0.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/queue-microtask": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
- "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ]
- },
- "node_modules/random-bytes": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
- "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/randombytes": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
- "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
- "dependencies": {
- "safe-buffer": "^5.1.0"
- }
- },
- "node_modules/randomstring": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/randomstring/-/randomstring-1.2.3.tgz",
- "integrity": "sha512-3dEFySepTzp2CvH6W/ASYGguPPveBuz5MpZ7MuoUkoVehmyNl9+F9c9GFVrz2QPbM9NXTIHGcmJDY/3j4677kQ==",
- "dependencies": {
- "array-uniq": "1.0.2",
- "randombytes": "2.0.3"
- },
- "bin": {
- "randomstring": "bin/randomstring"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/randomstring/node_modules/randombytes": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.3.tgz",
- "integrity": "sha512-lDVjxQQFoCG1jcrP06LNo2lbWp4QTShEXnhActFBwYuHprllQV6VUpwreApsYqCgD+N1mHoqJ/BI/4eV4R2GYg=="
- },
- "node_modules/range-parser": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
- "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/rasha": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/rasha/-/rasha-1.2.5.tgz",
- "integrity": "sha512-KxtX+/fBk+wM7O3CNgwjSh5elwFilLvqWajhr6wFr2Hd63JnKTTi43Tw+Jb1hxJQWOwoya+NZWR2xztn3hCrTw==",
- "bin": {
- "rasha": "bin/rasha.js"
- }
- },
- "node_modules/raw-body": {
- "version": "2.5.1",
- "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
- "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
- "dependencies": {
- "bytes": "3.1.2",
- "http-errors": "2.0.0",
- "iconv-lite": "0.4.24",
- "unpipe": "1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/readable-stream": {
- "version": "2.3.7",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
- "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
- "dependencies": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.3",
- "isarray": "~1.0.0",
- "process-nextick-args": "~2.0.0",
- "safe-buffer": "~5.1.1",
- "string_decoder": "~1.1.1",
- "util-deprecate": "~1.0.1"
- }
- },
- "node_modules/readable-stream/node_modules/safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
- },
- "node_modules/readdirp": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
- "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
- "dev": true,
- "dependencies": {
- "picomatch": "^2.2.1"
- },
- "engines": {
- "node": ">=8.10.0"
- }
- },
- "node_modules/redirect-https": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/redirect-https/-/redirect-https-1.3.1.tgz",
- "integrity": "sha512-Stex2nI+tMpZXKvy++32TiBXEy+GdpAfp3EUnl5BqCiJ5f5i6XvUSFrs7TR7IoRSlthM7ZtD89uYGTtJBXlFYg==",
- "dependencies": {
- "escape-html": "^1.0.3"
- }
- },
- "node_modules/regenerator-runtime": {
- "version": "0.13.11",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
- "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
- },
- "node_modules/regexp-clone": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz",
- "integrity": "sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw=="
- },
- "node_modules/regexpp": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
- "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
- "dev": true,
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/mysticatea"
- }
- },
- "node_modules/request": {
- "version": "2.88.2",
- "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
- "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
- "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142",
- "dependencies": {
- "aws-sign2": "~0.7.0",
- "aws4": "^1.8.0",
- "caseless": "~0.12.0",
- "combined-stream": "~1.0.6",
- "extend": "~3.0.2",
- "forever-agent": "~0.6.1",
- "form-data": "~2.3.2",
- "har-validator": "~5.1.3",
- "http-signature": "~1.2.0",
- "is-typedarray": "~1.0.0",
- "isstream": "~0.1.2",
- "json-stringify-safe": "~5.0.1",
- "mime-types": "~2.1.19",
- "oauth-sign": "~0.9.0",
- "performance-now": "^2.1.0",
- "qs": "~6.5.2",
- "safe-buffer": "^5.1.2",
- "tough-cookie": "~2.5.0",
- "tunnel-agent": "^0.6.0",
- "uuid": "^3.3.2"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/request/node_modules/form-data": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
- "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
- "dependencies": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.6",
- "mime-types": "^2.1.12"
- },
- "engines": {
- "node": ">= 0.12"
- }
- },
- "node_modules/request/node_modules/qs": {
- "version": "6.5.3",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz",
- "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==",
- "engines": {
- "node": ">=0.6"
- }
- },
- "node_modules/require-at": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/require-at/-/require-at-1.0.6.tgz",
- "integrity": "sha512-7i1auJbMUrXEAZCOQ0VNJgmcT2VOKPRl2YGJwgpHpC9CE91Mv4/4UYIUm4chGJaI381ZDq1JUicFii64Hapd8g==",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/resolve-from": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
- "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/reusify": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
- "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
- "dev": true,
- "engines": {
- "iojs": ">=1.0.0",
- "node": ">=0.10.0"
- }
- },
- "node_modules/rimraf": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
- "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
- "dev": true,
- "dependencies": {
- "glob": "^7.1.3"
- },
- "bin": {
- "rimraf": "bin.js"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/rimraf/node_modules/glob": {
- "version": "7.2.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
- "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
- "dev": true,
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.1.1",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "engines": {
- "node": "*"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/rrule": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/rrule/-/rrule-2.4.1.tgz",
- "integrity": "sha512-+NcvhETefswZq13T8nkuEnnQ6YgUeZaqMqVbp+ZiFDPCbp3AVgQIwUvNVDdMNrP05bKZG9ddDULFp0qZZYDrxg==",
- "optionalDependencies": {
- "luxon": "^1.3.3"
- }
- },
- "node_modules/rsa-compat": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/rsa-compat/-/rsa-compat-2.0.8.tgz",
- "integrity": "sha512-BFiiSEbuxzsVdaxpejbxfX07qs+rtous49Y6mL/zw6YHh9cranDvm2BvBmqT3rso84IsxNlP5BXnuNvm1Wn3Tw==",
- "dependencies": {
- "keypairs": "^1.2.14"
- },
- "bin": {
- "rsa-keygen-js": "bin/rsa-keygen.js"
- },
- "engines": {
- "node": ">=10.12"
- }
- },
- "node_modules/run-parallel": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
- "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "dependencies": {
- "queue-microtask": "^1.2.2"
- }
- },
- "node_modules/safe-buffer": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ]
- },
- "node_modules/safe-replace": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/safe-replace/-/safe-replace-1.1.0.tgz",
- "integrity": "sha512-9/V2E0CDsKs9DWOOwJH7jYpSl9S3N05uyevNjvsnDauBqRowBPOyot1fIvV5N2IuZAbYyvrTXrYFVG0RZInfFw=="
- },
- "node_modules/safer-buffer": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
- },
- "node_modules/sanitize-html": {
- "version": "2.9.0",
- "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.9.0.tgz",
- "integrity": "sha512-KY1hpSbqFNcpoLf+nP7iStbP5JfQZ2Nd19ZEE7qFsQqRdp+sO5yX/e5+HoG9puFAcSTEpzQuihfKUltDcLlQjg==",
- "dependencies": {
- "deepmerge": "^4.2.2",
- "escape-string-regexp": "^4.0.0",
- "htmlparser2": "^8.0.0",
- "is-plain-object": "^5.0.0",
- "parse-srcset": "^1.0.2",
- "postcss": "^8.3.11"
- }
- },
- "node_modules/sanitize-html/node_modules/escape-string-regexp": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
- "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/saslprep": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
- "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==",
- "optional": true,
- "dependencies": {
- "sparse-bitfield": "^3.0.3"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/sax": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
- "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
- },
- "node_modules/semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
- "dev": true,
- "bin": {
- "semver": "bin/semver"
- }
- },
- "node_modules/send": {
- "version": "0.18.0",
- "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
- "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
- "dependencies": {
- "debug": "2.6.9",
- "depd": "2.0.0",
- "destroy": "1.2.0",
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "etag": "~1.8.1",
- "fresh": "0.5.2",
- "http-errors": "2.0.0",
- "mime": "1.6.0",
- "ms": "2.1.3",
- "on-finished": "2.4.1",
- "range-parser": "~1.2.1",
- "statuses": "2.0.1"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/send/node_modules/ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
- },
- "node_modules/serve-static": {
- "version": "1.15.0",
- "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
- "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
- "dependencies": {
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "parseurl": "~1.3.3",
- "send": "0.18.0"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/setprototypeof": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
- "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
- },
- "node_modules/shebang-command": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "dev": true,
- "dependencies": {
- "shebang-regex": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/shebang-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/side-channel": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
- "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
- "dependencies": {
- "call-bind": "^1.0.0",
- "get-intrinsic": "^1.0.2",
- "object-inspect": "^1.9.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/sift": {
- "version": "13.5.2",
- "resolved": "https://registry.npmjs.org/sift/-/sift-13.5.2.tgz",
- "integrity": "sha512-+gxdEOMA2J+AI+fVsCqeNn7Tgx3M9ZN9jdi95939l1IJ8cZsqS8sqpJyOkic2SJk+1+98Uwryt/gL6XDaV+UZA=="
- },
- "node_modules/simple-update-notifier": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz",
- "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==",
- "dev": true,
- "dependencies": {
- "semver": "~7.0.0"
- },
- "engines": {
- "node": ">=8.10.0"
- }
- },
- "node_modules/simple-update-notifier/node_modules/semver": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz",
- "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==",
- "dev": true,
- "bin": {
- "semver": "bin/semver.js"
- }
- },
- "node_modules/sliced": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz",
- "integrity": "sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2Xxzm/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yA=="
- },
- "node_modules/sorted-array-functions": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/sorted-array-functions/-/sorted-array-functions-1.3.0.tgz",
- "integrity": "sha512-2sqgzeFlid6N4Z2fUQ1cvFmTOLRi/sEDzSQ0OKYchqgoPmQBVyM3959qYx3fpS6Esef80KjmpgPeEr028dP3OA=="
- },
- "node_modules/source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/source-map-js": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
- "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/sparse-bitfield": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
- "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
- "optional": true,
- "dependencies": {
- "memory-pager": "^1.0.2"
- }
- },
- "node_modules/sshpk": {
- "version": "1.17.0",
- "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz",
- "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==",
- "dependencies": {
- "asn1": "~0.2.3",
- "assert-plus": "^1.0.0",
- "bcrypt-pbkdf": "^1.0.0",
- "dashdash": "^1.12.0",
- "ecc-jsbn": "~0.1.1",
- "getpass": "^0.1.1",
- "jsbn": "~0.1.0",
- "safer-buffer": "^2.0.2",
- "tweetnacl": "~0.14.0"
- },
- "bin": {
- "sshpk-conv": "bin/sshpk-conv",
- "sshpk-sign": "bin/sshpk-sign",
- "sshpk-verify": "bin/sshpk-verify"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/statuses": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
- "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/streamsearch": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
- "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
- "engines": {
- "node": ">=10.0.0"
- }
- },
- "node_modules/string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "dependencies": {
- "safe-buffer": "~5.1.0"
- }
- },
- "node_modules/string_decoder/node_modules/safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
- },
- "node_modules/strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "dependencies": {
- "ansi-regex": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/strip-json-comments": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
- "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
- "dev": true,
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dependencies": {
- "has-flag": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/text-table": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
- "dev": true
- },
- "node_modules/timm": {
- "version": "1.7.1",
- "resolved": "https://registry.npmjs.org/timm/-/timm-1.7.1.tgz",
- "integrity": "sha512-IjZc9KIotudix8bMaBW6QvMuq64BrJWFs1+4V0lXwWGQZwH+LnX87doAYhem4caOEusRP9/g6jVDQmZ8XOk1nw=="
- },
- "node_modules/tinycolor2": {
- "version": "1.5.2",
- "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.5.2.tgz",
- "integrity": "sha512-h80m9GPFGbcLzZByXlNSEhp1gf8Dy+VX/2JCGUZsWLo7lV1mnE/XlxGYgRBoMLJh1lIDXP0EMC4RPTjlRaV+Bg=="
- },
- "node_modules/to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
- "dependencies": {
- "is-number": "^7.0.0"
- },
- "engines": {
- "node": ">=8.0"
- }
- },
- "node_modules/toidentifier": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
- "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
- "engines": {
- "node": ">=0.6"
- }
- },
- "node_modules/touch": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
- "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==",
- "dev": true,
- "dependencies": {
- "nopt": "~1.0.10"
- },
- "bin": {
- "nodetouch": "bin/nodetouch.js"
- }
- },
- "node_modules/tough-cookie": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
- "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
- "dependencies": {
- "psl": "^1.1.28",
- "punycode": "^2.1.1"
- },
- "engines": {
- "node": ">=0.8"
- }
- },
- "node_modules/tunnel-agent": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
- "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
- "dependencies": {
- "safe-buffer": "^5.0.1"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/tweetnacl": {
- "version": "0.14.5",
- "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
- "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="
- },
- "node_modules/type-check": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
- "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
- "dev": true,
- "dependencies": {
- "prelude-ls": "^1.2.1"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/type-fest": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
- "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/type-is": {
- "version": "1.6.18",
- "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
- "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
- "dependencies": {
- "media-typer": "0.3.0",
- "mime-types": "~2.1.24"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/typedarray": {
- "version": "0.0.6",
- "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
- "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
- },
- "node_modules/uglify-js": {
- "version": "3.17.4",
- "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz",
- "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==",
- "optional": true,
- "bin": {
- "uglifyjs": "bin/uglifyjs"
- },
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/uid-safe": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
- "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
- "dependencies": {
- "random-bytes": "~1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/undefsafe": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
- "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
- "dev": true
- },
- "node_modules/unpipe": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
- "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/uri-js": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
- "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "dependencies": {
- "punycode": "^2.1.0"
- }
- },
- "node_modules/utif": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/utif/-/utif-2.0.1.tgz",
- "integrity": "sha512-Z/S1fNKCicQTf375lIP9G8Sa1H/phcysstNrrSdZKj1f9g58J4NMgb5IgiEZN9/nLMPDwF0W7hdOe9Qq2IYoLg==",
- "dependencies": {
- "pako": "^1.0.5"
- }
- },
- "node_modules/util-deprecate": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
- },
- "node_modules/utils-merge": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
- "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
- "engines": {
- "node": ">= 0.4.0"
- }
- },
- "node_modules/uuid": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
- "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
- "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
- "bin": {
- "uuid": "bin/uuid"
- }
- },
- "node_modules/validator": {
- "version": "13.7.0",
- "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz",
- "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==",
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/vary": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
- "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/verror": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
- "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==",
- "engines": [
- "node >=0.6.0"
- ],
- "dependencies": {
- "assert-plus": "^1.0.0",
- "core-util-is": "1.0.2",
- "extsprintf": "^1.2.0"
- }
- },
- "node_modules/verror/node_modules/core-util-is": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
- "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="
- },
- "node_modules/which": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
- "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "dev": true,
- "dependencies": {
- "isexe": "^2.0.0"
- },
- "bin": {
- "node-which": "bin/node-which"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/word-wrap": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
- "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/wordwrap": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
- "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q=="
- },
- "node_modules/wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
- },
- "node_modules/xhr": {
- "version": "2.6.0",
- "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz",
- "integrity": "sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==",
- "dependencies": {
- "global": "~4.4.0",
- "is-function": "^1.0.1",
- "parse-headers": "^2.0.0",
- "xtend": "^4.0.0"
- }
- },
- "node_modules/xml-parse-from-string": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz",
- "integrity": "sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g=="
- },
- "node_modules/xml2js": {
- "version": "0.4.23",
- "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
- "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
- "dependencies": {
- "sax": ">=0.6.0",
- "xmlbuilder": "~11.0.0"
- },
- "engines": {
- "node": ">=4.0.0"
- }
- },
- "node_modules/xmlbuilder": {
- "version": "11.0.1",
- "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
- "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/xtend": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
- "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
- "engines": {
- "node": ">=0.4"
- }
- },
- "node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
- },
- "node_modules/yocto-queue": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
- "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- }
- },
- "dependencies": {
- "@babel/runtime": {
- "version": "7.20.13",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz",
- "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==",
- "requires": {
- "regenerator-runtime": "^0.13.11"
- }
- },
- "@eslint/eslintrc": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz",
- "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==",
- "dev": true,
- "requires": {
- "ajv": "^6.12.4",
- "debug": "^4.3.2",
- "espree": "^9.4.0",
- "globals": "^13.19.0",
- "ignore": "^5.2.0",
- "import-fresh": "^3.2.1",
- "js-yaml": "^4.1.0",
- "minimatch": "^3.1.2",
- "strip-json-comments": "^3.1.1"
- },
- "dependencies": {
- "debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "dev": true,
- "requires": {
- "ms": "2.1.2"
- }
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- }
- }
- },
- "@humanwhocodes/config-array": {
- "version": "0.11.8",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
- "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==",
- "dev": true,
- "requires": {
- "@humanwhocodes/object-schema": "^1.2.1",
- "debug": "^4.1.1",
- "minimatch": "^3.0.5"
- },
- "dependencies": {
- "debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "dev": true,
- "requires": {
- "ms": "2.1.2"
- }
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- }
- }
- },
- "@humanwhocodes/module-importer": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
- "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
- "dev": true
- },
- "@humanwhocodes/object-schema": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
- "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
- "dev": true
- },
- "@jimp/bmp": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/bmp/-/bmp-0.16.2.tgz",
- "integrity": "sha512-4g9vW45QfMoGhLVvaFj26h4e7cC+McHUQwyFQmNTLW4FfC1OonN9oUr2m/FEDGkTYKR7aqdXR5XUqqIkHWLaFw==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2",
- "bmp-js": "^0.1.0"
- }
- },
- "@jimp/core": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/core/-/core-0.16.2.tgz",
- "integrity": "sha512-dp7HcyUMzjXphXYodI6PaXue+I9PXAavbb+AN+1XqFbotN22Z12DosNPEyy+UhLY/hZiQQqUkEaJHkvV31rs+w==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2",
- "any-base": "^1.1.0",
- "buffer": "^5.2.0",
- "exif-parser": "^0.1.12",
- "file-type": "^9.0.0",
- "load-bmfont": "^1.3.1",
- "mkdirp": "^0.5.1",
- "phin": "^2.9.1",
- "pixelmatch": "^4.0.2",
- "tinycolor2": "^1.4.1"
- }
- },
- "@jimp/custom": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/custom/-/custom-0.16.2.tgz",
- "integrity": "sha512-GtNwOs4hcVS2GIbqRUf42rUuX07oLB92cj7cqxZb0ZGWwcwhnmSW0TFLAkNafXmqn9ug4VTpNvcJSUdiuECVKg==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/core": "^0.16.2"
- }
- },
- "@jimp/gif": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/gif/-/gif-0.16.2.tgz",
- "integrity": "sha512-TMdyT9Q0paIKNtT7c5KzQD29CNCsI/t8ka28jMrBjEK7j5RRTvBfuoOnHv7pDJRCjCIqeUoaUSJ7QcciKic6CA==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2",
- "gifwrap": "^0.9.2",
- "omggif": "^1.0.9"
- }
- },
- "@jimp/jpeg": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/jpeg/-/jpeg-0.16.2.tgz",
- "integrity": "sha512-BW5gZydgq6wdIwHd+3iUNgrTklvoQc/FUKSj9meM6A0FU21lUaansRX5BDdJqHkyXJLnnlDGwDt27J+hQuBAVw==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2",
- "jpeg-js": "^0.4.2"
- }
- },
- "@jimp/plugin-blit": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-0.16.2.tgz",
- "integrity": "sha512-Z31rRfV80gC/r+B/bOPSVVpJEWXUV248j7MdnMOFLu4vr8DMqXVo9jYqvwU/s4LSTMAMXqm4Jg6E/jQfadPKAg==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- }
- },
- "@jimp/plugin-blur": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-0.16.2.tgz",
- "integrity": "sha512-ShkJCAzRI+1fAKPuLLgEkixpSpVmKTYaKEFROUcgmrv9AansDXGNCupchqVMTdxf8zPyW8rR1ilvG3OJobufLQ==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- }
- },
- "@jimp/plugin-circle": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-circle/-/plugin-circle-0.16.2.tgz",
- "integrity": "sha512-6T4z/48F4Z5+YwAVCLOvXQcyGmo0E3WztxCz6XGQf66r4JJK78+zcCDYZFLMx0BGM0091FogNK4QniP8JaOkrA==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- }
- },
- "@jimp/plugin-color": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-0.16.2.tgz",
- "integrity": "sha512-6oBV0g0J17/7E+aTquvUsgSc85nUbUi+64tIK5eFIDzvjhlqhjGNJYlc46KJMCWIs61qRJayQoZdL/iT/iQuGQ==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2",
- "tinycolor2": "^1.4.1"
- }
- },
- "@jimp/plugin-contain": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-0.16.2.tgz",
- "integrity": "sha512-pLcxO3hVN3LCEhMNvpZ9B7xILHVlS433Vv16zFFJxLRqZdYvPLsc+ZzJhjAiHHuEjVblQrktHE3LGeQwGJPo0w==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- }
- },
- "@jimp/plugin-cover": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-0.16.2.tgz",
- "integrity": "sha512-gzWM7VvYeI8msyiwbUZxH+sGQEgO6Vd6adGxZ0CeKX00uQOe5lDzxb1Wjx7sHcJGz8a/5fmAuwz7rdDtpDUbkw==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- }
- },
- "@jimp/plugin-crop": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-0.16.2.tgz",
- "integrity": "sha512-qCd3hfMEE+Z2EuuyXewgXRTtKJGIerWzc1zLEJztsUkPz5i73IGgkOL+mrNutZwGaXZbm+8SwUaGb46sxAO6Tw==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- }
- },
- "@jimp/plugin-displace": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-0.16.2.tgz",
- "integrity": "sha512-6nXdvNNjCdD95v2o3/jPeur903dz08lG4Y8gmr5oL2yVv9LSSbMonoXYrR/ASesdyXqGdXJLU4NL+yZs4zUqbQ==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- }
- },
- "@jimp/plugin-dither": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-0.16.2.tgz",
- "integrity": "sha512-DERpIzy21ZanMkVsD0Tdy8HQLbD1E41OuvIzaMRoW4183PA6AgGNlrQoFTyXmzjy6FTy1SxaQgTEdouInAWZ9Q==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- }
- },
- "@jimp/plugin-fisheye": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-fisheye/-/plugin-fisheye-0.16.2.tgz",
- "integrity": "sha512-Df7PsGIwiIpQu3EygYCnaJyTfOwvwtYV3cmYJS7yFLtdiFUuod+hlSo5GkwEPLAy+QBxhUbDuUqnsWo4NQtbiQ==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- }
- },
- "@jimp/plugin-flip": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-0.16.2.tgz",
- "integrity": "sha512-+2uC8ioVQUr06mnjSWraskz2L33nJHze35LkQ8ZNsIpoZLkgvfiWatqAs5bj+1jGI/9kxoCFAaT1Is0f+a4/rw==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- }
- },
- "@jimp/plugin-gaussian": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-gaussian/-/plugin-gaussian-0.16.2.tgz",
- "integrity": "sha512-2mnuDSg4ZEH8zcJig7DZZf4st/cYmQ5UYJKP76iGhZ+6JDACk6uejwAgT5xHecNhkVAaXMdCybA2eknH/9OE1w==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- }
- },
- "@jimp/plugin-invert": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-invert/-/plugin-invert-0.16.2.tgz",
- "integrity": "sha512-xFvHbVepTY/nus+6yXiYN1iq+UBRkT0MdnObbiQPstUrAsz0Imn6MWISsnAyMvcNxHGrxaxjuU777JT/esM0gg==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- }
- },
- "@jimp/plugin-mask": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-0.16.2.tgz",
- "integrity": "sha512-AbdO85xxhfgEDdxYKpUotEI9ixiCMaIpfYHD5a5O/VWeimz2kuwhcrzlHGiyq1kKAgRcl0WEneTCZAHVSyvPKA==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- }
- },
- "@jimp/plugin-normalize": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-normalize/-/plugin-normalize-0.16.2.tgz",
- "integrity": "sha512-+ItBWFwmB0Od7OfOtTYT1gm543PpHUgU8/DN55z83l1JqS0OomDJAe7BmCppo2405TN6YtVm/csXo7p4iWd/SQ==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- }
- },
- "@jimp/plugin-print": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-0.16.2.tgz",
- "integrity": "sha512-ifTGEeJ5UZTCiqC70HMeU3iXk/vsOmhWiwVGOXSFXhFeE8ZpDWvlmBsrMYnRrJGuaaogHOIrrQPI+kCdDBSBIQ==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2",
- "load-bmfont": "^1.4.0"
- }
- },
- "@jimp/plugin-resize": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-0.16.2.tgz",
- "integrity": "sha512-gE4N9l6xuwzacFZ2EPCGZCJ/xR+aX2V7GdMndIl/6kYIw5/eib1SFuF9AZLvIPSFuE1FnGo8+vT0pr++SSbhYg==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- }
- },
- "@jimp/plugin-rotate": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-0.16.2.tgz",
- "integrity": "sha512-/CTEYkR1HrgmnE0VqPhhbBARbDAfFX590LWGIpxcYIYsUUGQCadl+8Qo4UX13FH0Nt8UHEtPA+O2x08uPYg9UA==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- }
- },
- "@jimp/plugin-scale": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-scale/-/plugin-scale-0.16.2.tgz",
- "integrity": "sha512-3inuxfrlquyLaqFdiiiQNJUurR0WbvN5wAf1qcYX2LubG1AG8grayYD6H7XVoxfUGTZXh1kpmeirEYlqA2zxcw==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- }
- },
- "@jimp/plugin-shadow": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-shadow/-/plugin-shadow-0.16.2.tgz",
- "integrity": "sha512-Q0aIs2/L6fWMcEh9Ms73u34bT1hyUMw/oxaVoIzOLo6/E8YzCs2Bi63H0/qaPS0MQpEppI++kvosPbblABY79w==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- }
- },
- "@jimp/plugin-threshold": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugin-threshold/-/plugin-threshold-0.16.2.tgz",
- "integrity": "sha512-gyOwmBgjtMPvcuyOhkP6dOGWbQdaTfhcBRN22mYeI/k/Wh/Zh1OI21F6eKLApsVRmg15MoFnkrCz64RROC34sw==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2"
- }
- },
- "@jimp/plugins": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/plugins/-/plugins-0.16.2.tgz",
- "integrity": "sha512-zCvYtCgctmC0tkYEu+y+kSwSIZBsNznqJ3/3vkpzxdyjd6wCfNY5Qc/68MPrLc1lmdeGo4cOOTYHG7Vc6myzRw==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/plugin-blit": "^0.16.2",
- "@jimp/plugin-blur": "^0.16.2",
- "@jimp/plugin-circle": "^0.16.2",
- "@jimp/plugin-color": "^0.16.2",
- "@jimp/plugin-contain": "^0.16.2",
- "@jimp/plugin-cover": "^0.16.2",
- "@jimp/plugin-crop": "^0.16.2",
- "@jimp/plugin-displace": "^0.16.2",
- "@jimp/plugin-dither": "^0.16.2",
- "@jimp/plugin-fisheye": "^0.16.2",
- "@jimp/plugin-flip": "^0.16.2",
- "@jimp/plugin-gaussian": "^0.16.2",
- "@jimp/plugin-invert": "^0.16.2",
- "@jimp/plugin-mask": "^0.16.2",
- "@jimp/plugin-normalize": "^0.16.2",
- "@jimp/plugin-print": "^0.16.2",
- "@jimp/plugin-resize": "^0.16.2",
- "@jimp/plugin-rotate": "^0.16.2",
- "@jimp/plugin-scale": "^0.16.2",
- "@jimp/plugin-shadow": "^0.16.2",
- "@jimp/plugin-threshold": "^0.16.2",
- "timm": "^1.6.1"
- }
- },
- "@jimp/png": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/png/-/png-0.16.2.tgz",
- "integrity": "sha512-sFOtOSz/tzDwXEChFQ/Nxe+0+vG3Tj0eUxnZVDUG/StXE9dI8Bqmwj3MIa0EgK5s+QG3YlnDOmlPUa4JqmeYeQ==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/utils": "^0.16.2",
- "pngjs": "^3.3.3"
- }
- },
- "@jimp/tiff": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/tiff/-/tiff-0.16.2.tgz",
- "integrity": "sha512-ADcdqmtZF+U2YoaaHTzFX8D6NFpmN4WZUT0BPMerEuY7Cq8QoLYU22z2h034FrVW+Rbi1b3y04sB9iDiQAlf2w==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "utif": "^2.0.1"
- }
- },
- "@jimp/types": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/types/-/types-0.16.2.tgz",
- "integrity": "sha512-0Ue5Sq0XnDF6TirisWv5E+8uOnRcd8vRLuwocJOhF76NIlcQrz+5r2k2XWKcr3d+11n28dHLXW5TKSqrUopxhA==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/bmp": "^0.16.2",
- "@jimp/gif": "^0.16.2",
- "@jimp/jpeg": "^0.16.2",
- "@jimp/png": "^0.16.2",
- "@jimp/tiff": "^0.16.2",
- "timm": "^1.6.1"
- }
- },
- "@jimp/utils": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-0.16.2.tgz",
- "integrity": "sha512-XENrPvmigiXZQ8E2nxJqO6UVvWBLzbNwyYi3Y8Q1IECoYhYI3kgOQ0fmy4G269Vz1V0omh1bNmC42r4OfXg1Jg==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "regenerator-runtime": "^0.13.3"
- }
- },
- "@nodelib/fs.scandir": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
- "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
- "dev": true,
- "requires": {
- "@nodelib/fs.stat": "2.0.5",
- "run-parallel": "^1.1.9"
- }
- },
- "@nodelib/fs.stat": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
- "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
- "dev": true
- },
- "@nodelib/fs.walk": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
- "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
- "dev": true,
- "requires": {
- "@nodelib/fs.scandir": "2.1.5",
- "fastq": "^1.6.0"
- }
- },
- "@root/mkdirp": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@root/mkdirp/-/mkdirp-1.0.0.tgz",
- "integrity": "sha512-hxGAYUx5029VggfG+U9naAhQkoMSXtOeXtbql97m3Hi6/sQSRL/4khKZPyOF6w11glyCOU38WCNLu9nUcSjOfA=="
- },
- "@root/request": {
- "version": "1.9.2",
- "resolved": "https://registry.npmjs.org/@root/request/-/request-1.9.2.tgz",
- "integrity": "sha512-wVaL9yVV9oDR9UNbPZa20qgY+4Ch6YN8JUkaE4el/uuS5dmhD8Lusm/ku8qJVNtmQA56XLzEDCRS6/vfpiHK2A=="
- },
- "@sendgrid/client": {
- "version": "6.5.5",
- "resolved": "https://registry.npmjs.org/@sendgrid/client/-/client-6.5.5.tgz",
- "integrity": "sha512-Nbfgo94gbWSL8PIgJfuHoifyOJJepvV8NQkkglctAEfb1hyozKhrzE6v1kPG/z4j0RodaTtXD5LJj/t0q/VhLA==",
- "requires": {
- "@sendgrid/helpers": "^6.5.5",
- "@types/request": "^2.48.4",
- "request": "^2.88.0"
- }
- },
- "@sendgrid/helpers": {
- "version": "6.5.5",
- "resolved": "https://registry.npmjs.org/@sendgrid/helpers/-/helpers-6.5.5.tgz",
- "integrity": "sha512-uRFEanalfss5hDsuzVXZ1wm7i7eEXHh1py80piOXjobiQ+MxmtR19EU+gDSXZ+uMcEehBGhxnb7QDNN0q65qig==",
- "requires": {
- "chalk": "^2.0.1",
- "deepmerge": "^4.2.2"
- }
- },
- "@sendgrid/mail": {
- "version": "6.5.5",
- "resolved": "https://registry.npmjs.org/@sendgrid/mail/-/mail-6.5.5.tgz",
- "integrity": "sha512-DSu8oTPI0BJFH60jMOG9gM+oeNMoRALFmdAYg2PIXpL+Zbxd7L2GzQZtmf1jLy/8UBImkbB3D74TjiOBiLRK1w==",
- "requires": {
- "@sendgrid/client": "^6.5.5",
- "@sendgrid/helpers": "^6.5.5"
- }
- },
- "@types/bson": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.5.tgz",
- "integrity": "sha512-vVLwMUqhYJSQ/WKcE60eFqcyuWse5fGH+NMAXHuKrUAPoryq3ATxk5o4bgYNtg5aOM4APVg7Hnb3ASqUYG0PKg==",
- "requires": {
- "@types/node": "*"
- }
- },
- "@types/caseless": {
- "version": "0.12.2",
- "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz",
- "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w=="
- },
- "@types/jsonwebtoken": {
- "version": "9.0.1",
- "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.1.tgz",
- "integrity": "sha512-c5ltxazpWabia/4UzhIoaDcIza4KViOQhdbjRlfcIGVnsE3c3brkz9Z+F/EeJIECOQP7W7US2hNE930cWWkPiw==",
- "requires": {
- "@types/node": "*"
- }
- },
- "@types/mongodb": {
- "version": "3.6.20",
- "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.20.tgz",
- "integrity": "sha512-WcdpPJCakFzcWWD9juKoZbRtQxKIMYF/JIAM4JrNHrMcnJL6/a2NWjXxW7fo9hxboxxkg+icff8d7+WIEvKgYQ==",
- "requires": {
- "@types/bson": "*",
- "@types/node": "*"
- }
- },
- "@types/node": {
- "version": "18.11.18",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz",
- "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA=="
- },
- "@types/request": {
- "version": "2.48.8",
- "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.8.tgz",
- "integrity": "sha512-whjk1EDJPcAR2kYHRbFl/lKeeKYTi05A15K9bnLInCVroNDCtXce57xKdI0/rQaA3K+6q0eFyUBPmqfSndUZdQ==",
- "requires": {
- "@types/caseless": "*",
- "@types/node": "*",
- "@types/tough-cookie": "*",
- "form-data": "^2.5.0"
- }
- },
- "@types/tough-cookie": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz",
- "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw=="
- },
- "abbrev": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
- "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
- "dev": true
- },
- "accepts": {
- "version": "1.3.8",
- "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
- "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
- "requires": {
- "mime-types": "~2.1.34",
- "negotiator": "0.6.3"
- }
- },
- "acme": {
- "version": "1.3.5",
- "resolved": "https://registry.npmjs.org/acme/-/acme-1.3.5.tgz",
- "integrity": "sha512-KIFVyMho7y3RxRSTzkuX031TmfXwzl0ioy8+r2pnfLz6YWFQ5q7a/cYUDTgIbrFMPe/syY26Qv1DOdHQ5ARWcw==",
- "requires": {
- "acme-v2": "^1.8.6"
- }
- },
- "acme-dns-01-cli": {
- "version": "3.0.7",
- "resolved": "https://registry.npmjs.org/acme-dns-01-cli/-/acme-dns-01-cli-3.0.7.tgz",
- "integrity": "sha512-Aa4bUpq6ftX1VODiShOetOY5U0tsXY5EV7+fQwme3Q8Y9rjYBArBXHgFCAVKtK1AF+Ev8pIuF6Z42hzMFa73/w=="
- },
- "acme-v2": {
- "version": "1.8.6",
- "resolved": "https://registry.npmjs.org/acme-v2/-/acme-v2-1.8.6.tgz",
- "integrity": "sha512-LWdicUYHTGDtYX7LlgsQurmM9txwfAFydg7mQLPKHrFMnNNtfJEtHC2fWfr+pFGNb3XKIbvyFUoyFB6cOmWRpA==",
- "requires": {
- "@root/request": "^1.3.11",
- "rsa-compat": "^2.0.8"
- }
- },
- "acorn": {
- "version": "8.8.2",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
- "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
- "dev": true
- },
- "acorn-jsx": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
- "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
- "dev": true,
- "requires": {}
- },
- "ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "requires": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- }
- },
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true
- },
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "any-base": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/any-base/-/any-base-1.1.0.tgz",
- "integrity": "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg=="
- },
- "anymatch": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
- "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
- "dev": true,
- "requires": {
- "normalize-path": "^3.0.0",
- "picomatch": "^2.0.4"
- }
- },
- "append-field": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
- "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw=="
- },
- "argparse": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "dev": true
- },
- "array-flatten": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
- "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
- },
- "array-uniq": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.2.tgz",
- "integrity": "sha512-GVYjmpL05al4dNlKJm53mKE4w9OOLiuVHWorsIA3YVz+Hu0hcn6PtE3Ydl0EqU7v+7ABC4mjjWsnLUxbpno+CA=="
- },
- "asn1": {
- "version": "0.2.6",
- "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
- "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
- "requires": {
- "safer-buffer": "~2.1.0"
- }
- },
- "assert-plus": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
- "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw=="
- },
- "asynckit": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
- },
- "aws-sign2": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
- "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA=="
- },
- "aws4": {
- "version": "1.12.0",
- "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz",
- "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg=="
- },
- "balanced-match": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
- },
- "base64-js": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
- "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
- },
- "bcrypt-pbkdf": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
- "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
- "requires": {
- "tweetnacl": "^0.14.3"
- }
- },
- "binary-extensions": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
- "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
- "dev": true
- },
- "binary-search": {
- "version": "1.3.6",
- "resolved": "https://registry.npmjs.org/binary-search/-/binary-search-1.3.6.tgz",
- "integrity": "sha512-nbE1WxOTTrUWIfsfZ4aHGYu5DOuNkbxGokjV6Z2kxfJK3uaAb8zNK1muzOeipoLHZjInT4Br88BHpzevc681xA=="
- },
- "bl": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz",
- "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==",
- "requires": {
- "readable-stream": "^2.3.5",
- "safe-buffer": "^5.1.1"
- }
- },
- "bluebird": {
- "version": "3.5.1",
- "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
- "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA=="
- },
- "bmp-js": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz",
- "integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw=="
- },
- "body-parser": {
- "version": "1.20.1",
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
- "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
- "requires": {
- "bytes": "3.1.2",
- "content-type": "~1.0.4",
- "debug": "2.6.9",
- "depd": "2.0.0",
- "destroy": "1.2.0",
- "http-errors": "2.0.0",
- "iconv-lite": "0.4.24",
- "on-finished": "2.4.1",
- "qs": "6.11.0",
- "raw-body": "2.5.1",
- "type-is": "~1.6.18",
- "unpipe": "1.0.0"
- }
- },
- "brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "dev": true,
- "requires": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
- "dev": true,
- "requires": {
- "fill-range": "^7.0.1"
- }
- },
- "bson": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz",
- "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg=="
- },
- "buffer": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
- "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
- "requires": {
- "base64-js": "^1.3.1",
- "ieee754": "^1.1.13"
- }
- },
- "buffer-equal": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz",
- "integrity": "sha512-RgSV6InVQ9ODPdLWJ5UAqBqJBOg370Nz6ZQtRzpt6nUjc8v0St97uJ4PYC6NztqIScrAXafKM3mZPMygSe1ggA=="
- },
- "buffer-equal-constant-time": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
- "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
- },
- "buffer-from": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
- "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
- },
- "busboy": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
- "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
- "requires": {
- "streamsearch": "^1.1.0"
- }
- },
- "bytes": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
- "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
- },
- "call-bind": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
- "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
- "requires": {
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.0.2"
- }
- },
- "callsites": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
- "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
- "dev": true
- },
- "caseless": {
- "version": "0.12.0",
- "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
- "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw=="
- },
- "cert-info": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/cert-info/-/cert-info-1.5.1.tgz",
- "integrity": "sha512-eoQC/yAgW3gKTKxjzyClvi+UzuY97YCjcl+lSqbsGIy7HeGaWxCPOQFivhUYm27hgsBMhsJJFya3kGvK6PMIcQ=="
- },
- "chalk": {
- "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": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "chokidar": {
- "version": "3.5.3",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
- "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
- "dev": true,
- "requires": {
- "anymatch": "~3.1.2",
- "braces": "~3.0.2",
- "fsevents": "~2.3.2",
- "glob-parent": "~5.1.2",
- "is-binary-path": "~2.1.0",
- "is-glob": "~4.0.1",
- "normalize-path": "~3.0.0",
- "readdirp": "~3.6.0"
- },
- "dependencies": {
- "glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dev": true,
- "requires": {
- "is-glob": "^4.0.1"
- }
- }
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
- },
- "combined-stream": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
- "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
- "requires": {
- "delayed-stream": "~1.0.0"
- }
- },
- "concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
- "dev": true
- },
- "concat-stream": {
- "version": "1.6.2",
- "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
- "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
- "requires": {
- "buffer-from": "^1.0.0",
- "inherits": "^2.0.3",
- "readable-stream": "^2.2.2",
- "typedarray": "^0.0.6"
- }
- },
- "content-disposition": {
- "version": "0.5.4",
- "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
- "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
- "requires": {
- "safe-buffer": "5.2.1"
- }
- },
- "content-type": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
- "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="
- },
- "cookie": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
- "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw=="
- },
- "cookie-signature": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
- "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
- },
- "core-util-is": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
- "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
- },
- "cors": {
- "version": "2.8.5",
- "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
- "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
- "requires": {
- "object-assign": "^4",
- "vary": "^1"
- }
- },
- "cron-parser": {
- "version": "2.18.0",
- "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-2.18.0.tgz",
- "integrity": "sha512-s4odpheTyydAbTBQepsqd2rNWGa2iV3cyo8g7zbI2QQYGLVsfbhmwukayS1XHppe02Oy1fg7mg6xoaraVJeEcg==",
- "requires": {
- "is-nan": "^1.3.0",
- "moment-timezone": "^0.5.31"
- }
- },
- "cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "dev": true,
- "requires": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- }
- },
- "dashdash": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
- "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==",
- "requires": {
- "assert-plus": "^1.0.0"
- }
- },
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "requires": {
- "ms": "2.0.0"
- }
- },
- "deep-is": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
- "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
- "dev": true
- },
- "deepmerge": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.0.tgz",
- "integrity": "sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og=="
- },
- "define-properties": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz",
- "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==",
- "requires": {
- "has-property-descriptors": "^1.0.0",
- "object-keys": "^1.1.1"
- }
- },
- "delayed-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
- "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
- },
- "denque": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz",
- "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw=="
- },
- "depd": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
- "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
- },
- "destroy": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
- "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="
- },
- "doctrine": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
- "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
- "dev": true,
- "requires": {
- "esutils": "^2.0.2"
- }
- },
- "dom-serializer": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
- "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
- "requires": {
- "domelementtype": "^2.3.0",
- "domhandler": "^5.0.2",
- "entities": "^4.2.0"
- }
- },
- "dom-walk": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz",
- "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w=="
- },
- "domelementtype": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
- "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="
- },
- "domhandler": {
- "version": "5.0.3",
- "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
- "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
- "requires": {
- "domelementtype": "^2.3.0"
- }
- },
- "domutils": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
- "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==",
- "requires": {
- "dom-serializer": "^2.0.0",
- "domelementtype": "^2.3.0",
- "domhandler": "^5.0.1"
- }
- },
- "dotenv": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz",
- "integrity": "sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w=="
- },
- "ecc-jsbn": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
- "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==",
- "requires": {
- "jsbn": "~0.1.0",
- "safer-buffer": "^2.1.0"
- }
- },
- "ecdsa-sig-formatter": {
- "version": "1.0.11",
- "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
- "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
- "requires": {
- "safe-buffer": "^5.0.1"
- }
- },
- "eckles": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/eckles/-/eckles-1.4.1.tgz",
- "integrity": "sha512-auWyk/k8oSkVHaD4RxkPadKsLUcIwKgr/h8F7UZEueFDBO7BsE4y+H6IMUDbfqKIFPg/9MxV6KcBdJCmVVcxSA=="
- },
- "ee-first": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
- "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
- },
- "encodeurl": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
- "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="
- },
- "entities": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
- "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA=="
- },
- "escape-html": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
- "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
- },
- "escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
- },
- "eslint": {
- "version": "8.33.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.33.0.tgz",
- "integrity": "sha512-WjOpFQgKK8VrCnAtl8We0SUOy/oVZ5NHykyMiagV1M9r8IFpIJX7DduK6n1mpfhlG7T1NLWm2SuD8QB7KFySaA==",
- "dev": true,
- "requires": {
- "@eslint/eslintrc": "^1.4.1",
- "@humanwhocodes/config-array": "^0.11.8",
- "@humanwhocodes/module-importer": "^1.0.1",
- "@nodelib/fs.walk": "^1.2.8",
- "ajv": "^6.10.0",
- "chalk": "^4.0.0",
- "cross-spawn": "^7.0.2",
- "debug": "^4.3.2",
- "doctrine": "^3.0.0",
- "escape-string-regexp": "^4.0.0",
- "eslint-scope": "^7.1.1",
- "eslint-utils": "^3.0.0",
- "eslint-visitor-keys": "^3.3.0",
- "espree": "^9.4.0",
- "esquery": "^1.4.0",
- "esutils": "^2.0.2",
- "fast-deep-equal": "^3.1.3",
- "file-entry-cache": "^6.0.1",
- "find-up": "^5.0.0",
- "glob-parent": "^6.0.2",
- "globals": "^13.19.0",
- "grapheme-splitter": "^1.0.4",
- "ignore": "^5.2.0",
- "import-fresh": "^3.0.0",
- "imurmurhash": "^0.1.4",
- "is-glob": "^4.0.0",
- "is-path-inside": "^3.0.3",
- "js-sdsl": "^4.1.4",
- "js-yaml": "^4.1.0",
- "json-stable-stringify-without-jsonify": "^1.0.1",
- "levn": "^0.4.1",
- "lodash.merge": "^4.6.2",
- "minimatch": "^3.1.2",
- "natural-compare": "^1.4.0",
- "optionator": "^0.9.1",
- "regexpp": "^3.2.0",
- "strip-ansi": "^6.0.1",
- "strip-json-comments": "^3.1.0",
- "text-table": "^0.2.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "dev": true,
- "requires": {
- "ms": "2.1.2"
- }
- },
- "escape-string-regexp": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
- "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "eslint-scope": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
- "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
- "dev": true,
- "requires": {
- "esrecurse": "^4.3.0",
- "estraverse": "^5.2.0"
- }
- },
- "eslint-utils": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
- "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
- "dev": true,
- "requires": {
- "eslint-visitor-keys": "^2.0.0"
- },
- "dependencies": {
- "eslint-visitor-keys": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
- "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
- "dev": true
- }
- }
- },
- "eslint-visitor-keys": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
- "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
- "dev": true
- },
- "espree": {
- "version": "9.4.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz",
- "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==",
- "dev": true,
- "requires": {
- "acorn": "^8.8.0",
- "acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^3.3.0"
- }
- },
- "esquery": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
- "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
- "dev": true,
- "requires": {
- "estraverse": "^5.1.0"
- }
- },
- "esrecurse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
- "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
- "dev": true,
- "requires": {
- "estraverse": "^5.2.0"
- }
- },
- "estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
- "dev": true
- },
- "esutils": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
- "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
- "dev": true
- },
- "etag": {
- "version": "1.8.1",
- "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
- "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="
- },
- "exif-parser": {
- "version": "0.1.12",
- "resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz",
- "integrity": "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw=="
- },
- "express": {
- "version": "4.18.2",
- "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
- "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
- "requires": {
- "accepts": "~1.3.8",
- "array-flatten": "1.1.1",
- "body-parser": "1.20.1",
- "content-disposition": "0.5.4",
- "content-type": "~1.0.4",
- "cookie": "0.5.0",
- "cookie-signature": "1.0.6",
- "debug": "2.6.9",
- "depd": "2.0.0",
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "etag": "~1.8.1",
- "finalhandler": "1.2.0",
- "fresh": "0.5.2",
- "http-errors": "2.0.0",
- "merge-descriptors": "1.0.1",
- "methods": "~1.1.2",
- "on-finished": "2.4.1",
- "parseurl": "~1.3.3",
- "path-to-regexp": "0.1.7",
- "proxy-addr": "~2.0.7",
- "qs": "6.11.0",
- "range-parser": "~1.2.1",
- "safe-buffer": "5.2.1",
- "send": "0.18.0",
- "serve-static": "1.15.0",
- "setprototypeof": "1.2.0",
- "statuses": "2.0.1",
- "type-is": "~1.6.18",
- "utils-merge": "1.0.1",
- "vary": "~1.1.2"
- }
- },
- "express-fileupload": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/express-fileupload/-/express-fileupload-1.4.0.tgz",
- "integrity": "sha512-RjzLCHxkv3umDeZKeFeMg8w7qe0V09w3B7oGZprr/oO2H/ISCgNzuqzn7gV3HRWb37GjRk429CCpSLS2KNTqMQ==",
- "requires": {
- "busboy": "^1.6.0"
- }
- },
- "express-handlebars": {
- "version": "6.0.7",
- "resolved": "https://registry.npmjs.org/express-handlebars/-/express-handlebars-6.0.7.tgz",
- "integrity": "sha512-iYeMFpc/hMD+E6FNAZA5fgWeXnXr4rslOSPkeEV6TwdmpJ5lEXuWX0u9vFYs31P2MURctQq2batR09oeNj0LIg==",
- "requires": {
- "glob": "^8.1.0",
- "graceful-fs": "^4.2.10",
- "handlebars": "^4.7.7"
- }
- },
- "express-jwt": {
- "version": "8.4.0",
- "resolved": "https://registry.npmjs.org/express-jwt/-/express-jwt-8.4.0.tgz",
- "integrity": "sha512-AvIkHI6+wuwHQTgfnl4kEPWeMKo5yw4FnXJJK+jf/PRWAflmuJKTs06ENRNJ6sCQceIUVqAi/fy8Nav8alnv0w==",
- "requires": {
- "@types/jsonwebtoken": "^9",
- "express-unless": "^2.1.3",
- "jsonwebtoken": "^9.0.0"
- }
- },
- "express-session": {
- "version": "1.17.3",
- "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.3.tgz",
- "integrity": "sha512-4+otWXlShYlG1Ma+2Jnn+xgKUZTMJ5QD3YvfilX3AcocOAbIkVylSWEklzALe/+Pu4qV6TYBj5GwOBFfdKqLBw==",
- "requires": {
- "cookie": "0.4.2",
- "cookie-signature": "1.0.6",
- "debug": "2.6.9",
- "depd": "~2.0.0",
- "on-headers": "~1.0.2",
- "parseurl": "~1.3.3",
- "safe-buffer": "5.2.1",
- "uid-safe": "~2.1.5"
- },
- "dependencies": {
- "cookie": {
- "version": "0.4.2",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
- "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA=="
- }
- }
- },
- "express-unless": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/express-unless/-/express-unless-2.1.3.tgz",
- "integrity": "sha512-wj4tLMyCVYuIIKHGt0FhCtIViBcwzWejX0EjNxveAa6dG+0XBCQhMbx+PnkLkFCxLC69qoFrxds4pIyL88inaQ=="
- },
- "express-validator": {
- "version": "6.14.3",
- "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-6.14.3.tgz",
- "integrity": "sha512-c4b9NMdhskfcLbH/FchsSfCt4Vb14gKzcotG9zLS+VoOJDox57aGhCL+kmAu7cl+ytaSed+HD5jdJhel8DQsdg==",
- "requires": {
- "lodash": "^4.17.21",
- "validator": "^13.7.0"
- }
- },
- "extend": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
- "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
- },
- "extsprintf": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
- "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g=="
- },
- "fast-deep-equal": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
- },
- "fast-json-stable-stringify": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
- },
- "fast-levenshtein": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
- "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
- "dev": true
- },
- "fastq": {
- "version": "1.15.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
- "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
- "dev": true,
- "requires": {
- "reusify": "^1.0.4"
- }
- },
- "file-entry-cache": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
- "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
- "dev": true,
- "requires": {
- "flat-cache": "^3.0.4"
- }
- },
- "file-type": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/file-type/-/file-type-9.0.0.tgz",
- "integrity": "sha512-Qe/5NJrgIOlwijpq3B7BEpzPFcgzggOTagZmkXQY4LA6bsXKTUstK7Wp12lEJ/mLKTpvIZxmIuRcLYWT6ov9lw=="
- },
- "fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "dev": true,
- "requires": {
- "to-regex-range": "^5.0.1"
- }
- },
- "finalhandler": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
- "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
- "requires": {
- "debug": "2.6.9",
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "on-finished": "2.4.1",
- "parseurl": "~1.3.3",
- "statuses": "2.0.1",
- "unpipe": "~1.0.0"
- }
- },
- "find-up": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
- "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
- "dev": true,
- "requires": {
- "locate-path": "^6.0.0",
- "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.2.7",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
- "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
- "dev": true
- },
- "forever-agent": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
- "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw=="
- },
- "form-data": {
- "version": "2.5.1",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
- "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
- "requires": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.6",
- "mime-types": "^2.1.12"
- }
- },
- "forwarded": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
- "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
- },
- "fresh": {
- "version": "0.5.2",
- "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
- "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="
- },
- "fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
- },
- "fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "dev": true,
- "optional": true
- },
- "function-bind": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
- },
- "generate-rsa-keypair": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/generate-rsa-keypair/-/generate-rsa-keypair-0.2.1.tgz",
- "integrity": "sha512-vxLfzfy6WbMLtkKV4AJtg7QH0ZqGGNkSYM6S0Q72Z70QXsztLklKFtX15te3YLIqmiQAYi3g3MWsTfXd6djkpg=="
- },
- "get-intrinsic": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
- "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
- "requires": {
- "function-bind": "^1.1.1",
- "has": "^1.0.3",
- "has-symbols": "^1.0.3"
- }
- },
- "getpass": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
- "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==",
- "requires": {
- "assert-plus": "^1.0.0"
- }
- },
- "gifwrap": {
- "version": "0.9.4",
- "resolved": "https://registry.npmjs.org/gifwrap/-/gifwrap-0.9.4.tgz",
- "integrity": "sha512-MDMwbhASQuVeD4JKd1fKgNgCRL3fGqMM4WaqpNhWO0JiMOAjbQdumbs4BbBZEy9/M00EHEjKN3HieVhCUlwjeQ==",
- "requires": {
- "image-q": "^4.0.0",
- "omggif": "^1.0.10"
- }
- },
- "glob": {
- "version": "8.1.0",
- "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
- "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
- "requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^5.0.1",
- "once": "^1.3.0"
- },
- "dependencies": {
- "brace-expansion": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
- "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
- "requires": {
- "balanced-match": "^1.0.0"
- }
- },
- "minimatch": {
- "version": "5.1.6",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
- "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
- "requires": {
- "brace-expansion": "^2.0.1"
- }
- }
- }
- },
- "glob-parent": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
- "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
- "dev": true,
- "requires": {
- "is-glob": "^4.0.3"
- }
- },
- "global": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz",
- "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==",
- "requires": {
- "min-document": "^2.19.0",
- "process": "^0.11.10"
- }
- },
- "globals": {
- "version": "13.20.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
- "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
- "dev": true,
- "requires": {
- "type-fest": "^0.20.2"
- }
- },
- "graceful-fs": {
- "version": "4.2.10",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
- "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="
- },
- "grapheme-splitter": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
- "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
- "dev": true
- },
- "greenlock": {
- "version": "2.8.8",
- "resolved": "https://registry.npmjs.org/greenlock/-/greenlock-2.8.8.tgz",
- "integrity": "sha512-U2pqxXXf0naeZc2363Xe174C6/T9lXGZYQjXBqa/PMb1CYRQuHwXlAqFEUu75JkxyHAzFGj/uliqSyQwIc91Yg==",
- "requires": {
- "acme": "^1.3.5",
- "acme-dns-01-cli": "^3.0.0",
- "acme-v2": "^1.8.6",
- "cert-info": "^1.5.1",
- "greenlock-store-fs": "^3.0.2",
- "keypairs": "^1.2.14",
- "le-challenge-fs": "^2.0.2",
- "le-sni-auto": "^2.1.9",
- "le-store-certbot": "^2.2.3",
- "rsa-compat": "^2.0.8"
- }
- },
- "greenlock-express": {
- "version": "2.7.18",
- "resolved": "https://registry.npmjs.org/greenlock-express/-/greenlock-express-2.7.18.tgz",
- "integrity": "sha512-8gOSo4twkd4Fdmc45jfHMCXdsYnYutcUGDKZ+FRZH8XQc712glqYNrWaeWThmh0QQ/ZEiV+WGROtAdGrY5sGlQ==",
- "requires": {
- "greenlock": "^2.8.8",
- "redirect-https": "^1.1.5"
- }
- },
- "greenlock-store-fs": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/greenlock-store-fs/-/greenlock-store-fs-3.2.2.tgz",
- "integrity": "sha512-92ejLB4DyV4qv/2b6VLGF2nKfYQeIfg3o+e/1cIoYLjlIaUFdbBXkzLTRozFlHsQPZt2ALi5qYrpC9IwH7GK8A==",
- "requires": {
- "@root/mkdirp": "^1.0.0",
- "safe-replace": "^1.1.0"
- }
- },
- "handlebars": {
- "version": "4.7.7",
- "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz",
- "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==",
- "requires": {
- "minimist": "^1.2.5",
- "neo-async": "^2.6.0",
- "source-map": "^0.6.1",
- "uglify-js": "^3.1.4",
- "wordwrap": "^1.0.0"
- }
- },
- "har-schema": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
- "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q=="
- },
- "har-validator": {
- "version": "5.1.5",
- "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
- "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
- "requires": {
- "ajv": "^6.12.3",
- "har-schema": "^2.0.0"
- }
- },
- "has": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
- "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
- "requires": {
- "function-bind": "^1.1.1"
- }
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="
- },
- "has-property-descriptors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
- "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
- "requires": {
- "get-intrinsic": "^1.1.1"
- }
- },
- "has-symbols": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
- "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
- },
- "htmlparser2": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz",
- "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==",
- "requires": {
- "domelementtype": "^2.3.0",
- "domhandler": "^5.0.2",
- "domutils": "^3.0.1",
- "entities": "^4.3.0"
- }
- },
- "http-errors": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
- "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
- "requires": {
- "depd": "2.0.0",
- "inherits": "2.0.4",
- "setprototypeof": "1.2.0",
- "statuses": "2.0.1",
- "toidentifier": "1.0.1"
- }
- },
- "http-signature": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
- "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==",
- "requires": {
- "assert-plus": "^1.0.0",
- "jsprim": "^1.2.2",
- "sshpk": "^1.7.0"
- }
- },
- "ical": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/ical/-/ical-0.6.0.tgz",
- "integrity": "sha512-P7R3uMhFnLY7Tfiz+2uZIninThWIoUM5BVO4f9ZsV36GYqoBkIg6RbkrBhmWCvcuK1vLzljLaNtpWeGM/5ZHRg==",
- "requires": {
- "request": "^2.88.0",
- "rrule": "2.4.1"
- }
- },
- "ical-generator": {
- "version": "1.15.4",
- "resolved": "https://registry.npmjs.org/ical-generator/-/ical-generator-1.15.4.tgz",
- "integrity": "sha512-drXe4RLkfNlvDvdy/E6BUI9p+01L3ySK1ufNEYI9TxNKG9ZA3G60QWoZvD1dtmH4scwDxYu6/sZBPJvYVNrj8A==",
- "requires": {
- "moment-timezone": "^0.5.32"
- }
- },
- "iconv-lite": {
- "version": "0.4.24",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
- "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
- "requires": {
- "safer-buffer": ">= 2.1.2 < 3"
- }
- },
- "ieee754": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
- "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
- },
- "ignore": {
- "version": "5.2.4",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
- "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
- "dev": true
- },
- "ignore-by-default": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
- "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
- "dev": true
- },
- "image-q": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/image-q/-/image-q-4.0.0.tgz",
- "integrity": "sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw==",
- "requires": {
- "@types/node": "16.9.1"
- },
- "dependencies": {
- "@types/node": {
- "version": "16.9.1",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.1.tgz",
- "integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g=="
- }
- }
- },
- "import-fresh": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
- "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
- "dev": true,
- "requires": {
- "parent-module": "^1.0.0",
- "resolve-from": "^4.0.0"
- }
- },
- "imurmurhash": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
- "dev": true
- },
- "inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
- "requires": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
- },
- "ipaddr.js": {
- "version": "1.9.1",
- "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
- "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
- },
- "is-binary-path": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
- "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
- "dev": true,
- "requires": {
- "binary-extensions": "^2.0.0"
- }
- },
- "is-extglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
- "dev": true
- },
- "is-function": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz",
- "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ=="
- },
- "is-glob": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
- "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "dev": true,
- "requires": {
- "is-extglob": "^2.1.1"
- }
- },
- "is-nan": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz",
- "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==",
- "requires": {
- "call-bind": "^1.0.0",
- "define-properties": "^1.1.3"
- }
- },
- "is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true
- },
- "is-path-inside": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
- "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
- "dev": true
- },
- "is-plain-object": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
- "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
- },
- "is-typedarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
- "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
- },
- "isarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
- },
- "isexe": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
- "dev": true
- },
- "isstream": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
- "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g=="
- },
- "jimp": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/jimp/-/jimp-0.16.2.tgz",
- "integrity": "sha512-UpItBk81a92f8oEyoGYbO3YK4QcM0hoIyuGHmShoF9Ov63P5Qo7Q/X2xsAgnODmSuDJFOtrPtJd5GSWW4LKdOQ==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@jimp/custom": "^0.16.2",
- "@jimp/plugins": "^0.16.2",
- "@jimp/types": "^0.16.2",
- "regenerator-runtime": "^0.13.3"
- }
- },
- "jpeg-js": {
- "version": "0.4.4",
- "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz",
- "integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg=="
- },
- "js-sdsl": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz",
- "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==",
- "dev": true
- },
- "js-yaml": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
- "dev": true,
- "requires": {
- "argparse": "^2.0.1"
- }
- },
- "jsbn": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
- "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg=="
- },
- "json-schema": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
- "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="
- },
- "json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
- },
- "json-stable-stringify-without-jsonify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
- "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
- "dev": true
- },
- "json-stringify-safe": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
- "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="
- },
- "jsonwebtoken": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz",
- "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==",
- "requires": {
- "jws": "^3.2.2",
- "lodash": "^4.17.21",
- "ms": "^2.1.1",
- "semver": "^7.3.8"
- },
- "dependencies": {
- "ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
- },
- "semver": {
- "version": "7.3.8",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
- "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
- "requires": {
- "lru-cache": "^6.0.0"
- }
- }
- }
- },
- "jsprim": {
- "version": "1.4.2",
- "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
- "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==",
- "requires": {
- "assert-plus": "1.0.0",
- "extsprintf": "1.3.0",
- "json-schema": "0.4.0",
- "verror": "1.10.0"
- }
- },
- "jwa": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
- "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
- "requires": {
- "buffer-equal-constant-time": "1.0.1",
- "ecdsa-sig-formatter": "1.0.11",
- "safe-buffer": "^5.0.1"
- }
- },
- "jws": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
- "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
- "requires": {
- "jwa": "^1.4.1",
- "safe-buffer": "^5.0.1"
- }
- },
- "kareem": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.2.tgz",
- "integrity": "sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ=="
- },
- "keypairs": {
- "version": "1.2.14",
- "resolved": "https://registry.npmjs.org/keypairs/-/keypairs-1.2.14.tgz",
- "integrity": "sha512-ZoZfZMygyB0QcjSlz7Rh6wT2CJasYEHBPETtmHZEfxuJd7bnsOG5AdtPZqHZBT+hoHvuWCp/4y8VmvTvH0Y9uA==",
- "requires": {
- "eckles": "^1.4.1",
- "rasha": "^1.2.4"
- }
- },
- "le-challenge-fs": {
- "version": "2.0.9",
- "resolved": "https://registry.npmjs.org/le-challenge-fs/-/le-challenge-fs-2.0.9.tgz",
- "integrity": "sha512-stzI6rxd+aXGxBl87QJKKY/i/wl3uz6EoWzX2xSazJvCPSYBQys1RVNgOcf0SfUQPh6TBCFJFSJkiR4mznb4sg==",
- "requires": {
- "@root/mkdirp": "^1.0.0"
- }
- },
- "le-sni-auto": {
- "version": "2.1.9",
- "resolved": "https://registry.npmjs.org/le-sni-auto/-/le-sni-auto-2.1.9.tgz",
- "integrity": "sha512-QmQHNwQDi/56GY8+qczFZ06FZbxaeJQjbjEhwwQHhkJ9IHhIQFkPfCT/OyDfLj4gqLIrg5ZX8CemxxVZnLEYfg=="
- },
- "le-store-certbot": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/le-store-certbot/-/le-store-certbot-2.2.3.tgz",
- "integrity": "sha512-c4ACR+v+JKMiAOOshLh6gdCKA7wIWR16+mROMLpQjq3rXJ3Vm8FaBHe2H+crT+flP+g7FmciAwUlfOJEJpIuCQ==",
- "requires": {
- "@root/mkdirp": "^1.0.0",
- "pyconf": "^1.1.7",
- "safe-replace": "^1.1.0"
- }
- },
- "levn": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
- "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
- "dev": true,
- "requires": {
- "prelude-ls": "^1.2.1",
- "type-check": "~0.4.0"
- }
- },
- "load-bmfont": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.4.1.tgz",
- "integrity": "sha512-8UyQoYmdRDy81Brz6aLAUhfZLwr5zV0L3taTQ4hju7m6biuwiWiJXjPhBJxbUQJA8PrkvJ/7Enqmwk2sM14soA==",
- "requires": {
- "buffer-equal": "0.0.1",
- "mime": "^1.3.4",
- "parse-bmfont-ascii": "^1.0.3",
- "parse-bmfont-binary": "^1.0.5",
- "parse-bmfont-xml": "^1.1.4",
- "phin": "^2.9.1",
- "xhr": "^2.0.1",
- "xtend": "^4.0.0"
- }
- },
- "locate-path": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
- "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
- "dev": true,
- "requires": {
- "p-locate": "^5.0.0"
- }
- },
- "lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
- },
- "lodash.merge": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
- "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
- "dev": true
- },
- "long-timeout": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/long-timeout/-/long-timeout-0.1.1.tgz",
- "integrity": "sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w=="
- },
- "lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "luxon": {
- "version": "1.28.1",
- "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.1.tgz",
- "integrity": "sha512-gYHAa180mKrNIUJCbwpmD0aTu9kV0dREDrwNnuyFAsO1Wt0EVYSZelPnJlbj9HplzXX/YWXHFTL45kvZ53M0pw==",
- "optional": true
- },
- "marked": {
- "version": "4.2.12",
- "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.12.tgz",
- "integrity": "sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw=="
- },
- "media-typer": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
- "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="
- },
- "memory-pager": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
- "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
- "optional": true
- },
- "merge-descriptors": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
- "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
- },
- "methods": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
- "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="
- },
- "mime": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
- "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
- },
- "mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
- },
- "mime-types": {
- "version": "2.1.35",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
- "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "requires": {
- "mime-db": "1.52.0"
- }
- },
- "min-document": {
- "version": "2.19.0",
- "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",
- "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==",
- "requires": {
- "dom-walk": "^0.1.0"
- }
- },
- "minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- },
- "minimist": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
- "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g=="
- },
- "mkdirp": {
- "version": "0.5.6",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
- "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
- "requires": {
- "minimist": "^1.2.6"
- }
- },
- "moment": {
- "version": "2.29.4",
- "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
- "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w=="
- },
- "moment-timezone": {
- "version": "0.5.40",
- "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.40.tgz",
- "integrity": "sha512-tWfmNkRYmBkPJz5mr9GVDn9vRlVZOTe6yqY92rFxiOdWXbjaR0+9LwQnZGGuNR63X456NqmEkbskte8tWL5ePg==",
- "requires": {
- "moment": ">= 2.9.0"
- }
- },
- "mongodb": {
- "version": "3.7.3",
- "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.3.tgz",
- "integrity": "sha512-Psm+g3/wHXhjBEktkxXsFMZvd3nemI0r3IPsE0bU+4//PnvNWKkzhZcEsbPcYiWqe8XqXJJEg4Tgtr7Raw67Yw==",
- "requires": {
- "bl": "^2.2.1",
- "bson": "^1.1.4",
- "denque": "^1.4.1",
- "optional-require": "^1.1.8",
- "safe-buffer": "^5.1.2",
- "saslprep": "^1.0.0"
- },
- "dependencies": {
- "optional-require": {
- "version": "1.1.8",
- "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.1.8.tgz",
- "integrity": "sha512-jq83qaUb0wNg9Krv1c5OQ+58EK+vHde6aBPzLvPPqJm89UQWsvSuFy9X/OSNJnFeSOKo7btE0n8Nl2+nE+z5nA==",
- "requires": {
- "require-at": "^1.0.6"
- }
- }
- }
- },
- "mongoose": {
- "version": "5.13.15",
- "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.15.tgz",
- "integrity": "sha512-cxp1Gbb8yUWkaEbajdhspSaKzAvsIvOtRlYD87GN/P2QEUhpd6bIvebi36T6M0tIVAMauNaK9SPA055N3PwF8Q==",
- "requires": {
- "@types/bson": "1.x || 4.0.x",
- "@types/mongodb": "^3.5.27",
- "bson": "^1.1.4",
- "kareem": "2.3.2",
- "mongodb": "3.7.3",
- "mongoose-legacy-pluralize": "1.0.2",
- "mpath": "0.8.4",
- "mquery": "3.2.5",
- "ms": "2.1.2",
- "optional-require": "1.0.x",
- "regexp-clone": "1.0.0",
- "safe-buffer": "5.2.1",
- "sift": "13.5.2",
- "sliced": "1.0.1"
- },
- "dependencies": {
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
- }
- }
- },
- "mongoose-legacy-pluralize": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz",
- "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==",
- "requires": {}
- },
- "mpath": {
- "version": "0.8.4",
- "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.8.4.tgz",
- "integrity": "sha512-DTxNZomBcTWlrMW76jy1wvV37X/cNNxPW1y2Jzd4DZkAaC5ZGsm8bfGfNOthcDuRJujXLqiuS6o3Tpy0JEoh7g=="
- },
- "mquery": {
- "version": "3.2.5",
- "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.5.tgz",
- "integrity": "sha512-VjOKHHgU84wij7IUoZzFRU07IAxd5kWJaDmyUzQlbjHjyoeK5TNeeo8ZsFDtTYnSgpW6n/nMNIHvE3u8Lbrf4A==",
- "requires": {
- "bluebird": "3.5.1",
- "debug": "3.1.0",
- "regexp-clone": "^1.0.0",
- "safe-buffer": "5.1.2",
- "sliced": "1.0.1"
- },
- "dependencies": {
- "debug": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
- "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
- "requires": {
- "ms": "2.0.0"
- }
- },
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
- }
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
- },
- "multer": {
- "version": "1.4.5-lts.1",
- "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz",
- "integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==",
- "requires": {
- "append-field": "^1.0.0",
- "busboy": "^1.0.0",
- "concat-stream": "^1.5.2",
- "mkdirp": "^0.5.4",
- "object-assign": "^4.1.1",
- "type-is": "^1.6.4",
- "xtend": "^4.0.0"
- }
- },
- "nanoid": {
- "version": "3.3.4",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
- "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw=="
- },
- "natural-compare": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
- "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
- "dev": true
- },
- "negotiator": {
- "version": "0.6.3",
- "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
- "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
- },
- "neo-async": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
- "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
- },
- "niceware": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/niceware/-/niceware-3.0.0.tgz",
- "integrity": "sha512-DbeDuqe836Ba4S9vjim4jTbbqmjCMwuAXFCVdh4QAvbmLOhmIQs84IakYrcXd/87VCsj1XKhSmmg7bAmwAEh5A==",
- "requires": {
- "binary-search": "^1.3.6",
- "randombytes": "^2.0.6"
- }
- },
- "node-schedule": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/node-schedule/-/node-schedule-1.3.3.tgz",
- "integrity": "sha512-uF9Ubn6luOPrcAYKfsXWimcJ1tPFtQ8I85wb4T3NgJQrXazEzojcFZVk46ZlLHby3eEJChgkV/0T689IsXh2Gw==",
- "requires": {
- "cron-parser": "^2.18.0",
- "long-timeout": "0.1.1",
- "sorted-array-functions": "^1.3.0"
- }
- },
- "nodemailer": {
- "version": "6.9.1",
- "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.1.tgz",
- "integrity": "sha512-qHw7dOiU5UKNnQpXktdgQ1d3OFgRAekuvbJLcdG5dnEo/GtcTHRYM7+UfJARdOFU9WUQO8OiIamgWPmiSFHYAA=="
- },
- "nodemon": {
- "version": "2.0.20",
- "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz",
- "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==",
- "dev": true,
- "requires": {
- "chokidar": "^3.5.2",
- "debug": "^3.2.7",
- "ignore-by-default": "^1.0.1",
- "minimatch": "^3.1.2",
- "pstree.remy": "^1.1.8",
- "semver": "^5.7.1",
- "simple-update-notifier": "^1.0.7",
- "supports-color": "^5.5.0",
- "touch": "^3.1.0",
- "undefsafe": "^2.0.5"
- },
- "dependencies": {
- "debug": {
- "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"
- }
- },
- "ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
- "dev": true
- }
- }
- },
- "nopt": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
- "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==",
- "dev": true,
- "requires": {
- "abbrev": "1"
- }
- },
- "normalize-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
- "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
- "dev": true
- },
- "oauth-sign": {
- "version": "0.9.0",
- "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
- "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
- },
- "object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
- },
- "object-inspect": {
- "version": "1.12.3",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
- "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g=="
- },
- "object-keys": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
- "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="
- },
- "omggif": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/omggif/-/omggif-1.0.10.tgz",
- "integrity": "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw=="
- },
- "on-finished": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
- "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
- "requires": {
- "ee-first": "1.1.1"
- }
- },
- "on-headers": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
- "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA=="
- },
- "once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
- "requires": {
- "wrappy": "1"
- }
- },
- "optional-require": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz",
- "integrity": "sha512-RV2Zp2MY2aeYK5G+B/Sps8lW5NHAzE5QClbFP15j+PWmP+T9PxlJXBOOLoSAdgwFvS4t0aMR4vpedMkbHfh0nA=="
- },
- "optionator": {
- "version": "0.9.1",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
- "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
- "dev": true,
- "requires": {
- "deep-is": "^0.1.3",
- "fast-levenshtein": "^2.0.6",
- "levn": "^0.4.1",
- "prelude-ls": "^1.2.1",
- "type-check": "^0.4.0",
- "word-wrap": "^1.2.3"
- }
- },
- "p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "requires": {
- "yocto-queue": "^0.1.0"
- }
- },
- "p-locate": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
- "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
- "dev": true,
- "requires": {
- "p-limit": "^3.0.2"
- }
- },
- "pako": {
- "version": "1.0.11",
- "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
- "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
- },
- "parent-module": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
- "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
- "dev": true,
- "requires": {
- "callsites": "^3.0.0"
- }
- },
- "parse-bmfont-ascii": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/parse-bmfont-ascii/-/parse-bmfont-ascii-1.0.6.tgz",
- "integrity": "sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA=="
- },
- "parse-bmfont-binary": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/parse-bmfont-binary/-/parse-bmfont-binary-1.0.6.tgz",
- "integrity": "sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA=="
- },
- "parse-bmfont-xml": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/parse-bmfont-xml/-/parse-bmfont-xml-1.1.4.tgz",
- "integrity": "sha512-bjnliEOmGv3y1aMEfREMBJ9tfL3WR0i0CKPj61DnSLaoxWR3nLrsQrEbCId/8rF4NyRF0cCqisSVXyQYWM+mCQ==",
- "requires": {
- "xml-parse-from-string": "^1.0.0",
- "xml2js": "^0.4.5"
- }
- },
- "parse-headers": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz",
- "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA=="
- },
- "parse-srcset": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz",
- "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q=="
- },
- "parseurl": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
- "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
- },
- "path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
- "dev": true
- },
- "path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
- "dev": true
- },
- "path-key": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "dev": true
- },
- "path-to-regexp": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
- "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
- },
- "performance-now": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
- "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
- },
- "phin": {
- "version": "2.9.3",
- "resolved": "https://registry.npmjs.org/phin/-/phin-2.9.3.tgz",
- "integrity": "sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA=="
- },
- "picocolors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
- "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
- },
- "picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
- "dev": true
- },
- "pixelmatch": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz",
- "integrity": "sha512-J8B6xqiO37sU/gkcMglv6h5Jbd9xNER7aHzpfRdNmV4IbQBzBpe4l9XmbG+xPF/znacgu2jfEw+wHffaq/YkXA==",
- "requires": {
- "pngjs": "^3.0.0"
- }
- },
- "pngjs": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz",
- "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w=="
- },
- "postcss": {
- "version": "8.4.21",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz",
- "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==",
- "requires": {
- "nanoid": "^3.3.4",
- "picocolors": "^1.0.0",
- "source-map-js": "^1.0.2"
- }
- },
- "prelude-ls": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
- "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
- "dev": true
- },
- "process": {
- "version": "0.11.10",
- "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
- "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="
- },
- "process-nextick-args": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
- "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
- },
- "proxy-addr": {
- "version": "2.0.7",
- "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
- "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
- "requires": {
- "forwarded": "0.2.0",
- "ipaddr.js": "1.9.1"
- }
- },
- "psl": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
- "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag=="
- },
- "pstree.remy": {
- "version": "1.1.8",
- "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
- "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
- "dev": true
- },
- "punycode": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
- "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA=="
- },
- "pyconf": {
- "version": "1.1.7",
- "resolved": "https://registry.npmjs.org/pyconf/-/pyconf-1.1.7.tgz",
- "integrity": "sha512-v4clh33m68sjtMsh8XMpjhGWb/MQODAYZ1y7ORG5Qv58UK25OddoB+oXyexgDkK8ttFui/lZm2sQDgA2Ftjfkw==",
- "requires": {
- "safe-replace": "^1.0.2"
- }
- },
- "qs": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
- "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
- "requires": {
- "side-channel": "^1.0.4"
- }
- },
- "queue-microtask": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
- "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
- "dev": true
- },
- "random-bytes": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
- "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ=="
- },
- "randombytes": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
- "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
- "requires": {
- "safe-buffer": "^5.1.0"
- }
- },
- "randomstring": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/randomstring/-/randomstring-1.2.3.tgz",
- "integrity": "sha512-3dEFySepTzp2CvH6W/ASYGguPPveBuz5MpZ7MuoUkoVehmyNl9+F9c9GFVrz2QPbM9NXTIHGcmJDY/3j4677kQ==",
- "requires": {
- "array-uniq": "1.0.2",
- "randombytes": "2.0.3"
- },
- "dependencies": {
- "randombytes": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.3.tgz",
- "integrity": "sha512-lDVjxQQFoCG1jcrP06LNo2lbWp4QTShEXnhActFBwYuHprllQV6VUpwreApsYqCgD+N1mHoqJ/BI/4eV4R2GYg=="
- }
- }
- },
- "range-parser": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
- "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
- },
- "rasha": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/rasha/-/rasha-1.2.5.tgz",
- "integrity": "sha512-KxtX+/fBk+wM7O3CNgwjSh5elwFilLvqWajhr6wFr2Hd63JnKTTi43Tw+Jb1hxJQWOwoya+NZWR2xztn3hCrTw=="
- },
- "raw-body": {
- "version": "2.5.1",
- "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
- "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
- "requires": {
- "bytes": "3.1.2",
- "http-errors": "2.0.0",
- "iconv-lite": "0.4.24",
- "unpipe": "1.0.0"
- }
- },
- "readable-stream": {
- "version": "2.3.7",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
- "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
- "requires": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.3",
- "isarray": "~1.0.0",
- "process-nextick-args": "~2.0.0",
- "safe-buffer": "~5.1.1",
- "string_decoder": "~1.1.1",
- "util-deprecate": "~1.0.1"
- },
- "dependencies": {
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
- }
- }
- },
- "readdirp": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
- "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
- "dev": true,
- "requires": {
- "picomatch": "^2.2.1"
- }
- },
- "redirect-https": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/redirect-https/-/redirect-https-1.3.1.tgz",
- "integrity": "sha512-Stex2nI+tMpZXKvy++32TiBXEy+GdpAfp3EUnl5BqCiJ5f5i6XvUSFrs7TR7IoRSlthM7ZtD89uYGTtJBXlFYg==",
- "requires": {
- "escape-html": "^1.0.3"
- }
- },
- "regenerator-runtime": {
- "version": "0.13.11",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
- "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
- },
- "regexp-clone": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz",
- "integrity": "sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw=="
- },
- "regexpp": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
- "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
- "dev": true
- },
- "request": {
- "version": "2.88.2",
- "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
- "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
- "requires": {
- "aws-sign2": "~0.7.0",
- "aws4": "^1.8.0",
- "caseless": "~0.12.0",
- "combined-stream": "~1.0.6",
- "extend": "~3.0.2",
- "forever-agent": "~0.6.1",
- "form-data": "~2.3.2",
- "har-validator": "~5.1.3",
- "http-signature": "~1.2.0",
- "is-typedarray": "~1.0.0",
- "isstream": "~0.1.2",
- "json-stringify-safe": "~5.0.1",
- "mime-types": "~2.1.19",
- "oauth-sign": "~0.9.0",
- "performance-now": "^2.1.0",
- "qs": "~6.5.2",
- "safe-buffer": "^5.1.2",
- "tough-cookie": "~2.5.0",
- "tunnel-agent": "^0.6.0",
- "uuid": "^3.3.2"
- },
- "dependencies": {
- "form-data": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
- "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
- "requires": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.6",
- "mime-types": "^2.1.12"
- }
- },
- "qs": {
- "version": "6.5.3",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz",
- "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA=="
- }
- }
- },
- "require-at": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/require-at/-/require-at-1.0.6.tgz",
- "integrity": "sha512-7i1auJbMUrXEAZCOQ0VNJgmcT2VOKPRl2YGJwgpHpC9CE91Mv4/4UYIUm4chGJaI381ZDq1JUicFii64Hapd8g=="
- },
- "resolve-from": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
- "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
- "dev": true
- },
- "reusify": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
- "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
- "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"
- },
- "dependencies": {
- "glob": {
- "version": "7.2.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
- "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
- "dev": true,
- "requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.1.1",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- }
- }
- }
- },
- "rrule": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/rrule/-/rrule-2.4.1.tgz",
- "integrity": "sha512-+NcvhETefswZq13T8nkuEnnQ6YgUeZaqMqVbp+ZiFDPCbp3AVgQIwUvNVDdMNrP05bKZG9ddDULFp0qZZYDrxg==",
- "requires": {
- "luxon": "^1.3.3"
- }
- },
- "rsa-compat": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/rsa-compat/-/rsa-compat-2.0.8.tgz",
- "integrity": "sha512-BFiiSEbuxzsVdaxpejbxfX07qs+rtous49Y6mL/zw6YHh9cranDvm2BvBmqT3rso84IsxNlP5BXnuNvm1Wn3Tw==",
- "requires": {
- "keypairs": "^1.2.14"
- }
- },
- "run-parallel": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
- "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
- "dev": true,
- "requires": {
- "queue-microtask": "^1.2.2"
- }
- },
- "safe-buffer": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
- },
- "safe-replace": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/safe-replace/-/safe-replace-1.1.0.tgz",
- "integrity": "sha512-9/V2E0CDsKs9DWOOwJH7jYpSl9S3N05uyevNjvsnDauBqRowBPOyot1fIvV5N2IuZAbYyvrTXrYFVG0RZInfFw=="
- },
- "safer-buffer": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
- },
- "sanitize-html": {
- "version": "2.9.0",
- "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.9.0.tgz",
- "integrity": "sha512-KY1hpSbqFNcpoLf+nP7iStbP5JfQZ2Nd19ZEE7qFsQqRdp+sO5yX/e5+HoG9puFAcSTEpzQuihfKUltDcLlQjg==",
- "requires": {
- "deepmerge": "^4.2.2",
- "escape-string-regexp": "^4.0.0",
- "htmlparser2": "^8.0.0",
- "is-plain-object": "^5.0.0",
- "parse-srcset": "^1.0.2",
- "postcss": "^8.3.11"
- },
- "dependencies": {
- "escape-string-regexp": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
- "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="
- }
- }
- },
- "saslprep": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
- "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==",
- "optional": true,
- "requires": {
- "sparse-bitfield": "^3.0.3"
- }
- },
- "sax": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
- "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
- },
- "semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
- "dev": true
- },
- "send": {
- "version": "0.18.0",
- "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
- "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
- "requires": {
- "debug": "2.6.9",
- "depd": "2.0.0",
- "destroy": "1.2.0",
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "etag": "~1.8.1",
- "fresh": "0.5.2",
- "http-errors": "2.0.0",
- "mime": "1.6.0",
- "ms": "2.1.3",
- "on-finished": "2.4.1",
- "range-parser": "~1.2.1",
- "statuses": "2.0.1"
- },
- "dependencies": {
- "ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
- }
- }
- },
- "serve-static": {
- "version": "1.15.0",
- "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
- "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
- "requires": {
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "parseurl": "~1.3.3",
- "send": "0.18.0"
- }
- },
- "setprototypeof": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
- "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
- },
- "shebang-command": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "dev": true,
- "requires": {
- "shebang-regex": "^3.0.0"
- }
- },
- "shebang-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "dev": true
- },
- "side-channel": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
- "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
- "requires": {
- "call-bind": "^1.0.0",
- "get-intrinsic": "^1.0.2",
- "object-inspect": "^1.9.0"
- }
- },
- "sift": {
- "version": "13.5.2",
- "resolved": "https://registry.npmjs.org/sift/-/sift-13.5.2.tgz",
- "integrity": "sha512-+gxdEOMA2J+AI+fVsCqeNn7Tgx3M9ZN9jdi95939l1IJ8cZsqS8sqpJyOkic2SJk+1+98Uwryt/gL6XDaV+UZA=="
- },
- "simple-update-notifier": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz",
- "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==",
- "dev": true,
- "requires": {
- "semver": "~7.0.0"
- },
- "dependencies": {
- "semver": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz",
- "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==",
- "dev": true
- }
- }
- },
- "sliced": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz",
- "integrity": "sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2Xxzm/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yA=="
- },
- "sorted-array-functions": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/sorted-array-functions/-/sorted-array-functions-1.3.0.tgz",
- "integrity": "sha512-2sqgzeFlid6N4Z2fUQ1cvFmTOLRi/sEDzSQ0OKYchqgoPmQBVyM3959qYx3fpS6Esef80KjmpgPeEr028dP3OA=="
- },
- "source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
- },
- "source-map-js": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
- "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw=="
- },
- "sparse-bitfield": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
- "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
- "optional": true,
- "requires": {
- "memory-pager": "^1.0.2"
- }
- },
- "sshpk": {
- "version": "1.17.0",
- "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz",
- "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==",
- "requires": {
- "asn1": "~0.2.3",
- "assert-plus": "^1.0.0",
- "bcrypt-pbkdf": "^1.0.0",
- "dashdash": "^1.12.0",
- "ecc-jsbn": "~0.1.1",
- "getpass": "^0.1.1",
- "jsbn": "~0.1.0",
- "safer-buffer": "^2.0.2",
- "tweetnacl": "~0.14.0"
- }
- },
- "statuses": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
- "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
- },
- "streamsearch": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
- "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="
- },
- "string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "requires": {
- "safe-buffer": "~5.1.0"
- },
- "dependencies": {
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
- }
- }
- },
- "strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- }
- },
- "strip-json-comments": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
- "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
- "dev": true
- },
- "supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "requires": {
- "has-flag": "^3.0.0"
- }
- },
- "text-table": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
- "dev": true
- },
- "timm": {
- "version": "1.7.1",
- "resolved": "https://registry.npmjs.org/timm/-/timm-1.7.1.tgz",
- "integrity": "sha512-IjZc9KIotudix8bMaBW6QvMuq64BrJWFs1+4V0lXwWGQZwH+LnX87doAYhem4caOEusRP9/g6jVDQmZ8XOk1nw=="
- },
- "tinycolor2": {
- "version": "1.5.2",
- "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.5.2.tgz",
- "integrity": "sha512-h80m9GPFGbcLzZByXlNSEhp1gf8Dy+VX/2JCGUZsWLo7lV1mnE/XlxGYgRBoMLJh1lIDXP0EMC4RPTjlRaV+Bg=="
- },
- "to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
- "requires": {
- "is-number": "^7.0.0"
- }
- },
- "toidentifier": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
- "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
- },
- "touch": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
- "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==",
- "dev": true,
- "requires": {
- "nopt": "~1.0.10"
- }
- },
- "tough-cookie": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
- "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
- "requires": {
- "psl": "^1.1.28",
- "punycode": "^2.1.1"
- }
- },
- "tunnel-agent": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
- "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
- "requires": {
- "safe-buffer": "^5.0.1"
- }
- },
- "tweetnacl": {
- "version": "0.14.5",
- "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
- "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="
- },
- "type-check": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
- "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
- "dev": true,
- "requires": {
- "prelude-ls": "^1.2.1"
- }
- },
- "type-fest": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
- "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
- "dev": true
- },
- "type-is": {
- "version": "1.6.18",
- "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
- "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
- "requires": {
- "media-typer": "0.3.0",
- "mime-types": "~2.1.24"
- }
- },
- "typedarray": {
- "version": "0.0.6",
- "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
- "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
- },
- "uglify-js": {
- "version": "3.17.4",
- "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz",
- "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==",
- "optional": true
- },
- "uid-safe": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
- "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
- "requires": {
- "random-bytes": "~1.0.0"
- }
- },
- "undefsafe": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
- "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
- "dev": true
- },
- "unpipe": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
- "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="
- },
- "uri-js": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
- "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "requires": {
- "punycode": "^2.1.0"
- }
- },
- "utif": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/utif/-/utif-2.0.1.tgz",
- "integrity": "sha512-Z/S1fNKCicQTf375lIP9G8Sa1H/phcysstNrrSdZKj1f9g58J4NMgb5IgiEZN9/nLMPDwF0W7hdOe9Qq2IYoLg==",
- "requires": {
- "pako": "^1.0.5"
- }
- },
- "util-deprecate": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
- },
- "utils-merge": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
- "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="
- },
- "uuid": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
- "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
- },
- "validator": {
- "version": "13.7.0",
- "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz",
- "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw=="
- },
- "vary": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
- "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="
- },
- "verror": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
- "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==",
- "requires": {
- "assert-plus": "^1.0.0",
- "core-util-is": "1.0.2",
- "extsprintf": "^1.2.0"
- },
- "dependencies": {
- "core-util-is": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
- "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="
- }
- }
- },
- "which": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
- "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "dev": true,
- "requires": {
- "isexe": "^2.0.0"
- }
- },
- "word-wrap": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
- "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
- "dev": true
- },
- "wordwrap": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
- "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q=="
- },
- "wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
- },
- "xhr": {
- "version": "2.6.0",
- "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz",
- "integrity": "sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==",
- "requires": {
- "global": "~4.4.0",
- "is-function": "^1.0.1",
- "parse-headers": "^2.0.0",
- "xtend": "^4.0.0"
- }
- },
- "xml-parse-from-string": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz",
- "integrity": "sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g=="
- },
- "xml2js": {
- "version": "0.4.23",
- "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
- "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
- "requires": {
- "sax": ">=0.6.0",
- "xmlbuilder": "~11.0.0"
- }
- },
- "xmlbuilder": {
- "version": "11.0.1",
- "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
- "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="
- },
- "xtend": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
- "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
- },
- "yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
- },
- "yocto-queue": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
- "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
- "dev": true
- }
- }
-}
diff --git a/package.json b/package.json
index 8963fd2..d765c0e 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,9 @@
"description": "",
"main": "index.js",
"scripts": {
- "start": "nodemon ./start.js"
+ "build": "tsc",
+ "start": "node dist/start.js",
+ "dev": "nodemon -e ts,js --watch src --exec \"pnpm run build ; pnpm run start\""
},
"engines": {
"node": ">=16.16.0"
@@ -14,36 +16,33 @@
"license": "GPL-3.0-or-later",
"dependencies": {
"@sendgrid/mail": "^6.5.5",
- "body-parser": "^1.18.3",
+ "body-parser": "^1.20.2",
"cors": "^2.8.5",
- "dotenv": "^6.1.0",
- "express": "^4.16.4",
- "express-fileupload": "^1.1.9",
- "express-handlebars": "^6.0.5",
- "express-jwt": "^8.4.0",
- "express-session": "^1.17.1",
- "express-validator": "^6.14.0",
+ "dotenv": "^6.2.0",
+ "express": "^4.18.2",
+ "express-fileupload": "^1.4.0",
+ "express-handlebars": "^6.0.7",
+ "express-session": "^1.17.3",
+ "express-validator": "^6.15.0",
"generate-rsa-keypair": "^0.2.1",
- "greenlock": "^2.8.8",
- "greenlock-express": "^2.7.18",
"ical": "^0.6.0",
- "ical-generator": "^1.11.0",
- "jimp": "^0.16.1",
- "jsonwebtoken": "^9.0.0",
- "marked": "^4.0.10",
- "moment-timezone": "^0.5.31",
- "mongoose": "^5.9.18",
- "multer": "^1.4.5-lts.1",
- "nanoid": "^3.1.9",
+ "ical-generator": "^1.15.4",
+ "jimp": "^0.16.13",
+ "marked": "^4.3.0",
+ "moment-timezone": "^0.5.43",
+ "mongoose": "^5.13.17",
+ "nanoid": "^3.3.6",
"niceware": "^3.0.0",
- "node-schedule": "^1.3.1",
- "nodemailer": "^6.4.8",
- "randomstring": "^1.1.5",
+ "node-schedule": "^1.3.3",
+ "nodemailer": "^6.9.2",
+ "randomstring": "^1.2.3",
"request": "^2.88.2",
- "sanitize-html": "^2.6.1"
+ "sanitize-html": "^2.10.0"
},
"devDependencies": {
- "eslint": "^8.4.1",
- "nodemon": "^2.0.15"
+ "eslint": "^8.40.0",
+ "nodemon": "^2.0.22",
+ "prettier": "^2.8.8",
+ "typescript": "^5.0.4"
}
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
new file mode 100644
index 0000000..33b638a
--- /dev/null
+++ b/pnpm-lock.yaml
@@ -0,0 +1,2916 @@
+lockfileVersion: '6.0'
+
+dependencies:
+ '@sendgrid/mail':
+ specifier: ^6.5.5
+ version: 6.5.5
+ body-parser:
+ specifier: ^1.20.2
+ version: 1.20.2
+ cors:
+ specifier: ^2.8.5
+ version: 2.8.5
+ dotenv:
+ specifier: ^6.2.0
+ version: 6.2.0
+ express:
+ specifier: ^4.18.2
+ version: 4.18.2
+ express-fileupload:
+ specifier: ^1.4.0
+ version: 1.4.0
+ express-handlebars:
+ specifier: ^6.0.7
+ version: 6.0.7
+ express-session:
+ specifier: ^1.17.3
+ version: 1.17.3
+ express-validator:
+ specifier: ^6.15.0
+ version: 6.15.0
+ generate-rsa-keypair:
+ specifier: ^0.2.1
+ version: 0.2.1
+ ical:
+ specifier: ^0.6.0
+ version: 0.6.0
+ ical-generator:
+ specifier: ^1.15.4
+ version: 1.15.4
+ jimp:
+ specifier: ^0.16.13
+ version: 0.16.13
+ marked:
+ specifier: ^4.3.0
+ version: 4.3.0
+ moment-timezone:
+ specifier: ^0.5.43
+ version: 0.5.43
+ mongoose:
+ specifier: ^5.13.17
+ version: 5.13.17
+ nanoid:
+ specifier: ^3.3.6
+ version: 3.3.6
+ niceware:
+ specifier: ^3.0.0
+ version: 3.0.0
+ node-schedule:
+ specifier: ^1.3.3
+ version: 1.3.3
+ nodemailer:
+ specifier: ^6.9.2
+ version: 6.9.2
+ randomstring:
+ specifier: ^1.2.3
+ version: 1.2.3
+ request:
+ specifier: ^2.88.2
+ version: 2.88.2
+ sanitize-html:
+ specifier: ^2.10.0
+ version: 2.10.0
+
+devDependencies:
+ eslint:
+ specifier: ^8.40.0
+ version: 8.40.0
+ nodemon:
+ specifier: ^2.0.22
+ version: 2.0.22
+ prettier:
+ specifier: ^2.8.8
+ version: 2.8.8
+ typescript:
+ specifier: ^5.0.4
+ version: 5.0.4
+
+packages:
+
+ /@babel/runtime@7.21.5:
+ resolution: {integrity: sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ regenerator-runtime: 0.13.11
+ dev: false
+
+ /@eslint-community/eslint-utils@4.4.0(eslint@8.40.0):
+ resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+ dependencies:
+ eslint: 8.40.0
+ eslint-visitor-keys: 3.4.1
+ dev: true
+
+ /@eslint-community/regexpp@4.5.1:
+ resolution: {integrity: sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==}
+ engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+ dev: true
+
+ /@eslint/eslintrc@2.0.3:
+ resolution: {integrity: sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dependencies:
+ ajv: 6.12.6
+ debug: 4.3.4
+ espree: 9.5.2
+ globals: 13.20.0
+ ignore: 5.2.4
+ import-fresh: 3.3.0
+ js-yaml: 4.1.0
+ minimatch: 3.1.2
+ strip-json-comments: 3.1.1
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@eslint/js@8.40.0:
+ resolution: {integrity: sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dev: true
+
+ /@humanwhocodes/config-array@0.11.8:
+ resolution: {integrity: sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==}
+ engines: {node: '>=10.10.0'}
+ dependencies:
+ '@humanwhocodes/object-schema': 1.2.1
+ debug: 4.3.4
+ minimatch: 3.1.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@humanwhocodes/module-importer@1.0.1:
+ resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
+ engines: {node: '>=12.22'}
+ dev: true
+
+ /@humanwhocodes/object-schema@1.2.1:
+ resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
+ dev: true
+
+ /@jimp/bmp@0.16.13(@jimp/custom@0.16.13):
+ resolution: {integrity: sha512-9edAxu7N2FX7vzkdl5Jo1BbACfycUtBQX+XBMcHA2bk62P8R0otgkHg798frgAk/WxQIzwxqOH6wMiCwrlAzdQ==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/utils': 0.16.13
+ bmp-js: 0.1.0
+ dev: false
+
+ /@jimp/core@0.16.13:
+ resolution: {integrity: sha512-qXpA1tzTnlkTku9yqtuRtS/wVntvE6f3m3GNxdTdtmc+O+Wcg9Xo2ABPMh7Nc0AHbMKzwvwgB2JnjZmlmJEObg==}
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/utils': 0.16.13
+ any-base: 1.1.0
+ buffer: 5.7.1
+ exif-parser: 0.1.12
+ file-type: 16.5.4
+ load-bmfont: 1.4.1
+ mkdirp: 0.5.6
+ phin: 2.9.3
+ pixelmatch: 4.0.2
+ tinycolor2: 1.6.0
+ dev: false
+
+ /@jimp/custom@0.16.13:
+ resolution: {integrity: sha512-LTATglVUPGkPf15zX1wTMlZ0+AU7cGEGF6ekVF1crA8eHUWsGjrYTB+Ht4E3HTrCok8weQG+K01rJndCp/l4XA==}
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/core': 0.16.13
+ dev: false
+
+ /@jimp/gif@0.16.13(@jimp/custom@0.16.13):
+ resolution: {integrity: sha512-yFAMZGv3o+YcjXilMWWwS/bv1iSqykFahFMSO169uVMtfQVfa90kt4/kDwrXNR6Q9i6VHpFiGZMlF2UnHClBvg==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/utils': 0.16.13
+ gifwrap: 0.9.4
+ omggif: 1.0.10
+ dev: false
+
+ /@jimp/jpeg@0.16.13(@jimp/custom@0.16.13):
+ resolution: {integrity: sha512-BJHlDxzTlCqP2ThqP8J0eDrbBfod7npWCbJAcfkKqdQuFk0zBPaZ6KKaQKyKxmWJ87Z6ohANZoMKEbtvrwz1AA==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/utils': 0.16.13
+ jpeg-js: 0.4.4
+ dev: false
+
+ /@jimp/plugin-blit@0.16.13(@jimp/custom@0.16.13):
+ resolution: {integrity: sha512-8Z1k96ZFxlhK2bgrY1JNWNwvaBeI/bciLM0yDOni2+aZwfIIiC7Y6PeWHTAvjHNjphz+XCt01WQmOYWCn0ML6g==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/utils': 0.16.13
+ dev: false
+
+ /@jimp/plugin-blur@0.16.13(@jimp/custom@0.16.13):
+ resolution: {integrity: sha512-PvLrfa8vkej3qinlebyhLpksJgCF5aiysDMSVhOZqwH5nQLLtDE9WYbnsofGw4r0VVpyw3H/ANCIzYTyCtP9Cg==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/utils': 0.16.13
+ dev: false
+
+ /@jimp/plugin-circle@0.16.13(@jimp/custom@0.16.13):
+ resolution: {integrity: sha512-RNave7EFgZrb5V5EpdvJGAEHMnDAJuwv05hKscNfIYxf0kR3KhViBTDy+MoTnMlIvaKFULfwIgaZWzyhuINMzA==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/utils': 0.16.13
+ dev: false
+
+ /@jimp/plugin-color@0.16.13(@jimp/custom@0.16.13):
+ resolution: {integrity: sha512-xW+9BtEvoIkkH/Wde9ql4nAFbYLkVINhpgAE7VcBUsuuB34WUbcBl/taOuUYQrPEFQJ4jfXiAJZ2H/rvKjCVnQ==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/utils': 0.16.13
+ tinycolor2: 1.6.0
+ dev: false
+
+ /@jimp/plugin-contain@0.16.13(@jimp/custom@0.16.13)(@jimp/plugin-blit@0.16.13)(@jimp/plugin-resize@0.16.13)(@jimp/plugin-scale@0.16.13):
+ resolution: {integrity: sha512-QayTXw4tXMwU6q6acNTQrTTFTXpNRBe+MgTGMDU0lk+23PjlFCO/9sacflelG8lsp7vNHhAxFeHptDMAksEYzg==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ '@jimp/plugin-blit': '>=0.3.5'
+ '@jimp/plugin-resize': '>=0.3.5'
+ '@jimp/plugin-scale': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/plugin-blit': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/plugin-resize': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/plugin-scale': 0.16.13(@jimp/custom@0.16.13)(@jimp/plugin-resize@0.16.13)
+ '@jimp/utils': 0.16.13
+ dev: false
+
+ /@jimp/plugin-cover@0.16.13(@jimp/custom@0.16.13)(@jimp/plugin-crop@0.16.13)(@jimp/plugin-resize@0.16.13)(@jimp/plugin-scale@0.16.13):
+ resolution: {integrity: sha512-BSsP71GTNaqWRcvkbWuIVH+zK7b3TSNebbhDkFK0fVaUTzHuKMS/mgY4hDZIEVt7Rf5FjadAYtsujHN9w0iSYA==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ '@jimp/plugin-crop': '>=0.3.5'
+ '@jimp/plugin-resize': '>=0.3.5'
+ '@jimp/plugin-scale': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/plugin-crop': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/plugin-resize': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/plugin-scale': 0.16.13(@jimp/custom@0.16.13)(@jimp/plugin-resize@0.16.13)
+ '@jimp/utils': 0.16.13
+ dev: false
+
+ /@jimp/plugin-crop@0.16.13(@jimp/custom@0.16.13):
+ resolution: {integrity: sha512-WEl2tPVYwzYL8OKme6Go2xqiWgKsgxlMwyHabdAU4tXaRwOCnOI7v4021gCcBb9zn/oWwguHuKHmK30Fw2Z/PA==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/utils': 0.16.13
+ dev: false
+
+ /@jimp/plugin-displace@0.16.13(@jimp/custom@0.16.13):
+ resolution: {integrity: sha512-qt9WKq8vWrcjySa9DyQ0x/RBMHQeiVjdVSY1SJsMjssPUf0pS74qorcuAkGi89biN3YoGUgPkpqECnAWnYwgGA==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/utils': 0.16.13
+ dev: false
+
+ /@jimp/plugin-dither@0.16.13(@jimp/custom@0.16.13):
+ resolution: {integrity: sha512-5/N3yJggbWQTlGZHQYJPmQXEwR52qaXjEzkp1yRBbtdaekXE3BG/suo0fqeoV/csf8ooI78sJzYmIrxNoWVtgQ==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/utils': 0.16.13
+ dev: false
+
+ /@jimp/plugin-fisheye@0.16.13(@jimp/custom@0.16.13):
+ resolution: {integrity: sha512-2rZmTdFbT/cF9lEZIkXCYO0TsT114Q27AX5IAo0Sju6jVQbvIk1dFUTnwLDadTo8wkJlFzGqMQ24Cs8cHWOliA==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/utils': 0.16.13
+ dev: false
+
+ /@jimp/plugin-flip@0.16.13(@jimp/custom@0.16.13)(@jimp/plugin-rotate@0.16.13):
+ resolution: {integrity: sha512-EmcgAA74FTc5u7Z+hUO/sRjWwfPPLuOQP5O64x5g4j0T12Bd29IgsYZxoutZo/rb3579+JNa/3wsSEmyVv1EpA==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ '@jimp/plugin-rotate': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/plugin-rotate': 0.16.13(@jimp/custom@0.16.13)(@jimp/plugin-blit@0.16.13)(@jimp/plugin-crop@0.16.13)(@jimp/plugin-resize@0.16.13)
+ '@jimp/utils': 0.16.13
+ dev: false
+
+ /@jimp/plugin-gaussian@0.16.13(@jimp/custom@0.16.13):
+ resolution: {integrity: sha512-A1XKfGQD0iDdIiKqFYi8nZMv4dDVYdxbrmgR7y/CzUHhSYdcmoljLIIsZZM3Iks/Wa353W3vtvkWLuDbQbch1w==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/utils': 0.16.13
+ dev: false
+
+ /@jimp/plugin-invert@0.16.13(@jimp/custom@0.16.13):
+ resolution: {integrity: sha512-xFMrIn7czEZbdbMzZWuaZFnlLGJDVJ82y5vlsKsXRTG2kcxRsMPXvZRWHV57nSs1YFsNqXSbrC8B98n0E32njQ==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/utils': 0.16.13
+ dev: false
+
+ /@jimp/plugin-mask@0.16.13(@jimp/custom@0.16.13):
+ resolution: {integrity: sha512-wLRYKVBXql2GAYgt6FkTnCfE+q5NomM7Dlh0oIPGAoMBWDyTx0eYutRK6PlUrRK2yMHuroAJCglICTbxqGzowQ==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/utils': 0.16.13
+ dev: false
+
+ /@jimp/plugin-normalize@0.16.13(@jimp/custom@0.16.13):
+ resolution: {integrity: sha512-3tfad0n9soRna4IfW9NzQdQ2Z3ijkmo21DREHbE6CGcMIxOSvfRdSvf1qQPApxjTSo8LTU4MCi/fidx/NZ0GqQ==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/utils': 0.16.13
+ dev: false
+
+ /@jimp/plugin-print@0.16.13(@jimp/custom@0.16.13)(@jimp/plugin-blit@0.16.13):
+ resolution: {integrity: sha512-0m6i3p01PGRkGAK9r53hDYrkyMq+tlhLOIbsSTmZyh6HLshUKlTB7eXskF5OpVd5ZUHoltlNc6R+ggvKIzxRFw==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ '@jimp/plugin-blit': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/plugin-blit': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/utils': 0.16.13
+ load-bmfont: 1.4.1
+ dev: false
+
+ /@jimp/plugin-resize@0.16.13(@jimp/custom@0.16.13):
+ resolution: {integrity: sha512-qoqtN8LDknm3fJm9nuPygJv30O3vGhSBD2TxrsCnhtOsxKAqVPJtFVdGd/qVuZ8nqQANQmTlfqTiK9mVWQ7MiQ==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/utils': 0.16.13
+ dev: false
+
+ /@jimp/plugin-rotate@0.16.13(@jimp/custom@0.16.13)(@jimp/plugin-blit@0.16.13)(@jimp/plugin-crop@0.16.13)(@jimp/plugin-resize@0.16.13):
+ resolution: {integrity: sha512-Ev+Jjmj1nHYw897z9C3R9dYsPv7S2/nxdgfFb/h8hOwK0Ovd1k/+yYS46A0uj/JCKK0pQk8wOslYBkPwdnLorw==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ '@jimp/plugin-blit': '>=0.3.5'
+ '@jimp/plugin-crop': '>=0.3.5'
+ '@jimp/plugin-resize': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/plugin-blit': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/plugin-crop': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/plugin-resize': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/utils': 0.16.13
+ dev: false
+
+ /@jimp/plugin-scale@0.16.13(@jimp/custom@0.16.13)(@jimp/plugin-resize@0.16.13):
+ resolution: {integrity: sha512-05POQaEJVucjTiSGMoH68ZiELc7QqpIpuQlZ2JBbhCV+WCbPFUBcGSmE7w4Jd0E2GvCho/NoMODLwgcVGQA97A==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ '@jimp/plugin-resize': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/plugin-resize': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/utils': 0.16.13
+ dev: false
+
+ /@jimp/plugin-shadow@0.16.13(@jimp/custom@0.16.13)(@jimp/plugin-blur@0.16.13)(@jimp/plugin-resize@0.16.13):
+ resolution: {integrity: sha512-nmu5VSZ9hsB1JchTKhnnCY+paRBnwzSyK5fhkhtQHHoFD5ArBQ/5wU8y6tCr7k/GQhhGq1OrixsECeMjPoc8Zw==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ '@jimp/plugin-blur': '>=0.3.5'
+ '@jimp/plugin-resize': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/plugin-blur': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/plugin-resize': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/utils': 0.16.13
+ dev: false
+
+ /@jimp/plugin-threshold@0.16.13(@jimp/custom@0.16.13)(@jimp/plugin-color@0.16.13)(@jimp/plugin-resize@0.16.13):
+ resolution: {integrity: sha512-+3zArBH0OE3Rhjm4HyAokMsZlIq5gpQec33CncyoSwxtRBM2WAhUVmCUKuBo+Lr/2/4ISoY4BWpHKhMLDix6cA==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ '@jimp/plugin-color': '>=0.8.0'
+ '@jimp/plugin-resize': '>=0.8.0'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/plugin-color': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/plugin-resize': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/utils': 0.16.13
+ dev: false
+
+ /@jimp/plugins@0.16.13(@jimp/custom@0.16.13):
+ resolution: {integrity: sha512-CJLdqODEhEVs4MgWCxpWL5l95sCBlkuSLz65cxEm56X5akIsn4LOlwnKoSEZioYcZUBvHhCheH67AyPTudfnQQ==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/plugin-blit': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/plugin-blur': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/plugin-circle': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/plugin-color': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/plugin-contain': 0.16.13(@jimp/custom@0.16.13)(@jimp/plugin-blit@0.16.13)(@jimp/plugin-resize@0.16.13)(@jimp/plugin-scale@0.16.13)
+ '@jimp/plugin-cover': 0.16.13(@jimp/custom@0.16.13)(@jimp/plugin-crop@0.16.13)(@jimp/plugin-resize@0.16.13)(@jimp/plugin-scale@0.16.13)
+ '@jimp/plugin-crop': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/plugin-displace': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/plugin-dither': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/plugin-fisheye': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/plugin-flip': 0.16.13(@jimp/custom@0.16.13)(@jimp/plugin-rotate@0.16.13)
+ '@jimp/plugin-gaussian': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/plugin-invert': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/plugin-mask': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/plugin-normalize': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/plugin-print': 0.16.13(@jimp/custom@0.16.13)(@jimp/plugin-blit@0.16.13)
+ '@jimp/plugin-resize': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/plugin-rotate': 0.16.13(@jimp/custom@0.16.13)(@jimp/plugin-blit@0.16.13)(@jimp/plugin-crop@0.16.13)(@jimp/plugin-resize@0.16.13)
+ '@jimp/plugin-scale': 0.16.13(@jimp/custom@0.16.13)(@jimp/plugin-resize@0.16.13)
+ '@jimp/plugin-shadow': 0.16.13(@jimp/custom@0.16.13)(@jimp/plugin-blur@0.16.13)(@jimp/plugin-resize@0.16.13)
+ '@jimp/plugin-threshold': 0.16.13(@jimp/custom@0.16.13)(@jimp/plugin-color@0.16.13)(@jimp/plugin-resize@0.16.13)
+ timm: 1.7.1
+ dev: false
+
+ /@jimp/png@0.16.13(@jimp/custom@0.16.13):
+ resolution: {integrity: sha512-8cGqINvbWJf1G0Her9zbq9I80roEX0A+U45xFby3tDWfzn+Zz8XKDF1Nv9VUwVx0N3zpcG1RPs9hfheG4Cq2kg==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/utils': 0.16.13
+ pngjs: 3.4.0
+ dev: false
+
+ /@jimp/tiff@0.16.13(@jimp/custom@0.16.13):
+ resolution: {integrity: sha512-oJY8d9u95SwW00VPHuCNxPap6Q1+E/xM5QThb9Hu+P6EGuu6lIeLaNBMmFZyblwFbwrH+WBOZlvIzDhi4Dm/6Q==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ utif: 2.0.1
+ dev: false
+
+ /@jimp/types@0.16.13(@jimp/custom@0.16.13):
+ resolution: {integrity: sha512-mC0yVNUobFDjoYLg4hoUwzMKgNlxynzwt3cDXzumGvRJ7Kb8qQGOWJQjQFo5OxmGExqzPphkirdbBF88RVLBCg==}
+ peerDependencies:
+ '@jimp/custom': '>=0.3.5'
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/bmp': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/custom': 0.16.13
+ '@jimp/gif': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/jpeg': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/png': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/tiff': 0.16.13(@jimp/custom@0.16.13)
+ timm: 1.7.1
+ dev: false
+
+ /@jimp/utils@0.16.13:
+ resolution: {integrity: sha512-VyCpkZzFTHXtKgVO35iKN0sYR10psGpV6SkcSeV4oF7eSYlR8Bl6aQLCzVeFjvESF7mxTmIiI3/XrMobVrtxDA==}
+ dependencies:
+ '@babel/runtime': 7.21.5
+ regenerator-runtime: 0.13.11
+ dev: false
+
+ /@nodelib/fs.scandir@2.1.5:
+ resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
+ engines: {node: '>= 8'}
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ run-parallel: 1.2.0
+ dev: true
+
+ /@nodelib/fs.stat@2.0.5:
+ resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
+ engines: {node: '>= 8'}
+ dev: true
+
+ /@nodelib/fs.walk@1.2.8:
+ resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
+ engines: {node: '>= 8'}
+ dependencies:
+ '@nodelib/fs.scandir': 2.1.5
+ fastq: 1.15.0
+ dev: true
+
+ /@sendgrid/client@6.5.5:
+ resolution: {integrity: sha512-Nbfgo94gbWSL8PIgJfuHoifyOJJepvV8NQkkglctAEfb1hyozKhrzE6v1kPG/z4j0RodaTtXD5LJj/t0q/VhLA==}
+ engines: {node: '>=6.0.0'}
+ dependencies:
+ '@sendgrid/helpers': 6.5.5
+ '@types/request': 2.48.8
+ request: 2.88.2
+ dev: false
+
+ /@sendgrid/helpers@6.5.5:
+ resolution: {integrity: sha512-uRFEanalfss5hDsuzVXZ1wm7i7eEXHh1py80piOXjobiQ+MxmtR19EU+gDSXZ+uMcEehBGhxnb7QDNN0q65qig==}
+ engines: {node: '>= 6.0.0'}
+ dependencies:
+ chalk: 2.4.2
+ deepmerge: 4.3.1
+ dev: false
+
+ /@sendgrid/mail@6.5.5:
+ resolution: {integrity: sha512-DSu8oTPI0BJFH60jMOG9gM+oeNMoRALFmdAYg2PIXpL+Zbxd7L2GzQZtmf1jLy/8UBImkbB3D74TjiOBiLRK1w==}
+ engines: {node: '>=6.0.0'}
+ dependencies:
+ '@sendgrid/client': 6.5.5
+ '@sendgrid/helpers': 6.5.5
+ dev: false
+
+ /@tokenizer/token@0.3.0:
+ resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==}
+ dev: false
+
+ /@types/bson@4.0.5:
+ resolution: {integrity: sha512-vVLwMUqhYJSQ/WKcE60eFqcyuWse5fGH+NMAXHuKrUAPoryq3ATxk5o4bgYNtg5aOM4APVg7Hnb3ASqUYG0PKg==}
+ dependencies:
+ '@types/node': 20.1.3
+ dev: false
+
+ /@types/caseless@0.12.2:
+ resolution: {integrity: sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==}
+ dev: false
+
+ /@types/mongodb@3.6.20:
+ resolution: {integrity: sha512-WcdpPJCakFzcWWD9juKoZbRtQxKIMYF/JIAM4JrNHrMcnJL6/a2NWjXxW7fo9hxboxxkg+icff8d7+WIEvKgYQ==}
+ dependencies:
+ '@types/bson': 4.0.5
+ '@types/node': 20.1.3
+ dev: false
+
+ /@types/node@16.9.1:
+ resolution: {integrity: sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==}
+ dev: false
+
+ /@types/node@20.1.3:
+ resolution: {integrity: sha512-NP2yfZpgmf2eDRPmgGq+fjGjSwFgYbihA8/gK+ey23qT9RkxsgNTZvGOEpXgzIGqesTYkElELLgtKoMQTys5vA==}
+ dev: false
+
+ /@types/request@2.48.8:
+ resolution: {integrity: sha512-whjk1EDJPcAR2kYHRbFl/lKeeKYTi05A15K9bnLInCVroNDCtXce57xKdI0/rQaA3K+6q0eFyUBPmqfSndUZdQ==}
+ dependencies:
+ '@types/caseless': 0.12.2
+ '@types/node': 20.1.3
+ '@types/tough-cookie': 4.0.2
+ form-data: 2.5.1
+ dev: false
+
+ /@types/tough-cookie@4.0.2:
+ resolution: {integrity: sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==}
+ dev: false
+
+ /abbrev@1.1.1:
+ resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
+ dev: true
+
+ /accepts@1.3.8:
+ resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
+ engines: {node: '>= 0.6'}
+ dependencies:
+ mime-types: 2.1.35
+ negotiator: 0.6.3
+ dev: false
+
+ /acorn-jsx@5.3.2(acorn@8.8.2):
+ resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
+ peerDependencies:
+ acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+ dependencies:
+ acorn: 8.8.2
+ dev: true
+
+ /acorn@8.8.2:
+ resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+ dev: true
+
+ /ajv@6.12.6:
+ resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
+ dependencies:
+ fast-deep-equal: 3.1.3
+ fast-json-stable-stringify: 2.1.0
+ json-schema-traverse: 0.4.1
+ uri-js: 4.4.1
+
+ /ansi-regex@5.0.1:
+ resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /ansi-styles@3.2.1:
+ resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
+ engines: {node: '>=4'}
+ dependencies:
+ color-convert: 1.9.3
+ dev: false
+
+ /ansi-styles@4.3.0:
+ resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+ engines: {node: '>=8'}
+ dependencies:
+ color-convert: 2.0.1
+ dev: true
+
+ /any-base@1.1.0:
+ resolution: {integrity: sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg==}
+ dev: false
+
+ /anymatch@3.1.3:
+ resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
+ engines: {node: '>= 8'}
+ dependencies:
+ normalize-path: 3.0.0
+ picomatch: 2.3.1
+ dev: true
+
+ /argparse@2.0.1:
+ resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+ dev: true
+
+ /array-flatten@1.1.1:
+ resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==}
+ dev: false
+
+ /array-uniq@1.0.2:
+ resolution: {integrity: sha512-GVYjmpL05al4dNlKJm53mKE4w9OOLiuVHWorsIA3YVz+Hu0hcn6PtE3Ydl0EqU7v+7ABC4mjjWsnLUxbpno+CA==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
+ /asn1@0.2.6:
+ resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==}
+ dependencies:
+ safer-buffer: 2.1.2
+ dev: false
+
+ /assert-plus@1.0.0:
+ resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==}
+ engines: {node: '>=0.8'}
+ dev: false
+
+ /asynckit@0.4.0:
+ resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
+ dev: false
+
+ /aws-sign2@0.7.0:
+ resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==}
+ dev: false
+
+ /aws4@1.12.0:
+ resolution: {integrity: sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==}
+ dev: false
+
+ /balanced-match@1.0.2:
+ resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+
+ /base64-js@1.5.1:
+ resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
+ dev: false
+
+ /bcrypt-pbkdf@1.0.2:
+ resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==}
+ dependencies:
+ tweetnacl: 0.14.5
+ dev: false
+
+ /binary-extensions@2.2.0:
+ resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /binary-search@1.3.6:
+ resolution: {integrity: sha512-nbE1WxOTTrUWIfsfZ4aHGYu5DOuNkbxGokjV6Z2kxfJK3uaAb8zNK1muzOeipoLHZjInT4Br88BHpzevc681xA==}
+ dev: false
+
+ /bl@2.2.1:
+ resolution: {integrity: sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==}
+ dependencies:
+ readable-stream: 2.3.8
+ safe-buffer: 5.2.1
+ dev: false
+
+ /bluebird@3.5.1:
+ resolution: {integrity: sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==}
+ dev: false
+
+ /bmp-js@0.1.0:
+ resolution: {integrity: sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==}
+ dev: false
+
+ /body-parser@1.20.1:
+ resolution: {integrity: sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==}
+ engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+ dependencies:
+ bytes: 3.1.2
+ content-type: 1.0.5
+ debug: 2.6.9
+ depd: 2.0.0
+ destroy: 1.2.0
+ http-errors: 2.0.0
+ iconv-lite: 0.4.24
+ on-finished: 2.4.1
+ qs: 6.11.0
+ raw-body: 2.5.1
+ type-is: 1.6.18
+ unpipe: 1.0.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /body-parser@1.20.2:
+ resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==}
+ engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+ dependencies:
+ bytes: 3.1.2
+ content-type: 1.0.5
+ debug: 2.6.9
+ depd: 2.0.0
+ destroy: 1.2.0
+ http-errors: 2.0.0
+ iconv-lite: 0.4.24
+ on-finished: 2.4.1
+ qs: 6.11.0
+ raw-body: 2.5.2
+ type-is: 1.6.18
+ unpipe: 1.0.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /brace-expansion@1.1.11:
+ resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
+ dependencies:
+ balanced-match: 1.0.2
+ concat-map: 0.0.1
+ dev: true
+
+ /brace-expansion@2.0.1:
+ resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
+ dependencies:
+ balanced-match: 1.0.2
+ dev: false
+
+ /braces@3.0.2:
+ resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
+ engines: {node: '>=8'}
+ dependencies:
+ fill-range: 7.0.1
+ dev: true
+
+ /bson@1.1.6:
+ resolution: {integrity: sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==}
+ engines: {node: '>=0.6.19'}
+ dev: false
+
+ /buffer-equal@0.0.1:
+ resolution: {integrity: sha512-RgSV6InVQ9ODPdLWJ5UAqBqJBOg370Nz6ZQtRzpt6nUjc8v0St97uJ4PYC6NztqIScrAXafKM3mZPMygSe1ggA==}
+ engines: {node: '>=0.4.0'}
+ dev: false
+
+ /buffer@5.7.1:
+ resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
+ dependencies:
+ base64-js: 1.5.1
+ ieee754: 1.2.1
+ dev: false
+
+ /busboy@1.6.0:
+ resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
+ engines: {node: '>=10.16.0'}
+ dependencies:
+ streamsearch: 1.1.0
+ dev: false
+
+ /bytes@3.1.2:
+ resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
+ engines: {node: '>= 0.8'}
+ dev: false
+
+ /call-bind@1.0.2:
+ resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==}
+ dependencies:
+ function-bind: 1.1.1
+ get-intrinsic: 1.2.0
+ dev: false
+
+ /callsites@3.1.0:
+ resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /caseless@0.12.0:
+ resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==}
+ dev: false
+
+ /chalk@2.4.2:
+ resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
+ engines: {node: '>=4'}
+ dependencies:
+ ansi-styles: 3.2.1
+ escape-string-regexp: 1.0.5
+ supports-color: 5.5.0
+ dev: false
+
+ /chalk@4.1.2:
+ resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+ engines: {node: '>=10'}
+ dependencies:
+ ansi-styles: 4.3.0
+ supports-color: 7.2.0
+ dev: true
+
+ /chokidar@3.5.3:
+ resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
+ engines: {node: '>= 8.10.0'}
+ dependencies:
+ anymatch: 3.1.3
+ braces: 3.0.2
+ glob-parent: 5.1.2
+ is-binary-path: 2.1.0
+ is-glob: 4.0.3
+ normalize-path: 3.0.0
+ readdirp: 3.6.0
+ optionalDependencies:
+ fsevents: 2.3.2
+ dev: true
+
+ /color-convert@1.9.3:
+ resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
+ dependencies:
+ color-name: 1.1.3
+ dev: false
+
+ /color-convert@2.0.1:
+ resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+ engines: {node: '>=7.0.0'}
+ dependencies:
+ color-name: 1.1.4
+ dev: true
+
+ /color-name@1.1.3:
+ resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
+ dev: false
+
+ /color-name@1.1.4:
+ resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+ dev: true
+
+ /combined-stream@1.0.8:
+ resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ delayed-stream: 1.0.0
+ dev: false
+
+ /concat-map@0.0.1:
+ resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+ dev: true
+
+ /content-disposition@0.5.4:
+ resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
+ engines: {node: '>= 0.6'}
+ dependencies:
+ safe-buffer: 5.2.1
+ dev: false
+
+ /content-type@1.0.5:
+ resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /cookie-signature@1.0.6:
+ resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
+ dev: false
+
+ /cookie@0.4.2:
+ resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /cookie@0.5.0:
+ resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /core-util-is@1.0.2:
+ resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==}
+ dev: false
+
+ /core-util-is@1.0.3:
+ resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
+ dev: false
+
+ /cors@2.8.5:
+ resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
+ engines: {node: '>= 0.10'}
+ dependencies:
+ object-assign: 4.1.1
+ vary: 1.1.2
+ dev: false
+
+ /cron-parser@2.18.0:
+ resolution: {integrity: sha512-s4odpheTyydAbTBQepsqd2rNWGa2iV3cyo8g7zbI2QQYGLVsfbhmwukayS1XHppe02Oy1fg7mg6xoaraVJeEcg==}
+ engines: {node: '>=0.8'}
+ dependencies:
+ is-nan: 1.3.2
+ moment-timezone: 0.5.43
+ dev: false
+
+ /cross-spawn@7.0.3:
+ resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
+ engines: {node: '>= 8'}
+ dependencies:
+ path-key: 3.1.1
+ shebang-command: 2.0.0
+ which: 2.0.2
+ dev: true
+
+ /dashdash@1.14.1:
+ resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==}
+ engines: {node: '>=0.10'}
+ dependencies:
+ assert-plus: 1.0.0
+ dev: false
+
+ /debug@2.6.9:
+ resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+ dependencies:
+ ms: 2.0.0
+ dev: false
+
+ /debug@3.1.0:
+ resolution: {integrity: sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+ dependencies:
+ ms: 2.0.0
+ dev: false
+
+ /debug@3.2.7(supports-color@5.5.0):
+ resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+ dependencies:
+ ms: 2.1.3
+ supports-color: 5.5.0
+ dev: true
+
+ /debug@4.3.4:
+ resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+ dependencies:
+ ms: 2.1.2
+ dev: true
+
+ /deep-is@0.1.4:
+ resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
+ dev: true
+
+ /deepmerge@4.3.1:
+ resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
+ /define-properties@1.2.0:
+ resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ has-property-descriptors: 1.0.0
+ object-keys: 1.1.1
+ dev: false
+
+ /delayed-stream@1.0.0:
+ resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
+ engines: {node: '>=0.4.0'}
+ dev: false
+
+ /denque@1.5.1:
+ resolution: {integrity: sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==}
+ engines: {node: '>=0.10'}
+ dev: false
+
+ /depd@2.0.0:
+ resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
+ engines: {node: '>= 0.8'}
+ dev: false
+
+ /destroy@1.2.0:
+ resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
+ engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+ dev: false
+
+ /doctrine@3.0.0:
+ resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
+ engines: {node: '>=6.0.0'}
+ dependencies:
+ esutils: 2.0.3
+ dev: true
+
+ /dom-serializer@2.0.0:
+ resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
+ dependencies:
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+ entities: 4.5.0
+ dev: false
+
+ /dom-walk@0.1.2:
+ resolution: {integrity: sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==}
+ dev: false
+
+ /domelementtype@2.3.0:
+ resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
+ dev: false
+
+ /domhandler@5.0.3:
+ resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
+ engines: {node: '>= 4'}
+ dependencies:
+ domelementtype: 2.3.0
+ dev: false
+
+ /domutils@3.1.0:
+ resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==}
+ dependencies:
+ dom-serializer: 2.0.0
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+ dev: false
+
+ /dotenv@6.2.0:
+ resolution: {integrity: sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==}
+ engines: {node: '>=6'}
+ dev: false
+
+ /ecc-jsbn@0.1.2:
+ resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==}
+ dependencies:
+ jsbn: 0.1.1
+ safer-buffer: 2.1.2
+ dev: false
+
+ /ee-first@1.1.1:
+ resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
+ dev: false
+
+ /encodeurl@1.0.2:
+ resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
+ engines: {node: '>= 0.8'}
+ dev: false
+
+ /entities@4.5.0:
+ resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
+ engines: {node: '>=0.12'}
+ dev: false
+
+ /escape-html@1.0.3:
+ resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
+ dev: false
+
+ /escape-string-regexp@1.0.5:
+ resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
+ engines: {node: '>=0.8.0'}
+ dev: false
+
+ /escape-string-regexp@4.0.0:
+ resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
+ engines: {node: '>=10'}
+
+ /eslint-scope@7.2.0:
+ resolution: {integrity: sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dependencies:
+ esrecurse: 4.3.0
+ estraverse: 5.3.0
+ dev: true
+
+ /eslint-visitor-keys@3.4.1:
+ resolution: {integrity: sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dev: true
+
+ /eslint@8.40.0:
+ resolution: {integrity: sha512-bvR+TsP9EHL3TqNtj9sCNJVAFK3fBN8Q7g5waghxyRsPLIMwL73XSKnZFK0hk/O2ANC+iAoq6PWMQ+IfBAJIiQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ hasBin: true
+ dependencies:
+ '@eslint-community/eslint-utils': 4.4.0(eslint@8.40.0)
+ '@eslint-community/regexpp': 4.5.1
+ '@eslint/eslintrc': 2.0.3
+ '@eslint/js': 8.40.0
+ '@humanwhocodes/config-array': 0.11.8
+ '@humanwhocodes/module-importer': 1.0.1
+ '@nodelib/fs.walk': 1.2.8
+ ajv: 6.12.6
+ chalk: 4.1.2
+ cross-spawn: 7.0.3
+ debug: 4.3.4
+ doctrine: 3.0.0
+ escape-string-regexp: 4.0.0
+ eslint-scope: 7.2.0
+ eslint-visitor-keys: 3.4.1
+ espree: 9.5.2
+ esquery: 1.5.0
+ esutils: 2.0.3
+ fast-deep-equal: 3.1.3
+ file-entry-cache: 6.0.1
+ find-up: 5.0.0
+ glob-parent: 6.0.2
+ globals: 13.20.0
+ grapheme-splitter: 1.0.4
+ ignore: 5.2.4
+ import-fresh: 3.3.0
+ imurmurhash: 0.1.4
+ is-glob: 4.0.3
+ is-path-inside: 3.0.3
+ js-sdsl: 4.4.0
+ js-yaml: 4.1.0
+ json-stable-stringify-without-jsonify: 1.0.1
+ levn: 0.4.1
+ lodash.merge: 4.6.2
+ minimatch: 3.1.2
+ natural-compare: 1.4.0
+ optionator: 0.9.1
+ strip-ansi: 6.0.1
+ strip-json-comments: 3.1.1
+ text-table: 0.2.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /espree@9.5.2:
+ resolution: {integrity: sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dependencies:
+ acorn: 8.8.2
+ acorn-jsx: 5.3.2(acorn@8.8.2)
+ eslint-visitor-keys: 3.4.1
+ dev: true
+
+ /esquery@1.5.0:
+ resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==}
+ engines: {node: '>=0.10'}
+ dependencies:
+ estraverse: 5.3.0
+ dev: true
+
+ /esrecurse@4.3.0:
+ resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
+ engines: {node: '>=4.0'}
+ dependencies:
+ estraverse: 5.3.0
+ dev: true
+
+ /estraverse@5.3.0:
+ resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
+ engines: {node: '>=4.0'}
+ dev: true
+
+ /esutils@2.0.3:
+ resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /etag@1.8.1:
+ resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /exif-parser@0.1.12:
+ resolution: {integrity: sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw==}
+ dev: false
+
+ /express-fileupload@1.4.0:
+ resolution: {integrity: sha512-RjzLCHxkv3umDeZKeFeMg8w7qe0V09w3B7oGZprr/oO2H/ISCgNzuqzn7gV3HRWb37GjRk429CCpSLS2KNTqMQ==}
+ engines: {node: '>=12.0.0'}
+ dependencies:
+ busboy: 1.6.0
+ dev: false
+
+ /express-handlebars@6.0.7:
+ resolution: {integrity: sha512-iYeMFpc/hMD+E6FNAZA5fgWeXnXr4rslOSPkeEV6TwdmpJ5lEXuWX0u9vFYs31P2MURctQq2batR09oeNj0LIg==}
+ engines: {node: '>=v12.22.9'}
+ dependencies:
+ glob: 8.1.0
+ graceful-fs: 4.2.11
+ handlebars: 4.7.7
+ dev: false
+
+ /express-session@1.17.3:
+ resolution: {integrity: sha512-4+otWXlShYlG1Ma+2Jnn+xgKUZTMJ5QD3YvfilX3AcocOAbIkVylSWEklzALe/+Pu4qV6TYBj5GwOBFfdKqLBw==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ cookie: 0.4.2
+ cookie-signature: 1.0.6
+ debug: 2.6.9
+ depd: 2.0.0
+ on-headers: 1.0.2
+ parseurl: 1.3.3
+ safe-buffer: 5.2.1
+ uid-safe: 2.1.5
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /express-validator@6.15.0:
+ resolution: {integrity: sha512-r05VYoBL3i2pswuehoFSy+uM8NBuVaY7avp5qrYjQBDzagx2Z5A77FZqPT8/gNLF3HopWkIzaTFaC4JysWXLqg==}
+ engines: {node: '>= 8.0.0'}
+ dependencies:
+ lodash: 4.17.21
+ validator: 13.9.0
+ dev: false
+
+ /express@4.18.2:
+ resolution: {integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==}
+ engines: {node: '>= 0.10.0'}
+ dependencies:
+ accepts: 1.3.8
+ array-flatten: 1.1.1
+ body-parser: 1.20.1
+ content-disposition: 0.5.4
+ content-type: 1.0.5
+ cookie: 0.5.0
+ cookie-signature: 1.0.6
+ debug: 2.6.9
+ depd: 2.0.0
+ encodeurl: 1.0.2
+ escape-html: 1.0.3
+ etag: 1.8.1
+ finalhandler: 1.2.0
+ fresh: 0.5.2
+ http-errors: 2.0.0
+ merge-descriptors: 1.0.1
+ methods: 1.1.2
+ on-finished: 2.4.1
+ parseurl: 1.3.3
+ path-to-regexp: 0.1.7
+ proxy-addr: 2.0.7
+ qs: 6.11.0
+ range-parser: 1.2.1
+ safe-buffer: 5.2.1
+ send: 0.18.0
+ serve-static: 1.15.0
+ setprototypeof: 1.2.0
+ statuses: 2.0.1
+ type-is: 1.6.18
+ utils-merge: 1.0.1
+ vary: 1.1.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /extend@3.0.2:
+ resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
+ dev: false
+
+ /extsprintf@1.3.0:
+ resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==}
+ engines: {'0': node >=0.6.0}
+ dev: false
+
+ /fast-deep-equal@3.1.3:
+ resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+
+ /fast-json-stable-stringify@2.1.0:
+ resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+
+ /fast-levenshtein@2.0.6:
+ resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+ dev: true
+
+ /fastq@1.15.0:
+ resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==}
+ dependencies:
+ reusify: 1.0.4
+ dev: true
+
+ /file-entry-cache@6.0.1:
+ resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
+ engines: {node: ^10.12.0 || >=12.0.0}
+ dependencies:
+ flat-cache: 3.0.4
+ dev: true
+
+ /file-type@16.5.4:
+ resolution: {integrity: sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==}
+ engines: {node: '>=10'}
+ dependencies:
+ readable-web-to-node-stream: 3.0.2
+ strtok3: 6.3.0
+ token-types: 4.2.1
+ dev: false
+
+ /fill-range@7.0.1:
+ resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ to-regex-range: 5.0.1
+ dev: true
+
+ /finalhandler@1.2.0:
+ resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ debug: 2.6.9
+ encodeurl: 1.0.2
+ escape-html: 1.0.3
+ on-finished: 2.4.1
+ parseurl: 1.3.3
+ statuses: 2.0.1
+ unpipe: 1.0.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /find-up@5.0.0:
+ resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
+ engines: {node: '>=10'}
+ dependencies:
+ locate-path: 6.0.0
+ path-exists: 4.0.0
+ dev: true
+
+ /flat-cache@3.0.4:
+ resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==}
+ engines: {node: ^10.12.0 || >=12.0.0}
+ dependencies:
+ flatted: 3.2.7
+ rimraf: 3.0.2
+ dev: true
+
+ /flatted@3.2.7:
+ resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==}
+ dev: true
+
+ /forever-agent@0.6.1:
+ resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==}
+ dev: false
+
+ /form-data@2.3.3:
+ resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==}
+ engines: {node: '>= 0.12'}
+ dependencies:
+ asynckit: 0.4.0
+ combined-stream: 1.0.8
+ mime-types: 2.1.35
+ dev: false
+
+ /form-data@2.5.1:
+ resolution: {integrity: sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==}
+ engines: {node: '>= 0.12'}
+ dependencies:
+ asynckit: 0.4.0
+ combined-stream: 1.0.8
+ mime-types: 2.1.35
+ dev: false
+
+ /forwarded@0.2.0:
+ resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /fresh@0.5.2:
+ resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /fs.realpath@1.0.0:
+ resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
+
+ /fsevents@2.3.2:
+ resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /function-bind@1.1.1:
+ resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
+ dev: false
+
+ /generate-rsa-keypair@0.2.1:
+ resolution: {integrity: sha512-vxLfzfy6WbMLtkKV4AJtg7QH0ZqGGNkSYM6S0Q72Z70QXsztLklKFtX15te3YLIqmiQAYi3g3MWsTfXd6djkpg==}
+ engines: {node: '>=8.6.0'}
+ requiresBuild: true
+ dev: false
+
+ /get-intrinsic@1.2.0:
+ resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==}
+ dependencies:
+ function-bind: 1.1.1
+ has: 1.0.3
+ has-symbols: 1.0.3
+ dev: false
+
+ /getpass@0.1.7:
+ resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==}
+ dependencies:
+ assert-plus: 1.0.0
+ dev: false
+
+ /gifwrap@0.9.4:
+ resolution: {integrity: sha512-MDMwbhASQuVeD4JKd1fKgNgCRL3fGqMM4WaqpNhWO0JiMOAjbQdumbs4BbBZEy9/M00EHEjKN3HieVhCUlwjeQ==}
+ dependencies:
+ image-q: 4.0.0
+ omggif: 1.0.10
+ dev: false
+
+ /glob-parent@5.1.2:
+ resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
+ engines: {node: '>= 6'}
+ dependencies:
+ is-glob: 4.0.3
+ dev: true
+
+ /glob-parent@6.0.2:
+ resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
+ engines: {node: '>=10.13.0'}
+ dependencies:
+ is-glob: 4.0.3
+ dev: true
+
+ /glob@7.2.3:
+ resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
+ dependencies:
+ fs.realpath: 1.0.0
+ inflight: 1.0.6
+ inherits: 2.0.4
+ minimatch: 3.1.2
+ once: 1.4.0
+ path-is-absolute: 1.0.1
+ dev: true
+
+ /glob@8.1.0:
+ resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ fs.realpath: 1.0.0
+ inflight: 1.0.6
+ inherits: 2.0.4
+ minimatch: 5.1.6
+ once: 1.4.0
+ dev: false
+
+ /global@4.4.0:
+ resolution: {integrity: sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==}
+ dependencies:
+ min-document: 2.19.0
+ process: 0.11.10
+ dev: false
+
+ /globals@13.20.0:
+ resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ type-fest: 0.20.2
+ dev: true
+
+ /graceful-fs@4.2.11:
+ resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+ dev: false
+
+ /grapheme-splitter@1.0.4:
+ resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==}
+ dev: true
+
+ /handlebars@4.7.7:
+ resolution: {integrity: sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==}
+ engines: {node: '>=0.4.7'}
+ hasBin: true
+ dependencies:
+ minimist: 1.2.8
+ neo-async: 2.6.2
+ source-map: 0.6.1
+ wordwrap: 1.0.0
+ optionalDependencies:
+ uglify-js: 3.17.4
+ dev: false
+
+ /har-schema@2.0.0:
+ resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==}
+ engines: {node: '>=4'}
+ dev: false
+
+ /har-validator@5.1.5:
+ resolution: {integrity: sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==}
+ engines: {node: '>=6'}
+ deprecated: this library is no longer supported
+ dependencies:
+ ajv: 6.12.6
+ har-schema: 2.0.0
+ dev: false
+
+ /has-flag@3.0.0:
+ resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
+ engines: {node: '>=4'}
+
+ /has-flag@4.0.0:
+ resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /has-property-descriptors@1.0.0:
+ resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==}
+ dependencies:
+ get-intrinsic: 1.2.0
+ dev: false
+
+ /has-symbols@1.0.3:
+ resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
+ engines: {node: '>= 0.4'}
+ dev: false
+
+ /has@1.0.3:
+ resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
+ engines: {node: '>= 0.4.0'}
+ dependencies:
+ function-bind: 1.1.1
+ dev: false
+
+ /htmlparser2@8.0.2:
+ resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
+ dependencies:
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+ domutils: 3.1.0
+ entities: 4.5.0
+ dev: false
+
+ /http-errors@2.0.0:
+ resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ depd: 2.0.0
+ inherits: 2.0.4
+ setprototypeof: 1.2.0
+ statuses: 2.0.1
+ toidentifier: 1.0.1
+ dev: false
+
+ /http-signature@1.2.0:
+ resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==}
+ engines: {node: '>=0.8', npm: '>=1.3.7'}
+ dependencies:
+ assert-plus: 1.0.0
+ jsprim: 1.4.2
+ sshpk: 1.17.0
+ dev: false
+
+ /ical-generator@1.15.4:
+ resolution: {integrity: sha512-drXe4RLkfNlvDvdy/E6BUI9p+01L3ySK1ufNEYI9TxNKG9ZA3G60QWoZvD1dtmH4scwDxYu6/sZBPJvYVNrj8A==}
+ engines: {node: '>=6.0.0'}
+ peerDependencies:
+ '@types/node': '>= 8.0.0'
+ dependencies:
+ moment-timezone: 0.5.43
+ dev: false
+
+ /ical@0.6.0:
+ resolution: {integrity: sha512-P7R3uMhFnLY7Tfiz+2uZIninThWIoUM5BVO4f9ZsV36GYqoBkIg6RbkrBhmWCvcuK1vLzljLaNtpWeGM/5ZHRg==}
+ dependencies:
+ request: 2.88.2
+ rrule: 2.4.1
+ dev: false
+
+ /iconv-lite@0.4.24:
+ resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ safer-buffer: 2.1.2
+ dev: false
+
+ /ieee754@1.2.1:
+ resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
+ dev: false
+
+ /ignore-by-default@1.0.1:
+ resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==}
+ dev: true
+
+ /ignore@5.2.4:
+ resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
+ engines: {node: '>= 4'}
+ dev: true
+
+ /image-q@4.0.0:
+ resolution: {integrity: sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw==}
+ dependencies:
+ '@types/node': 16.9.1
+ dev: false
+
+ /import-fresh@3.3.0:
+ resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
+ engines: {node: '>=6'}
+ dependencies:
+ parent-module: 1.0.1
+ resolve-from: 4.0.0
+ dev: true
+
+ /imurmurhash@0.1.4:
+ resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
+ engines: {node: '>=0.8.19'}
+ dev: true
+
+ /inflight@1.0.6:
+ resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
+ dependencies:
+ once: 1.4.0
+ wrappy: 1.0.2
+
+ /inherits@2.0.4:
+ resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+
+ /ipaddr.js@1.9.1:
+ resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
+ engines: {node: '>= 0.10'}
+ dev: false
+
+ /is-binary-path@2.1.0:
+ resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
+ engines: {node: '>=8'}
+ dependencies:
+ binary-extensions: 2.2.0
+ dev: true
+
+ /is-extglob@2.1.1:
+ resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /is-function@1.0.2:
+ resolution: {integrity: sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==}
+ dev: false
+
+ /is-glob@4.0.3:
+ resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-extglob: 2.1.1
+ dev: true
+
+ /is-nan@1.3.2:
+ resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.2.0
+ dev: false
+
+ /is-number@7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+ dev: true
+
+ /is-path-inside@3.0.3:
+ resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /is-plain-object@5.0.0:
+ resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
+ /is-typedarray@1.0.0:
+ resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==}
+ dev: false
+
+ /isarray@1.0.0:
+ resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
+ dev: false
+
+ /isexe@2.0.0:
+ resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+ dev: true
+
+ /isstream@0.1.2:
+ resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==}
+ dev: false
+
+ /jimp@0.16.13:
+ resolution: {integrity: sha512-Bxz8q7V4rnCky9A0ktTNGA9SkNFVWRHodddI/DaAWZJzF7sVUlFYKQ60y9JGqrKpi48ECA/TnfMzzc5C70VByA==}
+ dependencies:
+ '@babel/runtime': 7.21.5
+ '@jimp/custom': 0.16.13
+ '@jimp/plugins': 0.16.13(@jimp/custom@0.16.13)
+ '@jimp/types': 0.16.13(@jimp/custom@0.16.13)
+ regenerator-runtime: 0.13.11
+ dev: false
+
+ /jpeg-js@0.4.4:
+ resolution: {integrity: sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==}
+ dev: false
+
+ /js-sdsl@4.4.0:
+ resolution: {integrity: sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==}
+ dev: true
+
+ /js-yaml@4.1.0:
+ resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
+ hasBin: true
+ dependencies:
+ argparse: 2.0.1
+ dev: true
+
+ /jsbn@0.1.1:
+ resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==}
+ dev: false
+
+ /json-schema-traverse@0.4.1:
+ resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
+
+ /json-schema@0.4.0:
+ resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==}
+ dev: false
+
+ /json-stable-stringify-without-jsonify@1.0.1:
+ resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
+ dev: true
+
+ /json-stringify-safe@5.0.1:
+ resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==}
+ dev: false
+
+ /jsprim@1.4.2:
+ resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==}
+ engines: {node: '>=0.6.0'}
+ dependencies:
+ assert-plus: 1.0.0
+ extsprintf: 1.3.0
+ json-schema: 0.4.0
+ verror: 1.10.0
+ dev: false
+
+ /kareem@2.3.2:
+ resolution: {integrity: sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ==}
+ dev: false
+
+ /levn@0.4.1:
+ resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+ dev: true
+
+ /load-bmfont@1.4.1:
+ resolution: {integrity: sha512-8UyQoYmdRDy81Brz6aLAUhfZLwr5zV0L3taTQ4hju7m6biuwiWiJXjPhBJxbUQJA8PrkvJ/7Enqmwk2sM14soA==}
+ dependencies:
+ buffer-equal: 0.0.1
+ mime: 1.6.0
+ parse-bmfont-ascii: 1.0.6
+ parse-bmfont-binary: 1.0.6
+ parse-bmfont-xml: 1.1.4
+ phin: 2.9.3
+ xhr: 2.6.0
+ xtend: 4.0.2
+ dev: false
+
+ /locate-path@6.0.0:
+ resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
+ engines: {node: '>=10'}
+ dependencies:
+ p-locate: 5.0.0
+ dev: true
+
+ /lodash.merge@4.6.2:
+ resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+ dev: true
+
+ /lodash@4.17.21:
+ resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
+ dev: false
+
+ /long-timeout@0.1.1:
+ resolution: {integrity: sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w==}
+ dev: false
+
+ /luxon@1.28.1:
+ resolution: {integrity: sha512-gYHAa180mKrNIUJCbwpmD0aTu9kV0dREDrwNnuyFAsO1Wt0EVYSZelPnJlbj9HplzXX/YWXHFTL45kvZ53M0pw==}
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /marked@4.3.0:
+ resolution: {integrity: sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==}
+ engines: {node: '>= 12'}
+ hasBin: true
+ dev: false
+
+ /media-typer@0.3.0:
+ resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /memory-pager@1.5.0:
+ resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==}
+ dev: false
+ optional: true
+
+ /merge-descriptors@1.0.1:
+ resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==}
+ dev: false
+
+ /methods@1.1.2:
+ resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /mime-db@1.52.0:
+ resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /mime-types@2.1.35:
+ resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
+ engines: {node: '>= 0.6'}
+ dependencies:
+ mime-db: 1.52.0
+ dev: false
+
+ /mime@1.6.0:
+ resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
+ engines: {node: '>=4'}
+ hasBin: true
+ dev: false
+
+ /min-document@2.19.0:
+ resolution: {integrity: sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==}
+ dependencies:
+ dom-walk: 0.1.2
+ dev: false
+
+ /minimatch@3.1.2:
+ resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
+ dependencies:
+ brace-expansion: 1.1.11
+ dev: true
+
+ /minimatch@5.1.6:
+ resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==}
+ engines: {node: '>=10'}
+ dependencies:
+ brace-expansion: 2.0.1
+ dev: false
+
+ /minimist@1.2.8:
+ resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
+ dev: false
+
+ /mkdirp@0.5.6:
+ resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
+ hasBin: true
+ dependencies:
+ minimist: 1.2.8
+ dev: false
+
+ /moment-timezone@0.5.43:
+ resolution: {integrity: sha512-72j3aNyuIsDxdF1i7CEgV2FfxM1r6aaqJyLB2vwb33mXYyoyLly+F1zbWqhA3/bVIoJ4szlUoMbUnVdid32NUQ==}
+ dependencies:
+ moment: 2.29.4
+ dev: false
+
+ /moment@2.29.4:
+ resolution: {integrity: sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==}
+ dev: false
+
+ /mongodb@3.7.3:
+ resolution: {integrity: sha512-Psm+g3/wHXhjBEktkxXsFMZvd3nemI0r3IPsE0bU+4//PnvNWKkzhZcEsbPcYiWqe8XqXJJEg4Tgtr7Raw67Yw==}
+ engines: {node: '>=4'}
+ peerDependencies:
+ aws4: '*'
+ bson-ext: '*'
+ kerberos: '*'
+ mongodb-client-encryption: '*'
+ mongodb-extjson: '*'
+ snappy: '*'
+ peerDependenciesMeta:
+ aws4:
+ optional: true
+ bson-ext:
+ optional: true
+ kerberos:
+ optional: true
+ mongodb-client-encryption:
+ optional: true
+ mongodb-extjson:
+ optional: true
+ snappy:
+ optional: true
+ dependencies:
+ bl: 2.2.1
+ bson: 1.1.6
+ denque: 1.5.1
+ optional-require: 1.1.8
+ safe-buffer: 5.2.1
+ optionalDependencies:
+ saslprep: 1.0.3
+ dev: false
+
+ /mongoose-legacy-pluralize@1.0.2(mongoose@5.13.17):
+ resolution: {integrity: sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==}
+ peerDependencies:
+ mongoose: '*'
+ dependencies:
+ mongoose: 5.13.17
+ dev: false
+
+ /mongoose@5.13.17:
+ resolution: {integrity: sha512-kzlwQgrWaQflFSdENNGN4+FQEm/yOMgR1T1okIp5fARGQ8YKdjO+0U9Ikzsv5OVSFIkE0ATyJj2XxawYbf2bpA==}
+ engines: {node: '>=4.0.0'}
+ dependencies:
+ '@types/bson': 4.0.5
+ '@types/mongodb': 3.6.20
+ bson: 1.1.6
+ kareem: 2.3.2
+ mongodb: 3.7.3
+ mongoose-legacy-pluralize: 1.0.2(mongoose@5.13.17)
+ mpath: 0.8.4
+ mquery: 3.2.5
+ ms: 2.1.2
+ optional-require: 1.0.3
+ regexp-clone: 1.0.0
+ safe-buffer: 5.2.1
+ sift: 13.5.2
+ sliced: 1.0.1
+ transitivePeerDependencies:
+ - aws4
+ - bson-ext
+ - kerberos
+ - mongodb-client-encryption
+ - mongodb-extjson
+ - snappy
+ - supports-color
+ dev: false
+
+ /mpath@0.8.4:
+ resolution: {integrity: sha512-DTxNZomBcTWlrMW76jy1wvV37X/cNNxPW1y2Jzd4DZkAaC5ZGsm8bfGfNOthcDuRJujXLqiuS6o3Tpy0JEoh7g==}
+ engines: {node: '>=4.0.0'}
+ dev: false
+
+ /mquery@3.2.5:
+ resolution: {integrity: sha512-VjOKHHgU84wij7IUoZzFRU07IAxd5kWJaDmyUzQlbjHjyoeK5TNeeo8ZsFDtTYnSgpW6n/nMNIHvE3u8Lbrf4A==}
+ engines: {node: '>=4.0.0'}
+ dependencies:
+ bluebird: 3.5.1
+ debug: 3.1.0
+ regexp-clone: 1.0.0
+ safe-buffer: 5.1.2
+ sliced: 1.0.1
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /ms@2.0.0:
+ resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
+ dev: false
+
+ /ms@2.1.2:
+ resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
+
+ /ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+ /nanoid@3.3.6:
+ resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+ dev: false
+
+ /natural-compare@1.4.0:
+ resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+ dev: true
+
+ /negotiator@0.6.3:
+ resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /neo-async@2.6.2:
+ resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
+ dev: false
+
+ /niceware@3.0.0:
+ resolution: {integrity: sha512-DbeDuqe836Ba4S9vjim4jTbbqmjCMwuAXFCVdh4QAvbmLOhmIQs84IakYrcXd/87VCsj1XKhSmmg7bAmwAEh5A==}
+ dependencies:
+ binary-search: 1.3.6
+ randombytes: 2.1.0
+ dev: false
+
+ /node-schedule@1.3.3:
+ resolution: {integrity: sha512-uF9Ubn6luOPrcAYKfsXWimcJ1tPFtQ8I85wb4T3NgJQrXazEzojcFZVk46ZlLHby3eEJChgkV/0T689IsXh2Gw==}
+ dependencies:
+ cron-parser: 2.18.0
+ long-timeout: 0.1.1
+ sorted-array-functions: 1.3.0
+ dev: false
+
+ /nodemailer@6.9.2:
+ resolution: {integrity: sha512-4+TYaa/e1nIxQfyw/WzNPYTEZ5OvHIDEnmjs4LPmIfccPQN+2CYKmGHjWixn/chzD3bmUTu5FMfpltizMxqzdg==}
+ engines: {node: '>=6.0.0'}
+ dev: false
+
+ /nodemon@2.0.22:
+ resolution: {integrity: sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==}
+ engines: {node: '>=8.10.0'}
+ hasBin: true
+ dependencies:
+ chokidar: 3.5.3
+ debug: 3.2.7(supports-color@5.5.0)
+ ignore-by-default: 1.0.1
+ minimatch: 3.1.2
+ pstree.remy: 1.1.8
+ semver: 5.7.1
+ simple-update-notifier: 1.1.0
+ supports-color: 5.5.0
+ touch: 3.1.0
+ undefsafe: 2.0.5
+ dev: true
+
+ /nopt@1.0.10:
+ resolution: {integrity: sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==}
+ hasBin: true
+ dependencies:
+ abbrev: 1.1.1
+ dev: true
+
+ /normalize-path@3.0.0:
+ resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /oauth-sign@0.9.0:
+ resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==}
+ dev: false
+
+ /object-assign@4.1.1:
+ resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
+ /object-inspect@1.12.3:
+ resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==}
+ dev: false
+
+ /object-keys@1.1.1:
+ resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
+ engines: {node: '>= 0.4'}
+ dev: false
+
+ /omggif@1.0.10:
+ resolution: {integrity: sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==}
+ dev: false
+
+ /on-finished@2.4.1:
+ resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ ee-first: 1.1.1
+ dev: false
+
+ /on-headers@1.0.2:
+ resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==}
+ engines: {node: '>= 0.8'}
+ dev: false
+
+ /once@1.4.0:
+ resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+ dependencies:
+ wrappy: 1.0.2
+
+ /optional-require@1.0.3:
+ resolution: {integrity: sha512-RV2Zp2MY2aeYK5G+B/Sps8lW5NHAzE5QClbFP15j+PWmP+T9PxlJXBOOLoSAdgwFvS4t0aMR4vpedMkbHfh0nA==}
+ engines: {node: '>=4'}
+ dev: false
+
+ /optional-require@1.1.8:
+ resolution: {integrity: sha512-jq83qaUb0wNg9Krv1c5OQ+58EK+vHde6aBPzLvPPqJm89UQWsvSuFy9X/OSNJnFeSOKo7btE0n8Nl2+nE+z5nA==}
+ engines: {node: '>=4'}
+ dependencies:
+ require-at: 1.0.6
+ dev: false
+
+ /optionator@0.9.1:
+ resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ deep-is: 0.1.4
+ fast-levenshtein: 2.0.6
+ levn: 0.4.1
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+ word-wrap: 1.2.3
+ dev: true
+
+ /p-limit@3.1.0:
+ resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
+ engines: {node: '>=10'}
+ dependencies:
+ yocto-queue: 0.1.0
+ dev: true
+
+ /p-locate@5.0.0:
+ resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
+ engines: {node: '>=10'}
+ dependencies:
+ p-limit: 3.1.0
+ dev: true
+
+ /pako@1.0.11:
+ resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==}
+ dev: false
+
+ /parent-module@1.0.1:
+ resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+ engines: {node: '>=6'}
+ dependencies:
+ callsites: 3.1.0
+ dev: true
+
+ /parse-bmfont-ascii@1.0.6:
+ resolution: {integrity: sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA==}
+ dev: false
+
+ /parse-bmfont-binary@1.0.6:
+ resolution: {integrity: sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA==}
+ dev: false
+
+ /parse-bmfont-xml@1.1.4:
+ resolution: {integrity: sha512-bjnliEOmGv3y1aMEfREMBJ9tfL3WR0i0CKPj61DnSLaoxWR3nLrsQrEbCId/8rF4NyRF0cCqisSVXyQYWM+mCQ==}
+ dependencies:
+ xml-parse-from-string: 1.0.1
+ xml2js: 0.4.23
+ dev: false
+
+ /parse-headers@2.0.5:
+ resolution: {integrity: sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==}
+ dev: false
+
+ /parse-srcset@1.0.2:
+ resolution: {integrity: sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==}
+ dev: false
+
+ /parseurl@1.3.3:
+ resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
+ engines: {node: '>= 0.8'}
+ dev: false
+
+ /path-exists@4.0.0:
+ resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /path-is-absolute@1.0.1:
+ resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /path-key@3.1.1:
+ resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /path-to-regexp@0.1.7:
+ resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==}
+ dev: false
+
+ /peek-readable@4.1.0:
+ resolution: {integrity: sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==}
+ engines: {node: '>=8'}
+ dev: false
+
+ /performance-now@2.1.0:
+ resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==}
+ dev: false
+
+ /phin@2.9.3:
+ resolution: {integrity: sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA==}
+ dev: false
+
+ /picocolors@1.0.0:
+ resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
+ dev: false
+
+ /picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+ dev: true
+
+ /pixelmatch@4.0.2:
+ resolution: {integrity: sha512-J8B6xqiO37sU/gkcMglv6h5Jbd9xNER7aHzpfRdNmV4IbQBzBpe4l9XmbG+xPF/znacgu2jfEw+wHffaq/YkXA==}
+ hasBin: true
+ dependencies:
+ pngjs: 3.4.0
+ dev: false
+
+ /pngjs@3.4.0:
+ resolution: {integrity: sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==}
+ engines: {node: '>=4.0.0'}
+ dev: false
+
+ /postcss@8.4.23:
+ resolution: {integrity: sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==}
+ engines: {node: ^10 || ^12 || >=14}
+ dependencies:
+ nanoid: 3.3.6
+ picocolors: 1.0.0
+ source-map-js: 1.0.2
+ dev: false
+
+ /prelude-ls@1.2.1:
+ resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
+ engines: {node: '>= 0.8.0'}
+ dev: true
+
+ /prettier@2.8.8:
+ resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==}
+ engines: {node: '>=10.13.0'}
+ hasBin: true
+ dev: true
+
+ /process-nextick-args@2.0.1:
+ resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
+ dev: false
+
+ /process@0.11.10:
+ resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==}
+ engines: {node: '>= 0.6.0'}
+ dev: false
+
+ /proxy-addr@2.0.7:
+ resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
+ engines: {node: '>= 0.10'}
+ dependencies:
+ forwarded: 0.2.0
+ ipaddr.js: 1.9.1
+ dev: false
+
+ /psl@1.9.0:
+ resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==}
+ dev: false
+
+ /pstree.remy@1.1.8:
+ resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==}
+ dev: true
+
+ /punycode@2.3.0:
+ resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
+ engines: {node: '>=6'}
+
+ /qs@6.11.0:
+ resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==}
+ engines: {node: '>=0.6'}
+ dependencies:
+ side-channel: 1.0.4
+ dev: false
+
+ /qs@6.5.3:
+ resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==}
+ engines: {node: '>=0.6'}
+ dev: false
+
+ /queue-microtask@1.2.3:
+ resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+ dev: true
+
+ /random-bytes@1.0.0:
+ resolution: {integrity: sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==}
+ engines: {node: '>= 0.8'}
+ dev: false
+
+ /randombytes@2.0.3:
+ resolution: {integrity: sha512-lDVjxQQFoCG1jcrP06LNo2lbWp4QTShEXnhActFBwYuHprllQV6VUpwreApsYqCgD+N1mHoqJ/BI/4eV4R2GYg==}
+ dev: false
+
+ /randombytes@2.1.0:
+ resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
+ dependencies:
+ safe-buffer: 5.2.1
+ dev: false
+
+ /randomstring@1.2.3:
+ resolution: {integrity: sha512-3dEFySepTzp2CvH6W/ASYGguPPveBuz5MpZ7MuoUkoVehmyNl9+F9c9GFVrz2QPbM9NXTIHGcmJDY/3j4677kQ==}
+ hasBin: true
+ dependencies:
+ array-uniq: 1.0.2
+ randombytes: 2.0.3
+ dev: false
+
+ /range-parser@1.2.1:
+ resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /raw-body@2.5.1:
+ resolution: {integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ bytes: 3.1.2
+ http-errors: 2.0.0
+ iconv-lite: 0.4.24
+ unpipe: 1.0.0
+ dev: false
+
+ /raw-body@2.5.2:
+ resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ bytes: 3.1.2
+ http-errors: 2.0.0
+ iconv-lite: 0.4.24
+ unpipe: 1.0.0
+ dev: false
+
+ /readable-stream@2.3.8:
+ resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==}
+ dependencies:
+ core-util-is: 1.0.3
+ inherits: 2.0.4
+ isarray: 1.0.0
+ process-nextick-args: 2.0.1
+ safe-buffer: 5.1.2
+ string_decoder: 1.1.1
+ util-deprecate: 1.0.2
+ dev: false
+
+ /readable-stream@3.6.2:
+ resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
+ engines: {node: '>= 6'}
+ dependencies:
+ inherits: 2.0.4
+ string_decoder: 1.3.0
+ util-deprecate: 1.0.2
+ dev: false
+
+ /readable-web-to-node-stream@3.0.2:
+ resolution: {integrity: sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==}
+ engines: {node: '>=8'}
+ dependencies:
+ readable-stream: 3.6.2
+ dev: false
+
+ /readdirp@3.6.0:
+ resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
+ engines: {node: '>=8.10.0'}
+ dependencies:
+ picomatch: 2.3.1
+ dev: true
+
+ /regenerator-runtime@0.13.11:
+ resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
+ dev: false
+
+ /regexp-clone@1.0.0:
+ resolution: {integrity: sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw==}
+ dev: false
+
+ /request@2.88.2:
+ resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==}
+ engines: {node: '>= 6'}
+ deprecated: request has been deprecated, see https://github.com/request/request/issues/3142
+ dependencies:
+ aws-sign2: 0.7.0
+ aws4: 1.12.0
+ caseless: 0.12.0
+ combined-stream: 1.0.8
+ extend: 3.0.2
+ forever-agent: 0.6.1
+ form-data: 2.3.3
+ har-validator: 5.1.5
+ http-signature: 1.2.0
+ is-typedarray: 1.0.0
+ isstream: 0.1.2
+ json-stringify-safe: 5.0.1
+ mime-types: 2.1.35
+ oauth-sign: 0.9.0
+ performance-now: 2.1.0
+ qs: 6.5.3
+ safe-buffer: 5.2.1
+ tough-cookie: 2.5.0
+ tunnel-agent: 0.6.0
+ uuid: 3.4.0
+ dev: false
+
+ /require-at@1.0.6:
+ resolution: {integrity: sha512-7i1auJbMUrXEAZCOQ0VNJgmcT2VOKPRl2YGJwgpHpC9CE91Mv4/4UYIUm4chGJaI381ZDq1JUicFii64Hapd8g==}
+ engines: {node: '>=4'}
+ dev: false
+
+ /resolve-from@4.0.0:
+ resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /reusify@1.0.4:
+ resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
+ engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+ dev: true
+
+ /rimraf@3.0.2:
+ resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
+ hasBin: true
+ dependencies:
+ glob: 7.2.3
+ dev: true
+
+ /rrule@2.4.1:
+ resolution: {integrity: sha512-+NcvhETefswZq13T8nkuEnnQ6YgUeZaqMqVbp+ZiFDPCbp3AVgQIwUvNVDdMNrP05bKZG9ddDULFp0qZZYDrxg==}
+ optionalDependencies:
+ luxon: 1.28.1
+ dev: false
+
+ /run-parallel@1.2.0:
+ resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+ dependencies:
+ queue-microtask: 1.2.3
+ dev: true
+
+ /safe-buffer@5.1.2:
+ resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
+ dev: false
+
+ /safe-buffer@5.2.1:
+ resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
+ dev: false
+
+ /safer-buffer@2.1.2:
+ resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+ dev: false
+
+ /sanitize-html@2.10.0:
+ resolution: {integrity: sha512-JqdovUd81dG4k87vZt6uA6YhDfWkUGruUu/aPmXLxXi45gZExnt9Bnw/qeQU8oGf82vPyaE0vO4aH0PbobB9JQ==}
+ dependencies:
+ deepmerge: 4.3.1
+ escape-string-regexp: 4.0.0
+ htmlparser2: 8.0.2
+ is-plain-object: 5.0.0
+ parse-srcset: 1.0.2
+ postcss: 8.4.23
+ dev: false
+
+ /saslprep@1.0.3:
+ resolution: {integrity: sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==}
+ engines: {node: '>=6'}
+ requiresBuild: true
+ dependencies:
+ sparse-bitfield: 3.0.3
+ dev: false
+ optional: true
+
+ /sax@1.2.4:
+ resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==}
+ dev: false
+
+ /semver@5.7.1:
+ resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==}
+ hasBin: true
+ dev: true
+
+ /semver@7.0.0:
+ resolution: {integrity: sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==}
+ hasBin: true
+ dev: true
+
+ /send@0.18.0:
+ resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ debug: 2.6.9
+ depd: 2.0.0
+ destroy: 1.2.0
+ encodeurl: 1.0.2
+ escape-html: 1.0.3
+ etag: 1.8.1
+ fresh: 0.5.2
+ http-errors: 2.0.0
+ mime: 1.6.0
+ ms: 2.1.3
+ on-finished: 2.4.1
+ range-parser: 1.2.1
+ statuses: 2.0.1
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /serve-static@1.15.0:
+ resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ encodeurl: 1.0.2
+ escape-html: 1.0.3
+ parseurl: 1.3.3
+ send: 0.18.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /setprototypeof@1.2.0:
+ resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
+ dev: false
+
+ /shebang-command@2.0.0:
+ resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+ engines: {node: '>=8'}
+ dependencies:
+ shebang-regex: 3.0.0
+ dev: true
+
+ /shebang-regex@3.0.0:
+ resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /side-channel@1.0.4:
+ resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
+ dependencies:
+ call-bind: 1.0.2
+ get-intrinsic: 1.2.0
+ object-inspect: 1.12.3
+ dev: false
+
+ /sift@13.5.2:
+ resolution: {integrity: sha512-+gxdEOMA2J+AI+fVsCqeNn7Tgx3M9ZN9jdi95939l1IJ8cZsqS8sqpJyOkic2SJk+1+98Uwryt/gL6XDaV+UZA==}
+ dev: false
+
+ /simple-update-notifier@1.1.0:
+ resolution: {integrity: sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==}
+ engines: {node: '>=8.10.0'}
+ dependencies:
+ semver: 7.0.0
+ dev: true
+
+ /sliced@1.0.1:
+ resolution: {integrity: sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2Xxzm/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yA==}
+ dev: false
+
+ /sorted-array-functions@1.3.0:
+ resolution: {integrity: sha512-2sqgzeFlid6N4Z2fUQ1cvFmTOLRi/sEDzSQ0OKYchqgoPmQBVyM3959qYx3fpS6Esef80KjmpgPeEr028dP3OA==}
+ dev: false
+
+ /source-map-js@1.0.2:
+ resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
+ /source-map@0.6.1:
+ resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
+ /sparse-bitfield@3.0.3:
+ resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==}
+ dependencies:
+ memory-pager: 1.5.0
+ dev: false
+ optional: true
+
+ /sshpk@1.17.0:
+ resolution: {integrity: sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==}
+ engines: {node: '>=0.10.0'}
+ hasBin: true
+ dependencies:
+ asn1: 0.2.6
+ assert-plus: 1.0.0
+ bcrypt-pbkdf: 1.0.2
+ dashdash: 1.14.1
+ ecc-jsbn: 0.1.2
+ getpass: 0.1.7
+ jsbn: 0.1.1
+ safer-buffer: 2.1.2
+ tweetnacl: 0.14.5
+ dev: false
+
+ /statuses@2.0.1:
+ resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
+ engines: {node: '>= 0.8'}
+ dev: false
+
+ /streamsearch@1.1.0:
+ resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
+ engines: {node: '>=10.0.0'}
+ dev: false
+
+ /string_decoder@1.1.1:
+ resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
+ dependencies:
+ safe-buffer: 5.1.2
+ dev: false
+
+ /string_decoder@1.3.0:
+ resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
+ dependencies:
+ safe-buffer: 5.2.1
+ dev: false
+
+ /strip-ansi@6.0.1:
+ resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
+ engines: {node: '>=8'}
+ dependencies:
+ ansi-regex: 5.0.1
+ dev: true
+
+ /strip-json-comments@3.1.1:
+ resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /strtok3@6.3.0:
+ resolution: {integrity: sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==}
+ engines: {node: '>=10'}
+ dependencies:
+ '@tokenizer/token': 0.3.0
+ peek-readable: 4.1.0
+ dev: false
+
+ /supports-color@5.5.0:
+ resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
+ engines: {node: '>=4'}
+ dependencies:
+ has-flag: 3.0.0
+
+ /supports-color@7.2.0:
+ resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+ engines: {node: '>=8'}
+ dependencies:
+ has-flag: 4.0.0
+ dev: true
+
+ /text-table@0.2.0:
+ resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
+ dev: true
+
+ /timm@1.7.1:
+ resolution: {integrity: sha512-IjZc9KIotudix8bMaBW6QvMuq64BrJWFs1+4V0lXwWGQZwH+LnX87doAYhem4caOEusRP9/g6jVDQmZ8XOk1nw==}
+ dev: false
+
+ /tinycolor2@1.6.0:
+ resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==}
+ dev: false
+
+ /to-regex-range@5.0.1:
+ resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+ engines: {node: '>=8.0'}
+ dependencies:
+ is-number: 7.0.0
+ dev: true
+
+ /toidentifier@1.0.1:
+ resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
+ engines: {node: '>=0.6'}
+ dev: false
+
+ /token-types@4.2.1:
+ resolution: {integrity: sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==}
+ engines: {node: '>=10'}
+ dependencies:
+ '@tokenizer/token': 0.3.0
+ ieee754: 1.2.1
+ dev: false
+
+ /touch@3.1.0:
+ resolution: {integrity: sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==}
+ hasBin: true
+ dependencies:
+ nopt: 1.0.10
+ dev: true
+
+ /tough-cookie@2.5.0:
+ resolution: {integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==}
+ engines: {node: '>=0.8'}
+ dependencies:
+ psl: 1.9.0
+ punycode: 2.3.0
+ dev: false
+
+ /tunnel-agent@0.6.0:
+ resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
+ dependencies:
+ safe-buffer: 5.2.1
+ dev: false
+
+ /tweetnacl@0.14.5:
+ resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==}
+ dev: false
+
+ /type-check@0.4.0:
+ resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ prelude-ls: 1.2.1
+ dev: true
+
+ /type-fest@0.20.2:
+ resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /type-is@1.6.18:
+ resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
+ engines: {node: '>= 0.6'}
+ dependencies:
+ media-typer: 0.3.0
+ mime-types: 2.1.35
+ dev: false
+
+ /typescript@5.0.4:
+ resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==}
+ engines: {node: '>=12.20'}
+ hasBin: true
+ dev: true
+
+ /uglify-js@3.17.4:
+ resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==}
+ engines: {node: '>=0.8.0'}
+ hasBin: true
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /uid-safe@2.1.5:
+ resolution: {integrity: sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ random-bytes: 1.0.0
+ dev: false
+
+ /undefsafe@2.0.5:
+ resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==}
+ dev: true
+
+ /unpipe@1.0.0:
+ resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
+ engines: {node: '>= 0.8'}
+ dev: false
+
+ /uri-js@4.4.1:
+ resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+ dependencies:
+ punycode: 2.3.0
+
+ /utif@2.0.1:
+ resolution: {integrity: sha512-Z/S1fNKCicQTf375lIP9G8Sa1H/phcysstNrrSdZKj1f9g58J4NMgb5IgiEZN9/nLMPDwF0W7hdOe9Qq2IYoLg==}
+ dependencies:
+ pako: 1.0.11
+ dev: false
+
+ /util-deprecate@1.0.2:
+ resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+ dev: false
+
+ /utils-merge@1.0.1:
+ resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
+ engines: {node: '>= 0.4.0'}
+ dev: false
+
+ /uuid@3.4.0:
+ resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==}
+ deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.
+ hasBin: true
+ dev: false
+
+ /validator@13.9.0:
+ resolution: {integrity: sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA==}
+ engines: {node: '>= 0.10'}
+ dev: false
+
+ /vary@1.1.2:
+ resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
+ engines: {node: '>= 0.8'}
+ dev: false
+
+ /verror@1.10.0:
+ resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==}
+ engines: {'0': node >=0.6.0}
+ dependencies:
+ assert-plus: 1.0.0
+ core-util-is: 1.0.2
+ extsprintf: 1.3.0
+ dev: false
+
+ /which@2.0.2:
+ resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+ engines: {node: '>= 8'}
+ hasBin: true
+ dependencies:
+ isexe: 2.0.0
+ dev: true
+
+ /word-wrap@1.2.3:
+ resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /wordwrap@1.0.0:
+ resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==}
+ dev: false
+
+ /wrappy@1.0.2:
+ resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+
+ /xhr@2.6.0:
+ resolution: {integrity: sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==}
+ dependencies:
+ global: 4.4.0
+ is-function: 1.0.2
+ parse-headers: 2.0.5
+ xtend: 4.0.2
+ dev: false
+
+ /xml-parse-from-string@1.0.1:
+ resolution: {integrity: sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g==}
+ dev: false
+
+ /xml2js@0.4.23:
+ resolution: {integrity: sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==}
+ engines: {node: '>=4.0.0'}
+ dependencies:
+ sax: 1.2.4
+ xmlbuilder: 11.0.1
+ dev: false
+
+ /xmlbuilder@11.0.1:
+ resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==}
+ engines: {node: '>=4.0'}
+ dev: false
+
+ /xtend@4.0.2:
+ resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
+ engines: {node: '>=0.4'}
+ dev: false
+
+ /yocto-queue@0.1.0:
+ resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
+ engines: {node: '>=10'}
+ dev: true
diff --git a/routes.js b/routes.js
deleted file mode 100755
index c9867e3..0000000
--- a/routes.js
+++ /dev/null
@@ -1,1976 +0,0 @@
-const fs = require('fs');
-
-const express = require('express');
-
-const mongoose = require('mongoose');
-
-// This alphabet (used to generate all event, group, etc. IDs) is missing '-'
-// because ActivityPub doesn't like it in IDs
-const { customAlphabet } = require('nanoid');
-const nanoid = customAlphabet('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_', 21);
-
-const randomstring = require("randomstring");
-
-const { body, validationResult } = require('express-validator');
-
-const router = express.Router();
-
-const Event = mongoose.model('Event');
-const EventGroup = mongoose.model('EventGroup');
-const addToLog = require('./helpers.js').addToLog;
-
-var moment = require('moment-timezone');
-
-const marked = require('marked');
-
-const generateRSAKeypair = require('generate-rsa-keypair');
-const crypto = require('crypto');
-const request = require('request');
-const niceware = require('niceware');
-
-const domain = require('./config/domain.js').domain;
-const contactEmail = require('./config/domain.js').email;
-const mailService = require('./config/domain.js').mailService;
-const siteName = require('./config/domain.js').sitename;
-const siteLogo = require('./config/domain.js').logo_url;
-let isFederated = require('./config/domain.js').isFederated;
-let showKofi = require('./config/domain.js').showKofi;
-// if the federation config isn't set, things are federated by default
-if (isFederated === undefined) {
- isFederated = true;
-}
-const ap = require('./activitypub.js');
-
-// Extra marked renderer (used to render plaintext event description for page metadata)
-// Adapted from https://dustinpfister.github.io/2017/11/19/nodejs-marked/
-// &#63; to ? helper
-function htmlEscapeToText(text) {
- return text.replace(/\&\#[0-9]*;|&amp;/g, function (escapeCode) {
- if (escapeCode.match(/amp/)) {
- return '&';
- }
- return String.fromCharCode(escapeCode.match(/[0-9]+/));
- });
-}
-
-function render_plain() {
- var render = new marked.Renderer();
- // render just the text of a link, strong, em
- render.link = function (href, title, text) {
- return text;
- };
- render.strong = function (text) {
- return text;
- }
- render.em = function (text) {
- return text;
- }
- // render just the text of a paragraph
- render.paragraph = function (text) {
- return htmlEscapeToText(text) + '\r\n';
- };
- // render nothing for headings, images, and br
- render.heading = function (text, level) {
- return '';
- };
- render.image = function (href, title, text) {
- return '';
- };
- render.br = function () {
- return '';
- };
- return render;
-}
-
-const ical = require('ical');
-const { exportIcal } = require('./helpers.js');
-
-const sgMail = require('@sendgrid/mail');
-const nodemailer = require("nodemailer");
-
-const apiCredentials = require('./config/api.js');
-
-let sendEmails = false;
-let nodemailerTransporter;
-if (mailService) {
- switch (mailService) {
- case 'sendgrid':
- sgMail.setApiKey(apiCredentials.sendgrid);
- console.log("Sendgrid is ready to send emails.");
- sendEmails = true;
- break;
- case 'nodemailer':
- nodemailerTransporter = nodemailer.createTransport({
- host: apiCredentials.smtpServer,
- port: apiCredentials.smtpPort,
- secure: false, // true for 465, false for other ports
- auth: {
- user: apiCredentials.smtpUsername, // generated ethereal user
- pass: apiCredentials.smtpPassword, // generated ethereal password
- },
- });
- nodemailerTransporter.verify((error, success) => {
- if (error) {
- console.log(error);
- } else {
- console.log("Nodemailer SMTP server is ready to send emails.");
- sendEmails = true;
- }
- });
- break;
- default:
- console.error('You have not configured this Gathio instance to send emails! This means that event creators will not receive emails when their events are created, which means they may end up locked out of editing events. Consider setting up an email service.')
- }
-}
-
-const fileUpload = require('express-fileupload');
-var Jimp = require('jimp');
-router.use(fileUpload());
-
-// SCHEDULED DELETION
-const schedule = require('node-schedule');
-schedule.scheduleJob('59 23 * * *', function (fireDate) {
- const too_old = moment.tz('Etc/UTC').subtract(7, 'days').toDate();
- console.log("Old event deletion running! Deleting all events concluding before ", too_old);
-
- Event.find({ end: { $lte: too_old } }).then((oldEvents) => {
- oldEvents.forEach(event => {
- const deleteEventFromDB = (id) => {
- Event.remove({ "_id": id })
- .then(response => {
- addToLog("deleteOldEvents", "success", "Old event " + id + " deleted");
- }).catch((err) => {
- addToLog("deleteOldEvents", "error", "Attempt to delete old event " + id + " failed with error: " + err);
- });
- }
-
- if (event.image) {
- fs.unlink(global.appRoot + '/public/events/' + event.image, (err) => {
- if (err) {
- addToLog("deleteOldEvents", "error", "Attempt to delete event image for old event " + event.id + " failed with error: " + err);
- }
- // Image removed
- addToLog("deleteOldEvents", "error", "Image deleted for old event " + event.id);
- })
- }
- // Check if event has ActivityPub fields
- if (event.activityPubActor && event.activityPubEvent) {
- // Broadcast a Delete profile message to all followers so that at least Mastodon servers will delete their local profile information
- const guidUpdateObject = crypto.randomBytes(16).toString('hex');
- const jsonUpdateObject = JSON.parse(event.activityPubActor);
- const jsonEventObject = JSON.parse(event.activityPubEvent);
- // first broadcast AP messages, THEN delete from DB
- ap.broadcastDeleteMessage(jsonUpdateObject, event.followers, event.id, function (statuses) {
- ap.broadcastDeleteMessage(jsonEventObject, event.followers, event.id, function (statuses) {
- deleteEventFromDB(event._id);
- });
- });
- } else {
- // No ActivityPub data - simply delete the event
- deleteEventFromDB(event._id);
- }
- })
- }).catch((err) => {
- addToLog("deleteOldEvents", "error", "Attempt to delete old event " + event.id + " failed with error: " + err);
- });
-
- // TODO: While we're here, also remove all provisioned event attendees over a day
- // old (they're not going to become active)
-});
-
-// FRONTEND ROUTES
-
-router.get('/', (req, res) => {
- res.render('home', {
- domain,
- email: contactEmail,
- siteName,
- showKofi,
- });
-});
-
-router.get('/new', (req, res) => {
- res.render('home');
-});
-
-router.get('/new/event', (req, res) => {
- res.render('newevent', {
- domain: domain,
- email: contactEmail,
- siteName: siteName,
- });
-});
-router.get('/new/event/public', (req, res) => {
- let isPrivate = false;
- let isPublic = true;
- let isOrganisation = false;
- let isUnknownType = false;
- res.render('newevent', {
- title: 'New event',
- isPrivate: isPrivate,
- isPublic: isPublic,
- isOrganisation: isOrganisation,
- isUnknownType: isUnknownType,
- eventType: 'public',
- domain: domain,
- email: contactEmail,
- siteName: siteName,
- });
-})
-
-// return the JSON for the featured/pinned post for this event
-router.get('/:eventID/featured', (req, res) => {
- if (!isFederated) return res.sendStatus(404);
- const { eventID } = req.params;
- const guidObject = crypto.randomBytes(16).toString('hex');
- const featured = {
- "@context": "https://www.w3.org/ns/activitystreams",
- "id": `https://${domain}/${eventID}/featured`,
- "type": "OrderedCollection",
- "orderedItems": [
- ap.createFeaturedPost(eventID)
- ]
- }
- res.json(featured);
-});
-
-// return the JSON for a given activitypub message
-router.get('/:eventID/m/:hash', (req, res) => {
- if (!isFederated) return res.sendStatus(404);
- const { hash, eventID } = req.params;
- const id = `https://${domain}/${eventID}/m/${hash}`;
-
- Event.findOne({
- id: eventID
- })
- .then((event) => {
- if (!event) {
- res.status(404);
- res.render('404', { url: req.url });
- }
- else {
- const message = event.activityPubMessages.find(el => el.id === id);
- if (message) {
- return res.json(JSON.parse(message.content));
- }
- else {
- res.status(404);
- return res.render('404', { url: req.url });
- }
- }
- })
- .catch((err) => {
- addToLog("getActivityPubMessage", "error", "Attempt to get Activity Pub Message for " + id + " failed with error: " + err);
- res.status(404);
- res.render('404', { url: req.url });
- return;
- });
-});
-
-// return the webfinger record required for the initial activitypub handshake
-router.get('/.well-known/webfinger', (req, res) => {
- if (!isFederated) return res.sendStatus(404);
- let resource = req.query.resource;
- if (!resource || !resource.includes('acct:')) {
- return res.status(400).send('Bad request. Please make sure "acct:USER@DOMAIN" is what you are sending as the "resource" query parameter.');
- }
- else {
- // "foo@domain"
- let activityPubAccount = resource.replace('acct:', '');
- // "foo"
- let eventID = activityPubAccount.replace(/@.*/, '');
- Event.findOne({
- id: eventID
- })
- .then((event) => {
- if (!event) {
- res.status(404);
- res.render('404', { url: req.url });
- }
- else {
- res.json(ap.createWebfinger(eventID, domain));
- }
- })
- .catch((err) => {
- addToLog("renderWebfinger", "error", "Attempt to render webfinger for " + req.params.eventID + " failed with error: " + err);
- res.status(404);
- res.render('404', { url: req.url });
- return;
- });
- }
-});
-
-router.get('/:eventID', (req, res) => {
- Event.findOne({
- id: req.params.eventID
- })
- .lean() // Required, see: https://stackoverflow.com/questions/59690923/handlebars-access-has-been-denied-to-resolve-the-property-from-because-it-is
- .populate('eventGroup')
- .then((event) => {
- if (event) {
- const parsedLocation = event.location.replace(/\s+/g, '+');
- let displayDate;
- if (moment.tz(event.end, event.timezone).isSame(event.start, 'day')) {
- // Happening during one day
- displayDate = moment.tz(event.start, event.timezone).format('dddd D MMMM YYYY [<span class="text-muted">from</span>] h:mm a') + moment.tz(event.end, event.timezone).format(' [<span class="text-muted">to</span>] h:mm a [<span class="text-muted">](z)[</span>]');
- }
- else {
- displayDate = moment.tz(event.start, event.timezone).format('dddd D MMMM YYYY [<span class="text-muted">at</span>] h:mm a') + moment.tz(event.end, event.timezone).format(' [<span class="text-muted">–</span>] dddd D MMMM YYYY [<span class="text-muted">at</span>] h:mm a [<span class="text-muted">](z)[</span>]');
- }
- let eventStartISO = moment.tz(event.start, "Etc/UTC").toISOString();
- let eventEndISO = moment.tz(event.end, "Etc/UTC").toISOString();
- let parsedStart = moment.tz(event.start, event.timezone).format('YYYYMMDD[T]HHmmss');
- let parsedEnd = moment.tz(event.end, event.timezone).format('YYYYMMDD[T]HHmmss');
- let eventHasConcluded = false;
- if (moment.tz(event.end, event.timezone).isBefore(moment.tz(event.timezone))) {
- eventHasConcluded = true;
- }
- let eventHasBegun = false;
- if (moment.tz(event.start, event.timezone).isBefore(moment.tz(event.timezone))) {
- eventHasBegun = true;
- }
- let fromNow = moment.tz(event.start, event.timezone).fromNow();
- let parsedDescription = marked.parse(event.description);
- let eventEditToken = event.editToken;
-
- let escapedName = event.name.replace(/\s+/g, '+');
-
- let eventHasCoverImage = false;
- if (event.image) {
- eventHasCoverImage = true;
- }
- else {
- eventHasCoverImage = false;
- }
- let eventHasHost = false;
- if (event.hostName) {
- eventHasHost = true;
- }
- else {
- eventHasHost = false;
- }
- let firstLoad = false;
- if (event.firstLoad === true) {
- firstLoad = true;
- Event.findOneAndUpdate({ id: req.params.eventID }, { firstLoad: false }, function (err, raw) {
- if (err) {
- res.send(err);
- }
- });
- }
- let editingEnabled = false;
- if (Object.keys(req.query).length !== 0) {
- if (!req.query.e) {
- editingEnabled = false;
- console.log("No edit token set");
- }
- else {
- if (req.query.e === eventEditToken) {
- editingEnabled = true;
- }
- else {
- editingEnabled = false;
- }
- }
- }
- let eventAttendees = event.attendees.sort((a, b) => (a.name > b.name) ? 1 : ((b.name > a.name) ? -1 : 0))
- .map(el => {
- if (!el.id) {
- el.id = el._id;
- }
- if (el.number > 1) {
- el.name = `${el.name} (${el.number} people)`;
- }
- return el;
- })
- .filter((obj, pos, arr) => {
- return obj.status === 'attending' && arr.map(mapObj => mapObj.id).indexOf(obj.id) === pos;
- });
-
- let spotsRemaining, noMoreSpots;
- let numberOfAttendees = eventAttendees.reduce((acc, attendee) => {
- if (attendee.status === 'attending') {
- return acc + attendee.number || 1;
- }
- return acc;
- }, 0);
- if (event.maxAttendees) {
- spotsRemaining = event.maxAttendees - numberOfAttendees;
- if (spotsRemaining <= 0) {
- noMoreSpots = true;
- }
- }
- let metadata = {
- title: event.name,
- description: marked.parse(event.description, { renderer: render_plain() }).split(" ").splice(0, 40).join(" ").trim(),
- image: (eventHasCoverImage ? `https://${domain}/events/` + event.image : null),
- url: `https://${domain}/` + req.params.eventID
- };
- if (req.headers.accept && (req.headers.accept.includes('application/activity+json') || req.headers.accept.includes('application/json') || req.headers.accept.includes('application/json+ld'))) {
- res.json(JSON.parse(event.activityPubActor));
- }
- else {
- res.set("X-Robots-Tag", "noindex");
- res.render('event', {
- domain: domain,
- isFederated: isFederated,
- email: contactEmail,
- title: event.name,
- escapedName: escapedName,
- eventData: event,
- eventAttendees: eventAttendees,
- numberOfAttendees,
- spotsRemaining: spotsRemaining,
- noMoreSpots: noMoreSpots,
- eventStartISO: eventStartISO,
- eventEndISO: eventEndISO,
- parsedLocation: parsedLocation,
- parsedStart: parsedStart,
- parsedEnd: parsedEnd,
- displayDate: displayDate,
- fromNow: fromNow,
- timezone: event.timezone,
- parsedDescription: parsedDescription,
- editingEnabled: editingEnabled,
- eventHasCoverImage: eventHasCoverImage,
- eventHasHost: eventHasHost,
- firstLoad: firstLoad,
- eventHasConcluded: eventHasConcluded,
- eventHasBegun: eventHasBegun,
- metadata: metadata,
- siteName: siteName
- })
- }
- }
- else {
- res.status(404);
- res.render('404', { url: req.url });
- }
-
- })
- .catch((err) => {
- addToLog("displayEvent", "error", "Attempt to display event " + req.params.eventID + " failed with error: " + err);
- console.log(err)
- res.status(404);
- res.render('404', { url: req.url });
- return;
- });
-})
-
-router.get('/:eventID/followers', (req, res) => {
- if (!isFederated) return res.sendStatus(404);
- const eventID = req.params.eventID;
- Event.findOne({
- id: eventID
- })
- .then((event) => {
- if (event) {
- const followers = event.followers.map(el => el.actorId);
- let followersCollection = {
- "type": "OrderedCollection",
- "totalItems": followers.length,
- "id": `https://${domain}/${eventID}/followers`,
- "first": {
- "type": "OrderedCollectionPage",
- "totalItems": followers.length,
- "partOf": `https://${domain}/${eventID}/followers`,
- "orderedItems": followers,
- "id": `https://${domain}/${eventID}/followers?page=1`
- },
- "@context": ["https://www.w3.org/ns/activitystreams"]
- };
- return res.json(followersCollection);
- }
- else {
- return res.status(400).send('Bad request.');
- }
- })
-})
-
-router.get('/group/:eventGroupID', (req, res) => {
- EventGroup.findOne({
- id: req.params.eventGroupID
- })
- .lean() // Required, see: https://stackoverflow.com/questions/59690923/handlebars-access-has-been-denied-to-resolve-the-property-from-because-it-is
- .then(async (eventGroup) => {
- if (eventGroup) {
- let parsedDescription = marked.parse(eventGroup.description);
- let eventGroupEditToken = eventGroup.editToken;
-
- let escapedName = eventGroup.name.replace(/\s+/g, '+');
-
- let eventGroupHasCoverImage = false;
- if (eventGroup.image) {
- eventGroupHasCoverImage = true;
- }
- else {
- eventGroupHasCoverImage = false;
- }
- let eventGroupHasHost = false;
- if (eventGroup.hostName) {
- eventGroupHasHost = true;
- }
- else {
- eventGroupHasHost = false;
- }
-
- let events = await Event.find({ eventGroup: eventGroup._id }).lean().sort('start');
-
- events.map(event => {
- if (moment.tz(event.end, event.timezone).isSame(event.start, 'day')) {
- // Happening during one day
- event.displayDate = moment.tz(event.start, event.timezone).format('D MMM YYYY');
- }
- else {
- event.displayDate = moment.tz(event.start, event.timezone).format('D MMM YYYY') + moment.tz(event.end, event.timezone).format(' - D MMM YYYY');
- }
- if (moment.tz(event.end, event.timezone).isBefore(moment.tz(event.timezone))) {
- event.eventHasConcluded = true;
- } else {
- event.eventHasConcluded = false;
- }
- return (({ id, name, displayDate, eventHasConcluded }) => ({ id, name, displayDate, eventHasConcluded }))(event);
- });
-
- let upcomingEventsExist = false;
- if (events.some(e => e.eventHasConcluded === false)) {
- upcomingEventsExist = true;
- }
-
- let firstLoad = false;
- if (eventGroup.firstLoad === true) {
- firstLoad = true;
- EventGroup.findOneAndUpdate({ id: req.params.eventGroupID }, { firstLoad: false }, function (err, raw) {
- if (err) {
- res.send(err);
- }
- });
- }
- let editingEnabled = false;
- if (Object.keys(req.query).length !== 0) {
- if (!req.query.e) {
- editingEnabled = false;
- console.log("No edit token set");
- }
- else {
- if (req.query.e === eventGroupEditToken) {
- editingEnabled = true;
- }
- else {
- editingEnabled = false;
- }
- }
- }
- let metadata = {
- title: eventGroup.name,
- description: marked.parse(eventGroup.description, { renderer: render_plain() }).split(" ").splice(0, 40).join(" ").trim(),
- image: (eventGroupHasCoverImage ? `https://${domain}/events/` + eventGroup.image : null),
- url: `https://${domain}/` + req.params.eventID
- };
- res.set("X-Robots-Tag", "noindex");
- res.render('eventgroup', {
- domain: domain,
- title: eventGroup.name,
- eventGroupData: eventGroup,
- escapedName: escapedName,
- events: events,
- upcomingEventsExist: upcomingEventsExist,
- parsedDescription: parsedDescription,
- editingEnabled: editingEnabled,
- eventGroupHasCoverImage: eventGroupHasCoverImage,
- eventGroupHasHost: eventGroupHasHost,
- firstLoad: firstLoad,
- metadata: metadata
- })
- }
- else {
- res.status(404);
- res.render('404', { url: req.url });
- }
-
- })
- .catch((err) => {
- addToLog("displayEventGroup", "error", "Attempt to display event group " + req.params.eventGroupID + " failed with error: " + err);
- console.log(err)
- res.status(404);
- res.render('404', { url: req.url });
- return;
- });
-})
-
-router.get('/group/:eventGroupID/feed.ics', (req, res) => {
- EventGroup.findOne({
- id: req.params.eventGroupID
- })
- .lean() // Required, see: https://stackoverflow.com/questions/59690923/handlebars-access-has-been-denied-to-resolve-the-property-from-because-it-is
- .then(async (eventGroup) => {
- if (eventGroup) {
- let events = await Event.find({ eventGroup: eventGroup._id }).lean().sort('start');
- const string = exportIcal(events, eventGroup.name);
- res.set('Content-Type', 'text/calendar');
- return res.send(string);
- }
- })
- .catch((err) => {
- addToLog("eventGroupFeed", "error", "Attempt to display event group feed for " + req.params.eventGroupID + " failed with error: " + err);
- console.log(err)
- res.status(404);
- res.render('404', { url: req.url });
- return;
- });
-});
-
-router.get('/exportevent/:eventID', (req, res) => {
- Event.findOne({
- id: req.params.eventID
- })
- .populate('eventGroup')
- .then((event) => {
- if (event) {
- const string = exportIcal([event]);
- res.send(string);
- }
- })
- .catch((err) => {
- addToLog("exportEvent", "error", "Attempt to export event " + req.params.eventID + " failed with error: " + err);
- console.log(err)
- res.status(404);
- res.render('404', { url: req.url });
- return;
- });
-});
-
-router.get('/exportgroup/:eventGroupID', (req, res) => {
- EventGroup.findOne({
- id: req.params.eventGroupID
- })
- .lean() // Required, see: https://stackoverflow.com/questions/59690923/handlebars-access-has-been-denied-to-resolve-the-property-from-because-it-is
- .then(async (eventGroup) => {
- if (eventGroup) {
- let events = await Event.find({ eventGroup: eventGroup._id }).lean().sort('start');
- const string = exportIcal(events);
- res.send(string);
- }
- })
- .catch((err) => {
- addToLog("exportEvent", "error", "Attempt to export event group " + req.params.eventGroupID + " failed with error: " + err);
- console.log(err)
- res.status(404);
- res.render('404', { url: req.url });
- return;
- });
-});
-
-// BACKEND ROUTES
-
-router.post('/newevent', async (req, res) => {
- let eventID = nanoid();
- let editToken = randomstring.generate();
- let eventImageFilename = "";
- let isPartOfEventGroup = false;
- if (req.files && Object.keys(req.files).length !== 0) {
- let eventImageBuffer = req.files.imageUpload.data;
- eventImageFilename = await Jimp.read(eventImageBuffer)
- .then(img => {
- img
- .resize(920, Jimp.AUTO) // resize
- .quality(80) // set JPEG quality
- .write('./public/events/' + eventID + '.jpg'); // save
- const filename = eventID + '.jpg';
- return filename;
- })
- .catch(err => {
- addToLog("Jimp", "error", "Attempt to edit image failed with error: " + err);
- });
- }
- let startUTC = moment.tz(req.body.eventStart, 'D MMMM YYYY, hh:mm a', req.body.timezone);
- let endUTC = moment.tz(req.body.eventEnd, 'D MMMM YYYY, hh:mm a', req.body.timezone);
- let eventGroup;
- if (req.body.eventGroupCheckbox) {
- eventGroup = await EventGroup.findOne({
- id: req.body.eventGroupID,
- editToken: req.body.eventGroupEditToken
- })
- if (eventGroup) {
- isPartOfEventGroup = true;
- }
- }
-
- // generate RSA keypair for ActivityPub
- let pair = generateRSAKeypair();
-
- const event = new Event({
- id: eventID,
- type: req.body.eventType,
- name: req.body.eventName,
- location: req.body.eventLocation,
- start: startUTC,
- end: endUTC,
- timezone: req.body.timezone,
- description: req.body.eventDescription,
- image: eventImageFilename,
- creatorEmail: req.body.creatorEmail,
- url: req.body.eventURL,
- hostName: req.body.hostName,
- viewPassword: req.body.viewPassword,
- editPassword: req.body.editPassword,
- editToken: editToken,
- eventGroup: isPartOfEventGroup ? eventGroup._id : null,
- usersCanAttend: req.body.joinCheckbox ? true : false,
- showUsersList: req.body.guestlistCheckbox ? true : false,
- usersCanComment: req.body.interactionCheckbox ? true : false,
- maxAttendees: req.body.maxAttendees,
- firstLoad: true,
- activityPubActor: ap.createActivityPubActor(eventID, domain, pair.public, marked.parse(req.body.eventDescription), req.body.eventName, req.body.eventLocation, eventImageFilename, startUTC, endUTC, req.body.timezone),
- activityPubEvent: ap.createActivityPubEvent(req.body.eventName, startUTC, endUTC, req.body.timezone, req.body.eventDescription, req.body.eventLocation),
- activityPubMessages: [{ id: `https://${domain}/${eventID}/m/featuredPost`, content: JSON.stringify(ap.createFeaturedPost(eventID, req.body.eventName, startUTC, endUTC, req.body.timezone, req.body.eventDescription, req.body.eventLocation)) }],
- publicKey: pair.public,
- privateKey: pair.private
- });
- event.save()
- .then((event) => {
- addToLog("createEvent", "success", "Event " + eventID + "created");
- // Send email with edit link
- if (req.body.creatorEmail && sendEmails) {
- req.app.get('hbsInstance').renderView('./views/emails/createevent.handlebars', { eventID, editToken, siteName, siteLogo, domain, cache: true, layout: 'email.handlebars' }, function (err, html) {
- const msg = {
- to: req.body.creatorEmail,
- from: {
- name: siteName,
- email: contactEmail,
- address: contactEmail
- },
- subject: `${siteName}: ${req.body.eventName}`,
- html,
- };
- switch (mailService) {
- case 'sendgrid':
- sgMail.send(msg).catch(e => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- case 'nodemailer':
- nodemailerTransporter.sendMail(msg).catch(e => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- }
- });
- }
- // If the event was added to a group, send an email to any group
- // subscribers
- if (event.eventGroup && sendEmails) {
- EventGroup.findOne({ _id: event.eventGroup._id })
- .then((eventGroup) => {
- const subscribers = eventGroup.subscribers.reduce((acc, current) => {
- if (acc.includes(current.email)) {
- return acc;
- }
- return [current.email, ...acc];
- }, []);
- subscribers.forEach(emailAddress => {
- req.app.get('hbsInstance').renderView('./views/emails/eventgroupupdated.handlebars', { siteName, siteLogo, domain, eventID: req.params.eventID, eventGroupName: eventGroup.name, eventName: event.name, eventID: event.id, eventGroupID: eventGroup.id, emailAddress: encodeURIComponent(emailAddress), cache: true, layout: 'email.handlebars' }, function (err, html) {
- const msg = {
- to: emailAddress,
- from: {
- name: siteName,
- email: contactEmail,
- },
- subject: `${siteName}: New event in ${eventGroup.name}`,
- html,
- };
- switch (mailService) {
- case 'sendgrid':
- sgMail.send(msg).catch(e => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- case 'nodemailer':
- nodemailerTransporter.sendMail(msg).catch(e => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- }
- });
- });
- });
- }
- res.writeHead(302, {
- 'Location': '/' + eventID + '?e=' + editToken
- });
- res.end();
- })
- .catch((err) => { res.status(500).send('Database error, please try again :( - ' + err); addToLog("createEvent", "error", "Attempt to create event failed with error: " + err); });
-});
-
-router.post('/importevent', (req, res) => {
- let eventID = nanoid();
- let editToken = randomstring.generate();
- if (req.files && Object.keys(req.files).length !== 0) {
- let iCalObject = ical.parseICS(req.files.icsImportControl.data.toString('utf8'));
- let importedEventData = iCalObject[Object.keys(iCalObject)];
-
- let creatorEmail;
- if (req.body.creatorEmail) {
- creatorEmail = req.body.creatorEmail;
- } else if (importedEventData.organizer) {
- creatorEmail = importedEventData.organizer.val.replace("MAILTO:", "");
- }
-
- const event = new Event({
- id: eventID,
- type: 'public',
- name: importedEventData.summary,
- location: importedEventData.location,
- start: importedEventData.start,
- end: importedEventData.end,
- timezone: typeof importedEventData.start.tz !== 'undefined' ? importedEventData.start.tz : "Etc/UTC",
- description: importedEventData.description,
- image: '',
- creatorEmail: creatorEmail,
- url: '',
- hostName: importedEventData.organizer ? importedEventData.organizer.params.CN.replace(/["]+/g, '') : "",
- viewPassword: '',
- editPassword: '',
- editToken: editToken,
- usersCanAttend: false,
- showUsersList: false,
- usersCanComment: false,
- firstLoad: true
- });
- event.save()
- .then(() => {
- addToLog("createEvent", "success", "Event " + eventID + " created");
- // Send email with edit link
- if (creatorEmail && sendEmails) {
- req.app.get('hbsInstance').renderView('./views/emails/createevent.handlebars', { eventID, editToken, siteName, siteLogo, domain, cache: true, layout: 'email.handlebars' }, function (err, html) {
- const msg = {
- to: req.body.creatorEmail,
- from: {
- name: siteName,
- email: contactEmail,
- address: contactEmail
- },
- subject: `${siteName}: ${importedEventData.summary}`,
- html,
- };
- switch (mailService) {
- case 'sendgrid':
- sgMail.send(msg).catch(e => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- case 'nodemailer':
- nodemailerTransporter.sendMail(msg).catch(e => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- }
- });
- }
- res.writeHead(302, {
- 'Location': '/' + eventID + '?e=' + editToken
- });
- res.end();
- })
- .catch((err) => { res.send('Database error, please try again :('); addToLog("createEvent", "error", "Attempt to create event failed with error: " + err); });
- }
- else {
- console.log("Files array is empty!")
- res.status(500).end();
- }
-});
-
-router.post('/neweventgroup', (req, res) => {
- let eventGroupID = nanoid();
- let editToken = randomstring.generate();
- let eventGroupImageFilename = "";
- if (req.files && Object.keys(req.files).length !== 0) {
- let eventImageBuffer = req.files.imageUpload.data;
- Jimp.read(eventImageBuffer, (err, img) => {
- if (err) addToLog("Jimp", "error", "Attempt to edit image failed with error: " + err);
- img
- .resize(920, Jimp.AUTO) // resize
- .quality(80) // set JPEG quality
- .write('./public/events/' + eventGroupID + '.jpg'); // save
- });
- eventGroupImageFilename = eventGroupID + '.jpg';
- }
- const eventGroup = new EventGroup({
- id: eventGroupID,
- name: req.body.eventGroupName,
- description: req.body.eventGroupDescription,
- image: eventGroupImageFilename,
- creatorEmail: req.body.creatorEmail,
- url: req.body.eventGroupURL,
- hostName: req.body.hostName,
- editToken: editToken,
- firstLoad: true
- });
- eventGroup.save()
- .then(() => {
- addToLog("createEventGroup", "success", "Event group " + eventGroupID + " created");
- // Send email with edit link
- if (req.body.creatorEmail && sendEmails) {
- req.app.get('hbsInstance').renderView('./views/emails/createeventgroup.handlebars', { eventGroupID, editToken, siteName, siteLogo, domain, cache: true, layout: 'email.handlebars' }, function (err, html) {
- const msg = {
- to: req.body.creatorEmail,
- from: {
- name: siteName,
- email: contactEmail,
- address: contactEmail
- },
- subject: `${siteName}: ${req.body.eventGroupName}`,
- html,
- };
- switch (mailService) {
- case 'sendgrid':
- sgMail.send(msg).catch(e => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- case 'nodemailer':
- nodemailerTransporter.sendMail(msg).catch(e => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- }
- });
- }
- res.writeHead(302, {
- 'Location': '/group/' + eventGroupID + '?e=' + editToken
- });
- res.end();
- })
- .catch((err) => { res.send('Database error, please try again :( - ' + err); addToLog("createEvent", "error", "Attempt to create event failed with error: " + err); });
-});
-
-router.post('/verifytoken/event/:eventID', (req, res) => {
- Event.findOne({
- id: req.params.eventID,
- editToken: req.body.editToken,
- })
- .then(event => {
- if (event) return res.sendStatus(200);
- return res.sendStatus(404);
- })
-});
-
-router.post('/verifytoken/group/:eventGroupID', (req, res) => {
- EventGroup.findOne({
- id: req.params.eventGroupID,
- editToken: req.body.editToken,
- })
- .then(group => {
- if (group) return res.sendStatus(200);
- return res.sendStatus(404);
- })
-});
-
-
-router.post('/editevent/:eventID/:editToken', (req, res) => {
- let submittedEditToken = req.params.editToken;
- Event.findOne(({
- id: req.params.eventID,
- }))
- .then(async (event) => {
- if (event.editToken === submittedEditToken) {
- // Token matches
-
- // If there is a new image, upload that first
- let eventID = req.params.eventID;
- let eventImageFilename = event.image;
- if (req.files && Object.keys(req.files).length !== 0) {
- let eventImageBuffer = req.files.imageUpload.data;
- Jimp.read(eventImageBuffer, (err, img) => {
- if (err) throw err;
- img
- .resize(920, Jimp.AUTO) // resize
- .quality(80) // set JPEG
- .write('./public/events/' + eventID + '.jpg'); // save
- });
- eventImageFilename = eventID + '.jpg';
- }
- let startUTC = moment.tz(req.body.eventStart, 'D MMMM YYYY, hh:mm a', req.body.timezone);
- let endUTC = moment.tz(req.body.eventEnd, 'D MMMM YYYY, hh:mm a', req.body.timezone);
-
- let isPartOfEventGroup = false;
- let eventGroup;
- if (req.body.eventGroupCheckbox) {
- eventGroup = await EventGroup.findOne({
- id: req.body.eventGroupID,
- editToken: req.body.eventGroupEditToken
- })
- if (eventGroup) {
- isPartOfEventGroup = true;
- }
- }
- const updatedEvent = {
- name: req.body.eventName,
- location: req.body.eventLocation,
- start: startUTC,
- end: endUTC,
- timezone: req.body.timezone,
- description: req.body.eventDescription,
- url: req.body.eventURL,
- hostName: req.body.hostName,
- image: eventImageFilename,
- usersCanAttend: req.body.joinCheckbox ? true : false,
- showUsersList: req.body.guestlistCheckbox ? true : false,
- usersCanComment: req.body.interactionCheckbox ? true : false,
- maxAttendees: req.body.maxAttendeesCheckbox ? req.body.maxAttendees : null,
- eventGroup: isPartOfEventGroup ? eventGroup._id : null,
- activityPubActor: event.activityPubActor ? ap.updateActivityPubActor(JSON.parse(event.activityPubActor), req.body.eventDescription, req.body.eventName, req.body.eventLocation, eventImageFilename, startUTC, endUTC, req.body.timezone) : null,
- activityPubEvent: event.activityPubEvent ? ap.updateActivityPubEvent(JSON.parse(event.activityPubEvent), req.body.eventName, req.body.startUTC, req.body.endUTC, req.body.timezone) : null,
- }
- let diffText = '<p>This event was just updated with new information.</p><ul>';
- let displayDate;
- if (event.name !== updatedEvent.name) {
- diffText += `<li>the event name changed to ${updatedEvent.name}</li>`;
- }
- if (event.location !== updatedEvent.location) {
- diffText += `<li>the location changed to ${updatedEvent.location}</li>`;
- }
- if (event.start.toISOString() !== updatedEvent.start.toISOString()) {
- displayDate = moment.tz(updatedEvent.start, updatedEvent.timezone).format('dddd D MMMM YYYY h:mm a');
- diffText += `<li>the start time changed to ${displayDate}</li>`;
- }
- if (event.end.toISOString() !== updatedEvent.end.toISOString()) {
- displayDate = moment.tz(updatedEvent.end, updatedEvent.timezone).format('dddd D MMMM YYYY h:mm a');
- diffText += `<li>the end time changed to ${displayDate}</li>`;
- }
- if (event.timezone !== updatedEvent.timezone) {
- diffText += `<li>the time zone changed to ${updatedEvent.timezone}</li>`;
- }
- if (event.description !== updatedEvent.description) {
- diffText += `<li>the event description changed</li>`;
- }
- diffText += `</ul>`;
- Event.findOneAndUpdate({ id: req.params.eventID }, updatedEvent, function (err, raw) {
- if (err) {
- addToLog("editEvent", "error", "Attempt to edit event " + req.params.eventID + " failed with error: " + err);
- res.send(err);
- }
- })
- .then(() => {
- addToLog("editEvent", "success", "Event " + req.params.eventID + " edited");
- // send update to ActivityPub subscribers
- Event.findOne({ id: req.params.eventID }, function (err, event) {
- if (!event) return;
- let attendees = event.attendees.filter(el => el.id);
- if (!err) {
- // broadcast an identical message to all followers, will show in home timeline
- const guidObject = crypto.randomBytes(16).toString('hex');
- const jsonObject = {
- "@context": "https://www.w3.org/ns/activitystreams",
- "id": `https://${domain}/${req.params.eventID}/m/${guidObject}`,
- "name": `RSVP to ${event.name}`,
- "type": "Note",
- 'cc': 'https://www.w3.org/ns/activitystreams#Public',
- "content": `${diffText} See here: <a href="https://${domain}/${req.params.eventID}">https://${domain}/${req.params.eventID}</a>`,
- }
- ap.broadcastCreateMessage(jsonObject, event.followers, eventID)
- // also broadcast an Update profile message to all followers so that at least Mastodon servers will update the local profile information
- const jsonUpdateObject = JSON.parse(event.activityPubActor);
- ap.broadcastUpdateMessage(jsonUpdateObject, event.followers, eventID)
- // also broadcast an Update/Event for any calendar apps that are consuming our Events
- const jsonEventObject = JSON.parse(event.activityPubEvent);
- ap.broadcastUpdateMessage(jsonEventObject, event.followers, eventID)
-
- // DM to attendees
- for (const attendee of attendees) {
- const jsonObject = {
- "@context": "https://www.w3.org/ns/activitystreams",
- "name": `RSVP to ${event.name}`,
- "type": "Note",
- "content": `<span class=\"h-card\"><a href="${attendee.id}" class="u-url mention">@<span>${attendee.name}</span></a></span> ${diffText} See here: <a href="https://${domain}/${req.params.eventID}">https://${domain}/${req.params.eventID}</a>`,
- "tag": [{ "type": "Mention", "href": attendee.id, "name": attendee.name }]
- }
- // send direct message to user
- ap.sendDirectMessage(jsonObject, attendee.id, eventID);
- }
- }
- })
- // Send update to all attendees
- if (sendEmails) {
- Event.findOne({ id: req.params.eventID }).then((event) => {
- const attendeeEmails = event.attendees.filter(o => o.status === 'attending' && o.email).map(o => o.email);
- if (attendeeEmails.length) {
- console.log("Sending emails to: " + attendeeEmails);
- req.app.get('hbsInstance').renderView('./views/emails/editevent.handlebars', { diffText, eventID: req.params.eventID, siteName, siteLogo, domain, cache: true, layout: 'email.handlebars' }, function (err, html) {
- const msg = {
- to: attendeeEmails,
- from: {
- name: siteName,
- email: contactEmail,
- address: contactEmail
- },
- subject: `${siteName}: ${event.name} was just edited`,
- html,
- };
- switch (mailService) {
- case 'sendgrid':
- sgMail.sendMultiple(msg).catch(e => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- case 'nodemailer':
- nodemailerTransporter.sendMail(msg).catch(e => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- }
- });
- }
- else {
- console.log("Nothing to send!");
- }
- })
- }
- res.writeHead(302, {
- 'Location': '/' + req.params.eventID + '?e=' + req.params.editToken
- });
- res.end();
- })
- .catch((err) => { console.error(err); res.send('Sorry! Something went wrong!'); addToLog("editEvent", "error", "Attempt to edit event " + req.params.eventID + " failed with error: " + err); });
- }
- else {
- // Token doesn't match
- res.send('Sorry! Something went wrong');
- addToLog("editEvent", "error", "Attempt to edit event " + req.params.eventID + " failed with error: token does not match");
- }
- })
- .catch((err) => { console.error(err); res.send('Sorry! Something went wrong!'); addToLog("editEvent", "error", "Attempt to edit event " + req.params.eventID + " failed with error: " + err); });
-});
-
-router.post('/editeventgroup/:eventGroupID/:editToken', (req, res) => {
- let submittedEditToken = req.params.editToken;
- EventGroup.findOne(({
- id: req.params.eventGroupID,
- }))
- .then((eventGroup) => {
- if (eventGroup.editToken === submittedEditToken) {
- // Token matches
-
- // If there is a new image, upload that first
- let eventGroupID = req.params.eventGroupID;
- let eventGroupImageFilename = eventGroup.image;
- if (req.files && Object.keys(req.files).length !== 0) {
- let eventImageBuffer = req.files.eventGroupImageUpload.data;
- Jimp.read(eventImageBuffer, (err, img) => {
- if (err) throw err;
- img
- .resize(920, Jimp.AUTO) // resize
- .quality(80) // set JPEG
- .write('./public/events/' + eventGroupID + '.jpg'); // save
- });
- eventGroupImageFilename = eventGroupID + '.jpg';
- }
- const updatedEventGroup = {
- name: req.body.eventGroupName,
- description: req.body.eventGroupDescription,
- url: req.body.eventGroupURL,
- hostName: req.body.hostName,
- image: eventGroupImageFilename
- }
- EventGroup.findOneAndUpdate({ id: req.params.eventGroupID }, updatedEventGroup, function (err, raw) {
- if (err) {
- addToLog("editEventGroup", "error", "Attempt to edit event group " + req.params.eventGroupID + " failed with error: " + err);
- res.send(err);
- }
- })
- .then(() => {
- addToLog("editEventGroup", "success", "Event group " + req.params.eventGroupID + " edited");
- res.writeHead(302, {
- 'Location': '/group/' + req.params.eventGroupID + '?e=' + req.params.editToken
- });
- res.end();
- })
- .catch((err) => { console.error(err); res.send('Sorry! Something went wrong!'); addToLog("editEventGroup", "error", "Attempt to edit event group " + req.params.eventGroupID + " failed with error: " + err); });
- }
- else {
- // Token doesn't match
- res.send('Sorry! Something went wrong');
- addToLog("editEventGroup", "error", "Attempt to edit event group " + req.params.eventGroupID + " failed with error: token does not match");
- }
- })
- .catch((err) => { console.error(err); res.send('Sorry! Something went wrong!'); addToLog("editEventGroup", "error", "Attempt to edit event group " + req.params.eventGroupID + " failed with error: " + err); });
-});
-
-router.post('/deleteimage/:eventID/:editToken', (req, res) => {
- let submittedEditToken = req.params.editToken;
- Event.findOne(({
- id: req.params.eventID,
- }))
- .then((event) => {
- if (event.editToken === submittedEditToken) {
- // Token matches
- if (event.image) {
- eventImage = event.image;
- } else {
- res.status(500).send('This event doesn\'t have a linked image. What are you even doing');
- }
- fs.unlink(global.appRoot + '/public/events/' + eventImage, (err) => {
- if (err) {
- res.status(500).send(err);
- addToLog("deleteEventImage", "error", "Attempt to delete event image for event " + req.params.eventID + " failed with error: " + err);
- }
- // Image removed
- addToLog("deleteEventImage", "success", "Image for event " + req.params.eventID + " deleted");
- event.image = "";
- event.save()
- .then(response => {
- res.status(200).send('Success');
- })
- .catch(err => {
- res.status(500).send(err);
- addToLog("deleteEventImage", "error", "Attempt to delete event image for event " + req.params.eventID + " failed with error: " + err);
- })
- });
- }
- });
-});
-
-router.post('/deleteevent/:eventID/:editToken', (req, res) => {
- let submittedEditToken = req.params.editToken;
- let eventImage;
- Event.findOne(({
- id: req.params.eventID,
- }))
- .then((event) => {
- if (event.editToken === submittedEditToken) {
- // Token matches
-
- let eventImage;
- if (event.image) {
- eventImage = event.image;
- }
-
- // broadcast a Delete profile message to all followers so that at least Mastodon servers will delete their local profile information
- const guidUpdateObject = crypto.randomBytes(16).toString('hex');
- const jsonUpdateObject = JSON.parse(event.activityPubActor);
- // first broadcast AP messages, THEN delete from DB
- ap.broadcastDeleteMessage(jsonUpdateObject, event.followers, req.params.eventID, function (statuses) {
- Event.deleteOne({ id: req.params.eventID }, function (err, raw) {
- if (err) {
- res.send(err);
- addToLog("deleteEvent", "error", "Attempt to delete event " + req.params.eventID + " failed with error: " + err);
- }
- })
- .then(() => {
- // Delete image
- if (eventImage) {
- fs.unlink(global.appRoot + '/public/events/' + eventImage, (err) => {
- if (err) {
- res.send(err);
- addToLog("deleteEvent", "error", "Attempt to delete event image for event " + req.params.eventID + " failed with error: " + err);
- }
- // Image removed
- addToLog("deleteEvent", "success", "Event " + req.params.eventID + " deleted");
- })
- }
- res.writeHead(302, {
- 'Location': '/'
- });
- res.end();
-
- // Send emails here otherwise they don't exist lol
- if (sendEmails) {
- const attendeeEmails = event.attendees.filter(o => o.status === 'attending' && o.email).map(o => o.email);
- if (attendeeEmails.length) {
- console.log("Sending emails to: " + attendeeEmails);
- req.app.get('hbsInstance').renderView('./views/emails/deleteevent.handlebars', { siteName, siteLogo, domain, eventName: event.name, cache: true, layout: 'email.handlebars' }, function (err, html) {
- const msg = {
- to: attendeeEmails,
- from: {
- name: siteName,
- email: contactEmail,
- address: contactEmail
- },
- subject: `${siteName}: ${event.name} was deleted`,
- html,
- };
- switch (mailService) {
- case 'sendgrid':
- sgMail.sendMultiple(msg).catch(e => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- case 'nodemailer':
- nodemailerTransporter.sendMail(msg).catch(e => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- }
- });
- }
- else {
- console.log("Nothing to send!");
- }
- }
- })
- .catch((err) => { res.send('Sorry! Something went wrong (error deleting): ' + err); addToLog("deleteEvent", "error", "Attempt to delete event " + req.params.eventID + " failed with error: " + err); });
- });
- }
- else {
- // Token doesn't match
- res.send('Sorry! Something went wrong');
- addToLog("deleteEvent", "error", "Attempt to delete event " + req.params.eventID + " failed with error: token does not match");
- }
- })
- .catch((err) => { res.send('Sorry! Something went wrong: ' + err); addToLog("deleteEvent", "error", "Attempt to delete event " + req.params.eventID + " failed with error: " + err); });
-});
-
-router.post('/deleteeventgroup/:eventGroupID/:editToken', (req, res) => {
- let submittedEditToken = req.params.editToken;
- EventGroup.findOne(({
- id: req.params.eventGroupID,
- }))
- .then(async (eventGroup) => {
- if (eventGroup.editToken === submittedEditToken) {
- // Token matches
-
- let linkedEvents = await Event.find({ eventGroup: eventGroup._id });
-
- let linkedEventIDs = linkedEvents.map(event => event._id);
- let eventGroupImage = false;
- if (eventGroup.image) {
- eventGroupImage = eventGroup.image;
- }
-
- EventGroup.deleteOne({ id: req.params.eventGroupID }, function (err, raw) {
- if (err) {
- res.send(err);
- addToLog("deleteEventGroup", "error", "Attempt to delete event group " + req.params.eventGroupID + " failed with error: " + err);
- }
- })
- .then(() => {
- // Delete image
- if (eventGroupImage) {
- fs.unlink(global.appRoot + '/public/events/' + eventGroupImage, (err) => {
- if (err) {
- res.send(err);
- addToLog("deleteEventGroup", "error", "Attempt to delete event image for event group " + req.params.eventGroupID + " failed with error: " + err);
- }
- })
- }
- Event.update({ _id: { $in: linkedEventIDs } }, { $set: { eventGroup: null } }, { multi: true })
- .then(response => {
- console.log(response);
- addToLog("deleteEventGroup", "success", "Event group " + req.params.eventGroupID + " deleted");
- res.writeHead(302, {
- 'Location': '/'
- });
- res.end();
- })
- .catch((err) => { res.send('Sorry! Something went wrong (error deleting): ' + err); addToLog("deleteEventGroup", "error", "Attempt to delete event group " + req.params.eventGroupID + " failed with error: " + err); });
- })
- .catch((err) => { res.send('Sorry! Something went wrong (error deleting): ' + err); addToLog("deleteEventGroup", "error", "Attempt to delete event group " + req.params.eventGroupID + " failed with error: " + err); });
- }
- else {
- // Token doesn't match
- res.send('Sorry! Something went wrong');
- addToLog("deleteEventGroup", "error", "Attempt to delete event group " + req.params.eventGroupID + " failed with error: token does not match");
- }
- })
- .catch((err) => { res.send('Sorry! Something went wrong: ' + err); addToLog("deleteEventGroup", "error", "Attempt to delete event group " + req.params.eventGroupID + " failed with error: " + err); });
-});
-
-router.post('/attendee/provision', async (req, res) => {
- const removalPassword = niceware.generatePassphrase(6).join('-');
- const newAttendee = {
- status: 'provisioned',
- removalPassword,
- created: Date.now(),
- };
-
- const event = await Event.findOne({ id: req.query.eventID }).catch(e => {
- addToLog("provisionEventAttendee", "error", "Attempt to provision attendee in event " + req.query.eventID + " failed with error: " + e);
- return res.sendStatus(500);
- });
-
- if (!event) {
- return res.sendStatus(404);
- }
-
- event.attendees.push(newAttendee);
- await event.save().catch(e => {
- console.log(e);
- addToLog("provisionEventAttendee", "error", "Attempt to provision attendee in event " + req.query.eventID + " failed with error: " + e);
- return res.sendStatus(500);
- });
- addToLog("provisionEventAttendee", "success", "Attendee provisioned in event " + req.query.eventID);
-
- // Return the removal password and the number of free spots remaining
- let freeSpots;
- if (event.maxAttendees !== null && event.maxAttendees !== undefined) {
- freeSpots = event.maxAttendees - event.attendees.reduce((acc, a) => acc + (a.status === 'attending' ? (a.number || 1) : 0), 0);
- } else {
- freeSpots = undefined;
- }
- return res.json({ removalPassword, freeSpots });
-});
-
-router.post('/attendevent/:eventID', async (req, res) => {
- // Do not allow empty removal passwords
- if (!req.body.removalPassword) {
- return res.sendStatus(500);
- }
- const event = await Event.findOne({ id: req.params.eventID }).catch(e => {
- addToLog("attendEvent", "error", "Attempt to attend event " + req.params.eventID + " failed with error: " + e);
- return res.sendStatus(500);
- });
- if (!event) {
- return res.sendStatus(404);
- }
- const attendee = event.attendees.find(a => a.removalPassword === req.body.removalPassword);
- if (!attendee) {
- return res.sendStatus(404);
- }
- // Do we have enough free spots in this event to accomodate this attendee?
- // First, check if the event has a max number of attendees
- if (event.maxAttendees !== null && event.maxAttendees !== undefined) {
- const freeSpots = event.maxAttendees - event.attendees.reduce((acc, a) => acc + (a.status === 'attending' ? (a.number || 1) : 0), 0);
- if (req.body.attendeeNumber > freeSpots) {
- return res.sendStatus(403);
- }
- }
-
- Event.findOneAndUpdate({ id: req.params.eventID, 'attendees.removalPassword': req.body.removalPassword }, {
- "$set": {
- "attendees.$.status": "attending",
- "attendees.$.name": req.body.attendeeName,
- "attendees.$.email": req.body.attendeeEmail,
- "attendees.$.number": req.body.attendeeNumber,
- }
- }).then((event) => {
- addToLog("addEventAttendee", "success", "Attendee added to event " + req.params.eventID);
- if (sendEmails) {
- if (req.body.attendeeEmail) {
- req.app.get('hbsInstance').renderView('./views/emails/addeventattendee.handlebars', { eventID: req.params.eventID, siteName, siteLogo, domain, removalPassword: req.body.removalPassword, cache: true, layout: 'email.handlebars' }, function (err, html) {
- const msg = {
- to: req.body.attendeeEmail,
- from: {
- name: siteName,
- email: contactEmail,
- },
- subject: `${siteName}: You're RSVPed to ${event.name}`,
- html,
- };
- switch (mailService) {
- case 'sendgrid':
- sgMail.send(msg).catch(e => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- case 'nodemailer':
- nodemailerTransporter.sendMail(msg).catch(e => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- }
- });
- }
- }
- res.redirect(`/${req.params.eventID}`);
- })
- .catch((error) => {
- res.send('Database error, please try again :(');
- addToLog("addEventAttendee", "error", "Attempt to add attendee to event " + req.params.eventID + " failed with error: " + error);
- });
-});
-
-router.post('/unattendevent/:eventID', (req, res) => {
- const removalPassword = req.body.removalPassword;
- // Don't allow blank removal passwords!
- if (!removalPassword) {
- return res.sendStatus(500);
- }
-
- Event.update(
- { id: req.params.eventID },
- { $pull: { attendees: { removalPassword } } }
- )
- .then(response => {
- console.log(response)
- addToLog("unattendEvent", "success", "Attendee removed self from event " + req.params.eventID);
- if (sendEmails) {
- if (req.body.attendeeEmail) {
- req.app.get('hbsInstance').renderView('./views/emails/unattendevent.handlebars', { eventID: req.params.eventID, siteName, siteLogo, domain, cache: true, layout: 'email.handlebars' }, function (err, html) {
- const msg = {
- to: req.body.attendeeEmail,
- from: {
- name: siteName,
- email: contactEmail,
- },
- subject: `${siteName}: You have been removed from an event`,
- html,
- };
- switch (mailService) {
- case 'sendgrid':
- sgMail.send(msg).catch(e => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- case 'nodemailer':
- nodemailerTransporter.sendMail(msg).catch(e => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- }
- });
- }
- }
- res.writeHead(302, {
- 'Location': '/' + req.params.eventID
- });
- res.end();
- })
- .catch((err) => {
- res.send('Database error, please try again :('); addToLog("removeEventAttendee", "error", "Attempt to remove attendee from event " + req.params.eventID + " failed with error: " + err);
- });
-});
-
-// this is a one-click unattend that requires a secret URL that only the person who RSVPed over
-// activitypub knows
-router.get('/oneclickunattendevent/:eventID/:attendeeID', (req, res) => {
- // Mastodon will "click" links that sent to its users, presumably as a prefetch?
- // Anyway, this ignores the automated clicks that are done without the user's knowledge
- if (req.headers['user-agent'] && req.headers['user-agent'].includes('Mastodon')) {
- return res.sendStatus(200);
- }
- Event.update(
- { id: req.params.eventID },
- { $pull: { attendees: { _id: req.params.attendeeID } } }
- )
- .then(response => {
- addToLog("oneClickUnattend", "success", "Attendee removed via one click unattend " + req.params.eventID);
- if (sendEmails) {
- // currently this is never called because we don't have the email address
- if (req.body.attendeeEmail) {
- req.app.get('hbsInstance').renderView('./views/emails/removeeventattendee.handlebars', { eventName: req.params.eventName, siteName, domain, cache: true, layout: 'email.handlebars' }, function (err, html) {
- const msg = {
- to: req.body.attendeeEmail,
- from: {
- name: siteName,
- email: contactEmail,
- },
- subject: `${siteName}: You have been removed from an event`,
- html,
- };
- switch (mailService) {
- case 'sendgrid':
- sgMail.send(msg).catch(e => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- case 'nodemailer':
- nodemailerTransporter.sendMail(msg).catch(e => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- }
- });
- }
- }
- res.writeHead(302, {
- 'Location': '/' + req.params.eventID
- });
- res.end();
- })
- .catch((err) => {
- res.send('Database error, please try again :('); addToLog("removeEventAttendee", "error", "Attempt to remove attendee by admin from event " + req.params.eventID + " failed with error: " + err);
- });
-});
-
-router.post('/removeattendee/:eventID/:attendeeID', (req, res) => {
- Event.update(
- { id: req.params.eventID },
- { $pull: { attendees: { _id: req.params.attendeeID } } }
- )
- .then(response => {
- console.log(response)
- addToLog("removeEventAttendee", "success", "Attendee removed by admin from event " + req.params.eventID);
- if (sendEmails) {
- // currently this is never called because we don't have the email address
- if (req.body.attendeeEmail) {
- req.app.get('hbsInstance').renderView('./views/emails/removeeventattendee.handlebars', { eventName: req.params.eventName, siteName, siteLogo, domain, cache: true, layout: 'email.handlebars' }, function (err, html) {
- const msg = {
- to: req.body.attendeeEmail,
- from: {
- name: siteName,
- email: contactEmail,
- },
- subject: `${siteName}: You have been removed from an event`,
- html,
- };
- switch (mailService) {
- case 'sendgrid':
- sgMail.send(msg).catch(e => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- case 'nodemailer':
- nodemailerTransporter.sendMail(msg).catch(e => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- }
- });
- }
- }
- res.writeHead(302, {
- 'Location': '/' + req.params.eventID
- });
- res.end();
- })
- .catch((err) => {
- res.send('Database error, please try again :('); addToLog("removeEventAttendee", "error", "Attempt to remove attendee by admin from event " + req.params.eventID + " failed with error: " + err);
- });
-});
-
-/*
- * Create an email subscription on an event group.
- */
-router.post('/subscribe/:eventGroupID', (req, res) => {
- const subscriber = {
- email: req.body.emailAddress,
- };
- if (!subscriber.email) {
- return res.sendStatus(500);
- }
-
- EventGroup.findOne(({
- id: req.params.eventGroupID,
- }))
- .then((eventGroup) => {
- if (!eventGroup) {
- return res.sendStatus(404);
- }
- eventGroup.subscribers.push(subscriber);
- eventGroup.save();
- if (sendEmails) {
- req.app.get('hbsInstance').renderView('./views/emails/subscribed.handlebars', { eventGroupName: eventGroup.name, eventGroupID: eventGroup.id, emailAddress: encodeURIComponent(subscriber.email), siteName, siteLogo, domain, cache: true, layout: 'email.handlebars' }, function (err, html) {
- const msg = {
- to: subscriber.email,
- from: {
- name: siteName,
- email: contactEmail,
- },
- subject: `${siteName}: You have subscribed to an event group`,
- html,
- };
- switch (mailService) {
- case 'sendgrid':
- sgMail.send(msg).catch(e => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- case 'nodemailer':
- nodemailerTransporter.sendMail(msg).catch(e => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- }
- });
- }
- return res.redirect(`/group/${eventGroup.id}`)
- })
- .catch((error) => {
- addToLog("addSubscription", "error", "Attempt to subscribe " + req.body.emailAddress + " to event group " + req.params.eventGroupID + " failed with error: " + error);
- return res.sendStatus(500);
- });
-});
-
-/*
- * Delete an existing email subscription on an event group.
- */
-router.get('/unsubscribe/:eventGroupID', (req, res) => {
- const email = req.query.email;
- console.log(email);
- if (!email) {
- return res.sendStatus(500);
- }
-
- EventGroup.update(
- { id: req.params.eventGroupID },
- { $pull: { subscribers: { email } } }
- )
- .then(response => {
- return res.redirect('/');
- })
- .catch((error) => {
- addToLog("removeSubscription", "error", "Attempt to unsubscribe " + req.query.email + " from event group " + req.params.eventGroupID + " failed with error: " + error);
- return res.sendStatus(500);
- });
-});
-
-router.post('/post/comment/:eventID', (req, res) => {
- let commentID = nanoid();
- const newComment = {
- id: commentID,
- author: req.body.commentAuthor,
- content: req.body.commentContent,
- timestamp: moment()
- };
-
- Event.findOne({
- id: req.params.eventID,
- }, function (err, event) {
- if (!event) return;
- event.comments.push(newComment);
- event.save()
- .then(() => {
- addToLog("addEventComment", "success", "Comment added to event " + req.params.eventID);
- // broadcast an identical message to all followers, will show in their home timeline
- // and in the home timeline of the event
- const guidObject = crypto.randomBytes(16).toString('hex');
- const jsonObject = {
- "@context": "https://www.w3.org/ns/activitystreams",
- "id": `https://${domain}/${req.params.eventID}/m/${guidObject}`,
- "name": `Comment on ${event.name}`,
- "type": "Note",
- 'cc': 'https://www.w3.org/ns/activitystreams#Public',
- "content": `<p>${req.body.commentAuthor} commented: ${req.body.commentContent}.</p><p><a href="https://${domain}/${req.params.eventID}/">See the full conversation here.</a></p>`,
- }
- ap.broadcastCreateMessage(jsonObject, event.followers, req.params.eventID)
- if (sendEmails) {
- Event.findOne({ id: req.params.eventID }).then((event) => {
- const attendeeEmails = event.attendees.filter(o => o.status === 'attending' && o.email).map(o => o.email);
- if (attendeeEmails.length) {
- console.log("Sending emails to: " + attendeeEmails);
- req.app.get('hbsInstance').renderView('./views/emails/addeventcomment.handlebars', { siteName, siteLogo, domain, eventID: req.params.eventID, commentAuthor: req.body.commentAuthor, cache: true, layout: 'email.handlebars' }, function (err, html) {
- const msg = {
- to: attendeeEmails,
- from: {
- name: siteName,
- email: contactEmail,
- },
- subject: `${siteName}: New comment in ${event.name}`,
- html,
- };
- switch (mailService) {
- case 'sendgrid':
- sgMail.sendMultiple(msg).catch(e => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- case 'nodemailer':
- nodemailerTransporter.sendMail(msg).catch(e => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- }
- });
- }
- else {
- console.log("Nothing to send!");
- }
- });
- }
- res.writeHead(302, {
- 'Location': '/' + req.params.eventID
- });
- res.end();
- })
- .catch((err) => { res.send('Database error, please try again :(' + err); addToLog("addEventComment", "error", "Attempt to add comment to event " + req.params.eventID + " failed with error: " + err); });
- });
-});
-
-router.post('/post/reply/:eventID/:commentID', (req, res) => {
- let replyID = nanoid();
- let commentID = req.params.commentID;
- const newReply = {
- id: replyID,
- author: req.body.replyAuthor,
- content: req.body.replyContent,
- timestamp: moment()
- };
- Event.findOne({
- id: req.params.eventID,
- }, function (err, event) {
- if (!event) return;
- var parentComment = event.comments.id(commentID);
- parentComment.replies.push(newReply);
- event.save()
- .then(() => {
- addToLog("addEventReply", "success", "Reply added to comment " + commentID + " in event " + req.params.eventID);
- // broadcast an identical message to all followers, will show in their home timeline
- const guidObject = crypto.randomBytes(16).toString('hex');
- const jsonObject = {
- "@context": "https://www.w3.org/ns/activitystreams",
- "id": `https://${domain}/${req.params.eventID}/m/${guidObject}`,
- "name": `Comment on ${event.name}`,
- "type": "Note",
- 'cc': 'https://www.w3.org/ns/activitystreams#Public',
- "content": `<p>${req.body.replyAuthor} commented: ${req.body.replyContent}</p><p><a href="https://${domain}/${req.params.eventID}/">See the full conversation here.</a></p>`,
- }
- ap.broadcastCreateMessage(jsonObject, event.followers, req.params.eventID)
- if (sendEmails) {
- Event.findOne({ id: req.params.eventID }).then((event) => {
- const attendeeEmails = event.attendees.filter(o => o.status === 'attending' && o.email).map(o => o.email);
- if (attendeeEmails.length) {
- console.log("Sending emails to: " + attendeeEmails);
- req.app.get('hbsInstance').renderView('./views/emails/addeventcomment.handlebars', { siteName, siteLogo, domain, eventID: req.params.eventID, commentAuthor: req.body.replyAuthor, cache: true, layout: 'email.handlebars' }, function (err, html) {
- const msg = {
- to: attendeeEmails,
- from: {
- name: siteName,
- email: contactEmail,
- },
- subject: `${siteName}: New comment in ${event.name}`,
- html,
- };
- switch (mailService) {
- case 'sendgrid':
- sgMail.sendMultiple(msg).catch(e => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- case 'nodemailer':
- nodemailerTransporter.sendMail(msg).catch(e => {
- console.error(e.toString());
- res.status(500).end();
- });
- break;
- }
- });
- }
- else {
- console.log("Nothing to send!");
- }
- });
- }
- res.writeHead(302, {
- 'Location': '/' + req.params.eventID
- });
- res.end();
- })
- .catch((err) => { res.send('Database error, please try again :('); addToLog("addEventReply", "error", "Attempt to add reply to comment " + commentID + " in event " + req.params.eventID + " failed with error: " + err); });
- });
-});
-
-router.post('/deletecomment/:eventID/:commentID/:editToken', (req, res) => {
- let submittedEditToken = req.params.editToken;
- Event.findOne(({
- id: req.params.eventID,
- }))
- .then((event) => {
- if (event.editToken === submittedEditToken) {
- // Token matches
- event.comments.id(req.params.commentID).remove();
- event.save()
- .then(() => {
- addToLog("deleteComment", "success", "Comment deleted from event " + req.params.eventID);
- res.writeHead(302, {
- 'Location': '/' + req.params.eventID + '?e=' + req.params.editToken
- });
- res.end();
- })
- .catch((err) => { res.send('Sorry! Something went wrong (error deleting): ' + err); addToLog("deleteComment", "error", "Attempt to delete comment " + req.params.commentID + "from event " + req.params.eventID + " failed with error: " + err); });
- }
- else {
- // Token doesn't match
- res.send('Sorry! Something went wrong');
- addToLog("deleteComment", "error", "Attempt to delete comment " + req.params.commentID + "from event " + req.params.eventID + " failed with error: token does not match");
- }
- })
- .catch((err) => { res.send('Sorry! Something went wrong: ' + err); addToLog("deleteComment", "error", "Attempt to delete comment " + req.params.commentID + "from event " + req.params.eventID + " failed with error: " + err); });
-});
-
-router.post('/activitypub/inbox', (req, res) => {
- if (!isFederated) return res.sendStatus(404);
- // validate the incoming message
- const signature = req.get('Signature');
- let signature_header = signature.split(',').map(pair => {
- return pair.split('=').map(value => {
- return value.replace(/^"/g, '').replace(/"$/g, '')
- });
- }).reduce((acc, el) => {
- acc[el[0]] = el[1];
- return acc;
- }, {});
-
- // get the actor
- // TODO if this is a Delete for an Actor this won't work
- request({
- url: signature_header.keyId,
- headers: {
- 'Accept': 'application/activity+json',
- 'Content-Type': 'application/activity+json'
- }
- }, function (error, response, actor) {
- let publicKey = '';
-
- try {
- if (JSON.parse(actor).publicKey) {
- publicKey = JSON.parse(actor).publicKey.publicKeyPem;
- }
- }
- catch (err) {
- return res.status(500).send('Actor could not be parsed' + err);
- }
-
- let comparison_string = signature_header.headers.split(' ').map(header => {
- if (header === '(request-target)') {
- return '(request-target): post /activitypub/inbox';
- }
- else {
- return `${header}: ${req.get(header)}`
- }
- }).join('\n');
-
- const verifier = crypto.createVerify('RSA-SHA256')
- verifier.update(comparison_string, 'ascii')
- const publicKeyBuf = new Buffer(publicKey, 'ascii')
- const signatureBuf = new Buffer(signature_header.signature, 'base64')
- try {
- const result = verifier.verify(publicKeyBuf, signatureBuf)
- if (result) {
- // actually process the ActivityPub message now that it's been verified
- ap.processInbox(req, res);
- }
- else {
- return res.status(401).send('Signature could not be verified.');
- }
- }
- catch (err) {
- return res.status(401).send('Signature could not be verified: ' + err);
- }
- });
-});
-
-router.use(function (req, res, next) {
- res.status(404);
- res.render('404', { url: req.url });
- return;
-});
-
-addToLog("startup", "success", "Started up successfully");
-
-module.exports = router;
diff --git a/src/activitypub.js b/src/activitypub.js
new file mode 100644
index 0000000..c8fc682
--- /dev/null
+++ b/src/activitypub.js
@@ -0,0 +1,1283 @@
+const domain = require("./config/domain.js").domain;
+const contactEmail = require("./config/domain.js").email;
+const siteName = require("./config/domain.js").sitename;
+const isFederated = require("./config/domain.js").isFederated;
+const request = require("request");
+const addToLog = require("./helpers.js").addToLog;
+const crypto = require("crypto");
+// This alphabet (used to generate all event, group, etc. IDs) is missing '-'
+// because ActivityPub doesn't like it in IDs
+const { customAlphabet } = require("nanoid");
+const nanoid = customAlphabet(
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_",
+ 21
+);
+var moment = require("moment-timezone");
+const mongoose = require("mongoose");
+const Event = mongoose.model("Event");
+const EventGroup = mongoose.model("EventGroup");
+var sanitizeHtml = require("sanitize-html");
+
+function createActivityPubActor(
+ eventID,
+ domain,
+ pubkey,
+ description,
+ name,
+ location,
+ imageFilename,
+ startUTC,
+ endUTC,
+ timezone
+) {
+ let actor = {
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1",
+ ],
+
+ id: `https://${domain}/${eventID}`,
+ type: "Person",
+ preferredUsername: `${eventID}`,
+ inbox: `https://${domain}/activitypub/inbox`,
+ outbox: `https://${domain}/${eventID}/outbox`,
+ followers: `https://${domain}/${eventID}/followers`,
+ summary: `<p>${description}</p>`,
+ name: name,
+ featured: `https://${domain}/${eventID}/featured`,
+
+ publicKey: {
+ id: `https://${domain}/${eventID}#main-key`,
+ owner: `https://${domain}/${eventID}`,
+ publicKeyPem: pubkey,
+ },
+ };
+ if (location) {
+ actor.summary += `<p>Location: ${location}.</p>`;
+ }
+ let displayDate;
+ if (startUTC && timezone) {
+ displayDate = moment.tz(startUTC, timezone).format("D MMMM YYYY h:mm a");
+ actor.summary += `<p>Starting ${displayDate} ${timezone}.</p>`;
+ }
+ if (imageFilename) {
+ actor.icon = {
+ type: "Image",
+ mediaType: "image/jpg",
+ url: `https://${domain}/events/${imageFilename}`,
+ };
+ }
+ return JSON.stringify(actor);
+}
+
+function createActivityPubEvent(
+ name,
+ startUTC,
+ endUTC,
+ timezone,
+ description,
+ location
+) {
+ const guid = crypto.randomBytes(16).toString("hex");
+ let eventObject = {
+ "@context": "https://www.w3.org/ns/activitystreams",
+ id: `https://${domain}/${guid}`,
+ name: name,
+ type: "Event",
+ startTime: moment.tz(startUTC, timezone).format(),
+ endTime: moment.tz(endUTC, timezone).format(),
+ content: description,
+ location: location,
+ };
+ return JSON.stringify(eventObject);
+}
+
+function createFeaturedPost(
+ eventID,
+ name,
+ startUTC,
+ endUTC,
+ timezone,
+ description,
+ location
+) {
+ const featured = {
+ "@context": "https://www.w3.org/ns/activitystreams",
+ id: `https://${domain}/${eventID}/m/featuredPost`,
+ type: "Note",
+ name: "Test",
+ cc: "https://www.w3.org/ns/activitystreams#Public",
+ content: `<p>This is an event that was posted on <a href="https://${domain}/${eventID}">${siteName}</a>. If you follow this account, you'll see updates in your timeline about the event. If your software supports polls, you should get a poll in your DMs asking if you want to RSVP. You can reply and RSVP right from there. If your software has an event calendar built in, you should get an event in your inbox that you can RSVP to like you respond to any event.</p><p>For more information on how to interact with this, <a href="https://github.com/lowercasename/gathio/wiki/Fediverse-Instructions">check out this link</a>.</p>`,
+ attributedTo: `https://${domain}/${eventID}`,
+ };
+ return featured;
+}
+
+function updateActivityPubEvent(
+ oldEvent,
+ name,
+ startUTC,
+ endUTC,
+ timezone,
+ description,
+ location
+) {
+ // we want to persist the old ID no matter what happens to the Event itself
+ const id = oldEvent.id;
+ let eventObject = {
+ "@context": "https://www.w3.org/ns/activitystreams",
+ id: id,
+ name: name,
+ type: "Event",
+ startTime: moment.tz(startUTC, timezone).format(),
+ endTime: moment.tz(endUTC, timezone).format(),
+ content: description,
+ location: location,
+ };
+ return JSON.stringify(eventObject);
+}
+
+function updateActivityPubActor(
+ actor,
+ description,
+ name,
+ location,
+ imageFilename,
+ startUTC,
+ endUTC,
+ timezone
+) {
+ if (!actor) return;
+ actor.summary = `<p>${description}</p>`;
+ actor.name = name;
+ if (location) {
+ actor.summary += `<p>Location: ${location}.</p>`;
+ }
+ let displayDate;
+ if (startUTC && timezone) {
+ displayDate = moment.tz(startUTC, timezone).format("D MMMM YYYY h:mm a");
+ actor.summary += `<p>Starting ${displayDate} ${timezone}.</p>`;
+ }
+ if (imageFilename) {
+ actor.icon = {
+ type: "Image",
+ mediaType: "image/jpg",
+ url: `https://${domain}/events/${imageFilename}`,
+ };
+ }
+ return JSON.stringify(actor);
+}
+
+function signAndSend(message, eventID, targetDomain, inbox, callback) {
+ if (!isFederated) return;
+ let inboxFragment = inbox.replace("https://" + targetDomain, "");
+ // get the private key
+ Event.findOne({
+ id: eventID,
+ }).then((event) => {
+ if (event) {
+ const digest = crypto
+ .createHash("sha256")
+ .update(JSON.stringify(message))
+ .digest("base64");
+ const privateKey = event.privateKey;
+ const signer = crypto.createSign("sha256");
+ let d = new Date();
+ let stringToSign = `(request-target): post ${inboxFragment}\nhost: ${targetDomain}\ndate: ${d.toUTCString()}\ndigest: SHA-256=${digest}`;
+ signer.update(stringToSign);
+ signer.end();
+ const signature = signer.sign(privateKey);
+ const signature_b64 = signature.toString("base64");
+ const algorithm = "rsa-sha256";
+ let header = `keyId="https://${domain}/${eventID}",algorithm="${algorithm}",headers="(request-target) host date digest",signature="${signature_b64}"`;
+ request(
+ {
+ url: inbox,
+ headers: {
+ Host: targetDomain,
+ Date: d.toUTCString(),
+ Signature: header,
+ Digest: `SHA-256=${digest}`,
+ "Content-Type": "application/activity+json",
+ Accept: "application/activity+json",
+ },
+ method: "POST",
+ json: true,
+ body: message,
+ },
+ function (error, response) {
+ if (error) {
+ callback(error, null, 500);
+ } else {
+ // Add the message to the database
+ const messageID = message.id;
+ const newMessage = {
+ id: message.id,
+ content: JSON.stringify(message),
+ };
+ Event.findOne(
+ {
+ id: eventID,
+ },
+ function (err, event) {
+ if (!event) return;
+ event.activityPubMessages.push(newMessage);
+ // also add the message's object if it has one
+ if (message.object && message.object.id) {
+ event.activityPubMessages.push({
+ id: message.object.id,
+ content: JSON.stringify(message.object),
+ });
+ }
+ event
+ .save()
+ .then(() => {
+ addToLog(
+ "addActivityPubMessage",
+ "success",
+ "ActivityPubMessage added to event " + eventID
+ );
+ callback(null, message.id, 200);
+ })
+ .catch((err) => {
+ addToLog(
+ "addActivityPubMessage",
+ "error",
+ "Attempt to add ActivityPubMessage to event " +
+ eventID +
+ " failed with error: " +
+ err
+ );
+ callback(err, null, 500);
+ });
+ }
+ );
+ }
+ }
+ );
+ } else {
+ callback(`No record found for ${eventID}.`, null, 404);
+ }
+ });
+}
+
+// this function sends something to the timeline of every follower in the followers array
+// it's also an unlisted public message, meaning non-followers can see the message if they look at
+// the profile but it doesn't spam federated timelines
+function broadcastCreateMessage(apObject, followers, eventID) {
+ if (!isFederated) return;
+ let guidCreate = crypto.randomBytes(16).toString("hex");
+ Event.findOne(
+ {
+ id: eventID,
+ },
+ function (err, event) {
+ if (event) {
+ // iterate over followers
+ for (const follower of followers) {
+ let actorId = follower.actorId;
+ let myURL = new URL(actorId);
+ let targetDomain = myURL.hostname;
+ // get the inbox
+ const followerFound = event.followers.find(
+ (el) => el.actorId === actorId
+ );
+ if (followerFound) {
+ const actorJson = JSON.parse(follower.actorJson);
+ const inbox = actorJson.inbox;
+ const createMessage = {
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1",
+ ],
+ id: `https://${domain}/${eventID}/m/${guidCreate}`,
+ type: "Create",
+ actor: `https://${domain}/${eventID}`,
+ to: [actorId],
+ cc: "https://www.w3.org/ns/activitystreams#Public",
+ object: apObject,
+ };
+ signAndSend(
+ createMessage,
+ eventID,
+ targetDomain,
+ inbox,
+ function (err, resp, status) {
+ if (err) {
+ console.log(
+ `Didn't send to ${actorId}, status ${status} with error ${err}`
+ );
+ } else {
+ console.log("sent to", actorId);
+ }
+ }
+ );
+ } else {
+ console.log(`No follower found with the id ${actorId}`);
+ }
+ } // end followers
+ } // end if event
+ else {
+ console.log(`No event found with the id ${eventID}`);
+ }
+ }
+ );
+}
+
+// sends an Announce for the apObject
+function broadcastAnnounceMessage(apObject, followers, eventID) {
+ if (!isFederated) return;
+ let guidUpdate = crypto.randomBytes(16).toString("hex");
+ Event.findOne(
+ {
+ id: eventID,
+ },
+ function (err, event) {
+ if (event) {
+ // iterate over followers
+ for (const follower of followers) {
+ let actorId = follower.actorId;
+ let myURL = new URL(actorId);
+ let targetDomain = myURL.hostname;
+ // get the inbox
+ const followerFound = event.followers.find(
+ (el) => el.actorId === actorId
+ );
+ if (followerFound) {
+ const actorJson = JSON.parse(follower.actorJson);
+ const inbox = actorJson.inbox;
+ const announceMessage = {
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1",
+ ],
+ id: `https://${domain}/${eventID}/m/${guidUpdate}`,
+ cc: "https://www.w3.org/ns/activitystreams#Public",
+ type: "Announce",
+ actor: `https://${domain}/${eventID}`,
+ object: apObject,
+ to: actorId,
+ };
+ signAndSend(
+ announceMessage,
+ eventID,
+ targetDomain,
+ inbox,
+ function (err, resp, status) {
+ if (err) {
+ console.log(
+ `Didn't send to ${actorId}, status ${status} with error ${err}`
+ );
+ } else {
+ console.log("sent to", actorId);
+ }
+ }
+ );
+ } else {
+ console.log(`No follower found with the id ${actorId}`);
+ }
+ } // end followers
+ } // end if event
+ else {
+ console.log(`No event found with the id ${eventID}`);
+ }
+ }
+ );
+}
+
+// sends an Update for the apObject
+function broadcastUpdateMessage(apObject, followers, eventID) {
+ if (!isFederated) return;
+ let guidUpdate = crypto.randomBytes(16).toString("hex");
+ // iterate over followers
+ Event.findOne(
+ {
+ id: eventID,
+ },
+ function (err, event) {
+ if (event) {
+ for (const follower of followers) {
+ let actorId = follower.actorId;
+ let myURL = new URL(actorId);
+ let targetDomain = myURL.hostname;
+ // get the inbox
+ const followerFound = event.followers.find(
+ (el) => el.actorId === actorId
+ );
+ if (followerFound) {
+ const actorJson = JSON.parse(follower.actorJson);
+ const inbox = actorJson.inbox;
+ const createMessage = {
+ "@context": "https://www.w3.org/ns/activitystreams",
+ id: `https://${domain}/${eventID}/m/${guidUpdate}`,
+ type: "Update",
+ actor: `https://${domain}/${eventID}`,
+ object: apObject,
+ };
+ signAndSend(
+ createMessage,
+ eventID,
+ targetDomain,
+ inbox,
+ function (err, resp, status) {
+ if (err) {
+ console.log(
+ `Didn't send to ${actorId}, status ${status} with error ${err}`
+ );
+ } else {
+ console.log("sent to", actorId);
+ }
+ }
+ );
+ } else {
+ console.log(`No follower found with the id ${actorId}`);
+ }
+ } // end followers
+ } else {
+ console.log(`No event found with the id ${eventID}`);
+ }
+ }
+ );
+}
+
+function broadcastDeleteMessage(apObject, followers, eventID, callback) {
+ callback = callback || function () {};
+ if (!isFederated) {
+ callback([]);
+ return;
+ }
+ // we need to build an array of promises for each message we're sending, run Promise.all(), and then that will resolve when every message has been sent (or failed)
+ // per spec, each promise will execute *as it is built*, which is fine, we just need the guarantee that they are all done
+ let promises = [];
+
+ let guidUpdate = crypto.randomBytes(16).toString("hex");
+ // iterate over followers
+ for (const follower of followers) {
+ promises.push(
+ new Promise((resolve, reject) => {
+ let actorId = follower.actorId;
+ let myURL = new URL(actorId);
+ let targetDomain = myURL.hostname;
+ // get the inbox
+ Event.findOne(
+ {
+ id: eventID,
+ },
+ function (err, event) {
+ if (event) {
+ const follower = event.followers.find(
+ (el) => el.actorId === actorId
+ );
+ if (follower) {
+ const actorJson = JSON.parse(follower.actorJson);
+ const inbox = actorJson.inbox;
+ const createMessage = {
+ "@context": "https://www.w3.org/ns/activitystreams",
+ id: `https://${domain}/${eventID}/m/${guidUpdate}`,
+ type: "Delete",
+ actor: `https://${domain}/${eventID}`,
+ object: apObject,
+ };
+ signAndSend(
+ createMessage,
+ eventID,
+ targetDomain,
+ inbox,
+ function (err, resp, status) {
+ if (err) {
+ console.log(
+ `Didn't send to ${actorId}, status ${status} with error ${err}`
+ );
+ reject(
+ `Didn't send to ${actorId}, status ${status} with error ${err}`
+ );
+ } else {
+ console.log("sent to", actorId);
+ resolve("sent to", actorId);
+ }
+ }
+ );
+ } else {
+ console.log(
+ `No follower found with the id ${actorId}`,
+ null,
+ 404
+ );
+ reject(`No follower found with the id ${actorId}`, null, 404);
+ }
+ } else {
+ console.log(`No event found with the id ${eventID}`, null, 404);
+ reject(`No event found with the id ${eventID}`, null, 404);
+ }
+ }
+ ); // end event
+ })
+ );
+ } // end followers
+
+ Promise.all(promises.map((p) => p.catch((e) => e))).then((statuses) => {
+ callback(statuses);
+ });
+}
+
+// this sends a message "to:" an individual fediverse user
+function sendDirectMessage(apObject, actorId, eventID, callback) {
+ if (!isFederated) return;
+ callback = callback || function () {};
+ const guidCreate = crypto.randomBytes(16).toString("hex");
+ const guidObject = crypto.randomBytes(16).toString("hex");
+ let d = new Date();
+
+ apObject.published = d.toISOString();
+ apObject.attributedTo = `https://${domain}/${eventID}`;
+ apObject.to = actorId;
+ apObject.id = `https://${domain}/${eventID}/m/${guidObject}`;
+ apObject.content = unescape(apObject.content);
+
+ let createMessage = {
+ "@context": "https://www.w3.org/ns/activitystreams",
+ id: `https://${domain}/${eventID}/m/${guidCreate}`,
+ type: "Create",
+ actor: `https://${domain}/${eventID}`,
+ to: [actorId],
+ object: apObject,
+ };
+
+ let myURL = new URL(actorId);
+ let targetDomain = myURL.hostname;
+ // get the inbox
+ Event.findOne(
+ {
+ id: eventID,
+ },
+ function (err, event) {
+ if (event) {
+ const follower = event.followers.find((el) => el.actorId === actorId);
+ if (follower) {
+ const actorJson = JSON.parse(follower.actorJson);
+ const inbox = actorJson.inbox;
+ signAndSend(createMessage, eventID, targetDomain, inbox, callback);
+ } else {
+ callback(`No follower found with the id ${actorId}`, null, 404);
+ }
+ } else {
+ callback(`No event found with the id ${eventID}`, null, 404);
+ }
+ }
+ );
+}
+
+function sendAcceptMessage(thebody, eventID, targetDomain, callback) {
+ if (!isFederated) return;
+ callback = callback || function () {};
+ const guid = crypto.randomBytes(16).toString("hex");
+ const actorId = thebody.actor;
+ let message = {
+ "@context": "https://www.w3.org/ns/activitystreams",
+ id: `https://${domain}/${guid}`,
+ type: "Accept",
+ actor: `https://${domain}/${eventID}`,
+ object: thebody,
+ };
+ // get the inbox
+ Event.findOne(
+ {
+ id: eventID,
+ },
+ function (err, event) {
+ if (event) {
+ const follower = event.followers.find((el) => el.actorId === actorId);
+ if (follower) {
+ const actorJson = JSON.parse(follower.actorJson);
+ const inbox = actorJson.inbox;
+ signAndSend(message, eventID, targetDomain, inbox, callback);
+ }
+ } else {
+ callback(`Could not find event ${eventID}`, null, 404);
+ }
+ }
+ );
+}
+
+function _handleFollow(req, res) {
+ const myURL = new URL(req.body.actor);
+ let targetDomain = myURL.hostname;
+ let eventID = req.body.object.replace(`https://${domain}/`, "");
+ // Add the user to the DB of accounts that follow the account
+ // get the follower's username
+ request(
+ {
+ url: req.body.actor,
+ headers: {
+ Accept: "application/activity+json",
+ "Content-Type": "application/activity+json",
+ },
+ },
+ function (error, response, body) {
+ body = JSON.parse(body);
+ const name = body.preferredUsername || body.name || body.attributedTo;
+ const newFollower = {
+ actorId: req.body.actor,
+ followId: req.body.id,
+ name: name,
+ actorJson: JSON.stringify(body),
+ };
+ Event.findOne(
+ {
+ id: eventID,
+ },
+ function (err, event) {
+ // if this account is NOT already in our followers list, add it
+ if (
+ event &&
+ !event.followers.map((el) => el.actorId).includes(req.body.actor)
+ ) {
+ event.followers.push(newFollower);
+ event
+ .save()
+ .then(() => {
+ addToLog(
+ "addEventFollower",
+ "success",
+ "Follower added to event " + eventID
+ );
+ // Accept the follow request
+ sendAcceptMessage(
+ req.body,
+ eventID,
+ targetDomain,
+ function (err, resp, status) {
+ if (err) {
+ console.log(
+ `Didn't send Accept to ${req.body.actor}, status ${status} with error ${err}`
+ );
+ } else {
+ console.log("sent Accept to", req.body.actor);
+ // ALSO send an ActivityPub Event activity since this person is "interested" in the event, as indicated by the Follow
+ const jsonEventObject = JSON.parse(
+ event.activityPubEvent
+ );
+ // send direct message to user
+ sendDirectMessage(
+ jsonEventObject,
+ newFollower.actorId,
+ event.id
+ );
+
+ // if users can self-RSVP, send a Question to the new follower
+ if (event.usersCanAttend) {
+ const jsonObject = {
+ "@context": "https://www.w3.org/ns/activitystreams",
+ name: `RSVP to ${event.name}`,
+ type: "Question",
+ content: `<span class=\"h-card\"><a href="${req.body.actor}" class="u-url mention">@<span>${name}</span></a></span> Will you attend ${event.name}? (If you reply "Yes", you'll be listed as an attendee on the event page.)`,
+ oneOf: [{ type: "Note", name: "Yes" }],
+ endTime: event.start.toISOString(),
+ tag: [
+ {
+ type: "Mention",
+ href: req.body.actor,
+ name: name,
+ },
+ ],
+ };
+ // send direct message to user
+ sendDirectMessage(
+ jsonObject,
+ req.body.actor,
+ eventID,
+ function (error, response, statuscode) {
+ if (error) {
+ console.log(
+ "Error sending direct message:",
+ error
+ );
+ return res.status(statuscode).json(error);
+ } else {
+ return res
+ .status(statuscode)
+ .json({ messageid: response });
+ }
+ }
+ );
+ }
+ }
+ }
+ );
+ })
+ .catch((err) => {
+ addToLog(
+ "addEventFollower",
+ "error",
+ "Attempt to add follower to event " +
+ eventID +
+ " failed with error: " +
+ err
+ );
+ return res
+ .status(500)
+ .send("Database error, please try again :(");
+ });
+ } else {
+ // this person is already a follower so just say "ok"
+ return res.status(200);
+ }
+ }
+ );
+ }
+ ); //end request
+}
+
+function _handleUndoFollow(req, res) {
+ // get the record of all followers for this account
+ const eventID = req.body.object.object.replace(`https://${domain}/`, "");
+ Event.findOne(
+ {
+ id: eventID,
+ },
+ function (err, event) {
+ if (!event) return;
+ // check to see if the Follow object's id matches the id we have on record
+ // is this even someone who follows us
+ const indexOfFollower = event.followers.findIndex(
+ (el) => el.actorId === req.body.object.actor
+ );
+ if (indexOfFollower !== -1) {
+ // does the id we have match the id we are being given
+ if (event.followers[indexOfFollower].followId === req.body.object.id) {
+ // we have a match and can trust the Undo! remove this person from the followers list
+ event.followers.splice(indexOfFollower, 1);
+ event
+ .save()
+ .then(() => {
+ addToLog(
+ "removeEventFollower",
+ "success",
+ "Follower removed from event " + eventID
+ );
+ return res.sendStatus(200);
+ })
+ .catch((err) => {
+ addToLog(
+ "removeEventFollower",
+ "error",
+ "Attempt to remove follower from event " +
+ eventID +
+ " failed with error: " +
+ err
+ );
+ return res.send("Database error, please try again :(");
+ });
+ }
+ }
+ }
+ );
+}
+
+function _handleAcceptEvent(req, res) {
+ let { name, attributedTo, inReplyTo, to, actor } = req.body;
+ if (Array.isArray(to)) {
+ to = to[0];
+ }
+ const eventID = to.replace(`https://${domain}/`, "");
+ Event.findOne(
+ {
+ id: eventID,
+ },
+ function (err, event) {
+ if (!event) return;
+ // does the id we got match the id of a thing we sent out
+ const message = event.activityPubMessages.find(
+ (el) => el.id === req.body.object
+ );
+ if (message) {
+ // it's a match
+ request(
+ {
+ url: actor,
+ headers: {
+ Accept: "application/activity+json",
+ "Content-Type": "application/activity+json",
+ },
+ },
+ function (error, response, body) {
+ body = JSON.parse(body);
+ // if this account is NOT already in our attendees list, add it
+ if (!event.attendees.map((el) => el.id).includes(actor)) {
+ const attendeeName = body.preferredUsername || body.name || actor;
+ const newAttendee = {
+ name: attendeeName,
+ status: "attending",
+ id: actor,
+ number: 1,
+ };
+ event.attendees.push(newAttendee);
+ event
+ .save()
+ .then((fullEvent) => {
+ addToLog(
+ "addEventAttendee",
+ "success",
+ "Attendee added to event " + req.params.eventID
+ );
+ // get the new attendee with its hidden id from the full event
+ let fullAttendee = fullEvent.attendees.find(
+ (el) => el.id === actor
+ );
+ // send a "click here to remove yourself" link back to the user as a DM
+ const jsonObject = {
+ "@context": "https://www.w3.org/ns/activitystreams",
+ name: `RSVP to ${event.name}`,
+ type: "Note",
+ content: `<span class=\"h-card\"><a href="${newAttendee.id}" class="u-url mention">@<span>${newAttendee.name}</span></a></span> Thanks for RSVPing! You can remove yourself from the RSVP list by clicking here: <a href="https://${domain}/oneclickunattendevent/${event.id}/${fullAttendee._id}">https://${domain}/oneclickunattendevent/${event.id}/${fullAttendee._id}</a>`,
+ tag: [
+ {
+ type: "Mention",
+ href: newAttendee.id,
+ name: newAttendee.name,
+ },
+ ],
+ };
+ // send direct message to user
+ sendDirectMessage(jsonObject, newAttendee.id, event.id);
+ return res.sendStatus(200);
+ })
+ .catch((err) => {
+ addToLog(
+ "addEventAttendee",
+ "error",
+ "Attempt to add attendee to event " +
+ req.params.eventID +
+ " failed with error: " +
+ err
+ );
+ return res
+ .status(500)
+ .send("Database error, please try again :(");
+ });
+ } else {
+ // it's a duplicate and this person is already rsvped so just say OK
+ return res.status(200).send("Attendee is already registered.");
+ }
+ }
+ );
+ }
+ }
+ );
+}
+
+function _handleUndoAcceptEvent(req, res) {
+ let { name, attributedTo, inReplyTo, to, actor } = req.body;
+ if (Array.isArray(to)) {
+ to = to[0];
+ }
+ const eventID = to.replace(`https://${domain}/`, "");
+ Event.findOne(
+ {
+ id: eventID,
+ },
+ function (err, event) {
+ if (!event) return;
+ // does the id we got match the id of a thing we sent out
+ const message = event.activityPubMessages.find(
+ (el) => el.id === req.body.object.object
+ );
+ if (message) {
+ // it's a match
+ Event.update(
+ { id: eventID },
+ { $pull: { attendees: { id: actor } } }
+ ).then((response) => {
+ addToLog(
+ "oneClickUnattend",
+ "success",
+ "Attendee removed via one click unattend " + req.params.eventID
+ );
+ });
+ }
+ }
+ );
+}
+
+function _handleCreateNote(req, res) {
+ // figure out what this is in reply to -- it should be addressed specifically to us
+ let { name, attributedTo, inReplyTo, to } = req.body.object;
+ // if it's an array just grab the first element, since a poll should only broadcast back to the pollster
+ if (Array.isArray(to)) {
+ to = to[0];
+ }
+ const eventID = to.replace(`https://${domain}/`, "");
+ // make sure this person is actually a follower
+ Event.findOne(
+ {
+ id: eventID,
+ },
+ function (err, event) {
+ if (!event) return;
+ // is this even someone who follows us
+ const indexOfFollower = event.followers.findIndex(
+ (el) => el.actorId === req.body.object.attributedTo
+ );
+ if (indexOfFollower !== -1) {
+ // compare the inReplyTo to its stored message, if it exists and it's going to the right follower then this is a valid reply
+ const message = event.activityPubMessages.find((el) => {
+ const content = JSON.parse(el.content);
+ return inReplyTo === (content.object && content.object.id);
+ });
+ if (message) {
+ const content = JSON.parse(message.content);
+ // check if the message we sent out was sent to the actor this incoming message is attributedTo
+ if (content.to[0] === attributedTo) {
+ // it's a match, this is a valid poll response, add RSVP to database
+ // fetch the profile information of the user
+ request(
+ {
+ url: attributedTo,
+ headers: {
+ Accept: "application/activity+json",
+ "Content-Type": "application/activity+json",
+ },
+ },
+ function (error, response, body) {
+ body = JSON.parse(body);
+ // if this account is NOT already in our attendees list, add it
+ if (
+ !event.attendees.map((el) => el.id).includes(attributedTo)
+ ) {
+ const attendeeName =
+ body.preferredUsername || body.name || attributedTo;
+ const newAttendee = {
+ name: attendeeName,
+ status: "attending",
+ id: attributedTo,
+ number: 1,
+ };
+ event.attendees.push(newAttendee);
+ event
+ .save()
+ .then((fullEvent) => {
+ addToLog(
+ "addEventAttendee",
+ "success",
+ "Attendee added to event " + req.params.eventID
+ );
+ // get the new attendee with its hidden id from the full event
+ let fullAttendee = fullEvent.attendees.find(
+ (el) => el.id === attributedTo
+ );
+ // send a "click here to remove yourself" link back to the user as a DM
+ const jsonObject = {
+ "@context": "https://www.w3.org/ns/activitystreams",
+ name: `RSVP to ${event.name}`,
+ type: "Note",
+ content: `<span class=\"h-card\"><a href="${newAttendee.id}" class="u-url mention">@<span>${newAttendee.name}</span></a></span> Thanks for RSVPing! You can remove yourself from the RSVP list by clicking here: <a href="https://${domain}/oneclickunattendevent/${event.id}/${fullAttendee._id}">https://${domain}/oneclickunattendevent/${event.id}/${fullAttendee._id}</a>`,
+ tag: [
+ {
+ type: "Mention",
+ href: newAttendee.id,
+ name: newAttendee.name,
+ },
+ ],
+ };
+ // send direct message to user
+ sendDirectMessage(jsonObject, newAttendee.id, event.id);
+ return res.sendStatus(200);
+ })
+ .catch((err) => {
+ addToLog(
+ "addEventAttendee",
+ "error",
+ "Attempt to add attendee to event " +
+ req.params.eventID +
+ " failed with error: " +
+ err
+ );
+ return res
+ .status(500)
+ .send("Database error, please try again :(");
+ });
+ } else {
+ // it's a duplicate and this person is already rsvped so just say OK
+ return res
+ .status(200)
+ .send("Attendee is already registered.");
+ }
+ }
+ );
+ }
+ }
+ }
+ }
+ );
+}
+
+function _handleDelete(req, res) {
+ const deleteObjectId = req.body.object.id;
+ // find all events with comments from the author
+ Event.find(
+ {
+ "comments.actorId": req.body.actor,
+ },
+ function (err, events) {
+ if (!events) {
+ return res.sendStatus(404);
+ }
+
+ // find the event with THIS comment from the author
+ let eventWithComment = events.find((event) => {
+ let comments = event.comments;
+ return comments.find((comment) => {
+ if (!comment.activityJson) {
+ return false;
+ }
+ return (
+ JSON.parse(comment.activityJson).object.id === req.body.object.id
+ );
+ });
+ });
+
+ if (!eventWithComment) {
+ return res.sendStatus(404);
+ }
+
+ // delete the comment
+ // find the index of the comment, it should have an activityJson field because from an AP server you can only delete an AP-originated comment (and of course it needs to be yours)
+ let indexOfComment = eventWithComment.comments.findIndex((comment) => {
+ return (
+ comment.activityJson &&
+ JSON.parse(comment.activityJson).object.id === req.body.object.id
+ );
+ });
+ eventWithComment.comments.splice(indexOfComment, 1);
+ eventWithComment
+ .save()
+ .then(() => {
+ addToLog(
+ "deleteComment",
+ "success",
+ "Comment deleted from event " + eventWithComment.id
+ );
+ return res.sendStatus(200);
+ })
+ .catch((err) => {
+ addToLog(
+ "deleteComment",
+ "error",
+ "Attempt to delete comment " +
+ req.body.object.id +
+ "from event " +
+ eventWithComment.id +
+ " failed with error: " +
+ err
+ );
+ return res.sendStatus(500);
+ });
+ }
+ );
+}
+
+function _handleCreateNoteComment(req, res) {
+ // figure out what this is in reply to -- it should be addressed specifically to us
+ let { attributedTo, inReplyTo, to, cc } = req.body.object;
+ // normalize cc into an array
+ if (typeof cc === "string") {
+ cc = [cc];
+ }
+ // normalize to into an array
+ if (typeof to === "string") {
+ to = [to];
+ }
+
+ // if this is a public message (in the to or cc fields)
+ if (
+ to.includes("https://www.w3.org/ns/activitystreams#Public") ||
+ (Array.isArray(cc) &&
+ cc.includes("https://www.w3.org/ns/activitystreams#Public"))
+ ) {
+ // figure out which event(s) of ours it was addressing
+ let ourEvents = cc
+ .filter((el) => el.includes(`https://${domain}/`))
+ .map((el) => el.replace(`https://${domain}/`, ""));
+ // comments should only be on one event. if more than one, ignore (spam, probably)
+ if (ourEvents.length === 1) {
+ let eventID = ourEvents[0];
+ // add comment
+ let commentID = nanoid();
+ // get the actor for the commenter
+ request(
+ {
+ url: req.body.actor,
+ headers: {
+ Accept: "application/activity+json",
+ "Content-Type": "application/activity+json",
+ },
+ },
+ function (error, response, actor) {
+ if (!error) {
+ const parsedActor = JSON.parse(actor);
+ const name =
+ parsedActor.preferredUsername ||
+ parsedActor.name ||
+ req.body.actor;
+ const newComment = {
+ id: commentID,
+ actorId: req.body.actor,
+ activityId: req.body.object.id,
+ author: name,
+ content: sanitizeHtml(req.body.object.content, {
+ allowedTags: [],
+ allowedAttributes: {},
+ }).replace("@" + eventID, ""),
+ timestamp: moment(),
+ activityJson: JSON.stringify(req.body),
+ actorJson: actor,
+ };
+
+ Event.findOne(
+ {
+ id: eventID,
+ },
+ function (err, event) {
+ if (!event) {
+ return res.sendStatus(404);
+ }
+ if (!event.usersCanComment) {
+ return res.sendStatus(200);
+ }
+ event.comments.push(newComment);
+ event
+ .save()
+ .then(() => {
+ addToLog(
+ "addEventComment",
+ "success",
+ "Comment added to event " + eventID
+ );
+ const guidObject = crypto.randomBytes(16).toString("hex");
+ const jsonObject = req.body.object;
+ jsonObject.attributedTo = newComment.actorId;
+ broadcastAnnounceMessage(
+ jsonObject,
+ event.followers,
+ eventID
+ );
+ return res.sendStatus(200);
+ })
+ .catch((err) => {
+ addToLog(
+ "addEventComment",
+ "error",
+ "Attempt to add comment to event " +
+ eventID +
+ " failed with error: " +
+ err
+ );
+ res
+ .status(500)
+ .send("Database error, please try again :(" + err);
+ });
+ }
+ );
+ }
+ }
+ );
+ } // end ourevent
+ } // end public message
+}
+
+function processInbox(req, res) {
+ if (!isFederated) return res.sendStatus(404);
+ try {
+ // if a Follow activity hits the inbox
+ if (typeof req.body.object === "string" && req.body.type === "Follow") {
+ _handleFollow(req, res);
+ }
+ // if an Undo activity with a Follow object hits the inbox
+ if (
+ req.body &&
+ req.body.type === "Undo" &&
+ req.body.object &&
+ req.body.object.type === "Follow"
+ ) {
+ _handleUndoFollow(req, res);
+ }
+ // if an Accept activity with the id of the Event we sent out hits the inbox, it is an affirmative RSVP
+ if (
+ req.body &&
+ req.body.type === "Accept" &&
+ req.body.object &&
+ typeof req.body.object === "string"
+ ) {
+ _handleAcceptEvent(req, res);
+ }
+ // if an Undo activity containing an Accept containing the id of the Event we sent out hits the inbox, it is an undo RSVP
+ if (
+ req.body &&
+ req.body.type === "Undo" &&
+ req.body.object &&
+ req.body.object.object &&
+ typeof req.body.object.object === "string" &&
+ req.body.object.type === "Accept"
+ ) {
+ _handleUndoAcceptEvent(req, res);
+ }
+ // if a Create activity with a Note object hits the inbox, and it's a reply, it might be a vote in a poll
+ if (
+ req.body &&
+ req.body.type === "Create" &&
+ req.body.object &&
+ req.body.object.type === "Note" &&
+ req.body.object.inReplyTo &&
+ req.body.object.to
+ ) {
+ _handleCreateNote(req, res);
+ }
+ // if a Delete activity hits the inbox, it might a deletion of a comment
+ if (req.body && req.body.type === "Delete") {
+ _handleDelete(req, res);
+ }
+ // if we are CC'ed on a public or unlisted Create/Note, then this is a comment to us we should boost (Announce) to our followers
+ if (
+ req.body &&
+ req.body.type === "Create" &&
+ req.body.object &&
+ req.body.object.type === "Note" &&
+ req.body.object.to
+ ) {
+ _handleCreateNoteComment(req, res);
+ } // CC'ed
+ } catch (e) {
+ console.log("Error in processing inbox:", e);
+ }
+}
+
+function createWebfinger(eventID, domain) {
+ return {
+ subject: `acct:${eventID}@${domain}`,
+
+ links: [
+ {
+ rel: "self",
+ type: "application/activity+json",
+ href: `https://${domain}/${eventID}`,
+ },
+ ],
+ };
+}
+
+module.exports = {
+ processInbox,
+ sendAcceptMessage,
+ sendDirectMessage,
+ broadcastAnnounceMessage,
+ broadcastUpdateMessage,
+ broadcastDeleteMessage,
+ broadcastCreateMessage,
+ signAndSend,
+ createActivityPubActor,
+ updateActivityPubActor,
+ createActivityPubEvent,
+ updateActivityPubEvent,
+ createFeaturedPost,
+ createWebfinger,
+};
diff --git a/src/app.js b/src/app.js
new file mode 100755
index 0000000..4a2137e
--- /dev/null
+++ b/src/app.js
@@ -0,0 +1,53 @@
+const express = require("express");
+const path = require("path");
+const session = require("express-session");
+const cors = require("cors");
+const routes = require("./routes");
+const hbs = require("express-handlebars");
+const bodyParser = require("body-parser");
+
+const app = express();
+
+// Configuration //
+
+//app.use(cors());
+//app.use(bodyParser.json());
+//app.use(session({ secret: 'slartibartfast', cookie: { maxAge: 60000 }, resave: false, saveUninitialized: false }));
+
+// View engine //
+const hbsInstance = hbs.create({
+ defaultLayout: "main",
+ partialsDir: ["views/partials/"],
+ layoutsDir: "views/layouts/",
+ helpers: {
+ plural: function (number, text) {
+ var singular = number === 1;
+ // If no text parameter was given, just return a conditional s.
+ if (typeof text !== "string") return singular ? "" : "s";
+ // Split with regex into group1/group2 or group1(group3)
+ var match = text.match(/^([^()\/]+)(?:\/(.+))?(?:\((\w+)\))?/);
+ // If no match, just append a conditional s.
+ if (!match) return text + (singular ? "" : "s");
+ // We have a good match, so fire away
+ return (
+ (singular && match[1]) || // Singular case
+ match[2] || // Plural case: 'bagel/bagels' --> bagels
+ match[1] + (match[3] || "s")
+ ); // Plural case: 'bagel(s)' or 'bagel' --> bagels
+ },
+ },
+});
+app.engine("handlebars", hbsInstance.engine);
+app.set("view engine", "handlebars");
+app.set("hbsInstance", hbsInstance);
+
+// Static files //
+
+app.use(express.static("public"));
+
+// Router //
+app.use(bodyParser.json({ type: "application/activity+json" })); // support json encoded bodies
+app.use(bodyParser.urlencoded({ extended: true }));
+app.use("/", routes);
+
+module.exports = app;
diff --git a/src/config/api-example.js b/src/config/api-example.js
new file mode 100644
index 0000000..493b9d6
--- /dev/null
+++ b/src/config/api-example.js
@@ -0,0 +1,8 @@
+// Which of these fields are used depends on the 'mailService' config entry in config/domain.js
+module.exports = {
+ sendgrid: "", // If using SendGrid, the Sendgrid API key goes here
+ smtpServer: "", // If using Nodemailer, your SMTP server hostname goes here
+ smtpPort: "", // If using Nodemailer, your SMTP server port goes here
+ smtpUsername: "", // If using Nodemailer, your SMTP server username goes here
+ smtpPassword: "", // If using Nodemailer, your SMTP password goes here
+};
diff --git a/src/config/database-docker.js b/src/config/database-docker.js
new file mode 100644
index 0000000..96c987d
--- /dev/null
+++ b/src/config/database-docker.js
@@ -0,0 +1,3 @@
+module.exports = {
+ url: "mongodb://mongo:27017/gathio", // For dockerised MongoDB connection
+};
diff --git a/src/config/database-example.js b/src/config/database-example.js
new file mode 100644
index 0000000..ca7bdcc
--- /dev/null
+++ b/src/config/database-example.js
@@ -0,0 +1,3 @@
+module.exports = {
+ url: "mongodb://localhost:27017/gathio", // For local MongoDB connection
+};
diff --git a/src/config/domain-example.js b/src/config/domain-example.js
new file mode 100644
index 0000000..abac094
--- /dev/null
+++ b/src/config/domain-example.js
@@ -0,0 +1,13 @@
+module.exports = {
+ // Your domain goes here. If there is a port it should be 'domain:port', but otherwise just 'domain'
+ domain: "localhost:3000",
+ port: "3000",
+ email: "contact@example.com",
+ mailService: "nodemailer", // Which mail service to use to send emails to attendees. Options are 'nodemailer' or 'sendgrid'. Configure settings for the mail service in config/api.js.z
+ sitename: "gathio",
+ isFederated: true,
+ // If left blank, this defaults to https://yourdomain.com/images/gathio-email-logo.gif. Set a full URL here to change it to your own logo (or just change the file itself)
+ logo_url: "",
+ // Show a Ko-Fi box to donate money to Raphael Kabo (Gathio's creator) on the front page
+ showKofi: false,
+};
diff --git a/config/gathio.service b/src/config/gathio.service
index 447d44f..447d44f 100644
--- a/config/gathio.service
+++ b/src/config/gathio.service
diff --git a/helpers.js b/src/helpers.js
index bf95e27..9b7559f 100644
--- a/helpers.js
+++ b/src/helpers.js
@@ -1,10 +1,10 @@
-const domain = require('./config/domain.js').domain;
-const siteName = require('./config/domain.js').sitename;
+const domain = require("./config/domain.js").domain;
+const siteName = require("./config/domain.js").sitename;
-const mongoose = require('mongoose');
-const Log = mongoose.model('Log');
-var moment = require('moment-timezone');
-const icalGenerator = require('ical-generator');
+const mongoose = require("mongoose");
+const Log = mongoose.model("Log");
+var moment = require("moment-timezone");
+const icalGenerator = require("ical-generator");
// LOGGING
@@ -13,9 +13,11 @@ function addToLog(process, status, message) {
status: status,
process: process,
message: message,
- timestamp: moment()
+ timestamp: moment(),
+ });
+ logEntry.save().catch(() => {
+ console.log("Error saving log entry!");
});
- logEntry.save().catch(() => { console.log("Error saving log entry!") });
}
function exportIcal(events, calendarName) {
@@ -23,13 +25,13 @@ function exportIcal(events, calendarName) {
const cal = icalGenerator({
name: calendarName || siteName,
x: {
- 'X-WR-CALNAME': calendarName || siteName,
+ "X-WR-CALNAME": calendarName || siteName,
},
});
if (events instanceof Array === false) {
- events = [ events ];
+ events = [events];
}
- events.forEach(event => {
+ events.forEach((event) => {
// Add the event to the generator
cal.createEvent({
start: moment.tz(event.start, event.timezone),
@@ -40,10 +42,10 @@ function exportIcal(events, calendarName) {
description: event.description,
organizer: {
name: event.hostName || "Anonymous",
- email: event.creatorEmail || 'anonymous@anonymous.com',
+ email: event.creatorEmail || "anonymous@anonymous.com",
},
location: event.location,
- url: 'https://' + domain + '/' + event.id
+ url: "https://" + domain + "/" + event.id,
});
});
// Stringify it!
@@ -54,4 +56,4 @@ function exportIcal(events, calendarName) {
module.exports = {
addToLog,
exportIcal,
-}
+};
diff --git a/models/Event.js b/src/models/Event.js
index d800077..234084a 100755
--- a/models/Event.js
+++ b/src/models/Event.js
@@ -1,17 +1,17 @@
-const mongoose = require('mongoose');
+const mongoose = require("mongoose");
const Attendees = new mongoose.Schema({
name: {
type: String,
- trim: true
+ trim: true,
},
status: {
type: String,
- trim: true
+ trim: true,
},
email: {
type: String,
- trim: true
+ trim: true,
},
removalPassword: {
type: String,
@@ -29,226 +29,231 @@ const Attendees = new mongoose.Schema({
number: {
type: Number,
trim: true,
- default: 1
+ default: 1,
},
created: Date,
-})
+});
-const Followers = new mongoose.Schema({
- // this is the id of the original follow *request*, which we use to validate Undo events
- followId: {
- type: String,
- trim: true
- },
- // this is the actual remote user profile id
- actorId: {
- type: String,
- trim: true
- },
- // this is the stringified JSON of the entire user profile
- actorJson: {
- type: String,
- trim: true
- },
- name: {
- type: String,
- trim: true
- },
-}, { _id: false })
+const Followers = new mongoose.Schema(
+ {
+ // this is the id of the original follow *request*, which we use to validate Undo events
+ followId: {
+ type: String,
+ trim: true,
+ },
+ // this is the actual remote user profile id
+ actorId: {
+ type: String,
+ trim: true,
+ },
+ // this is the stringified JSON of the entire user profile
+ actorJson: {
+ type: String,
+ trim: true,
+ },
+ name: {
+ type: String,
+ trim: true,
+ },
+ },
+ { _id: false }
+);
const ReplySchema = new mongoose.Schema({
id: {
type: String,
required: true,
unique: true,
- sparse: true
+ sparse: true,
},
author: {
type: String,
trim: true,
- required: true
+ required: true,
},
content: {
type: String,
trim: true,
- required: true
+ required: true,
},
timestamp: {
type: Date,
trim: true,
- required: true
- }
-})
+ required: true,
+ },
+});
const ActivityPubMessages = new mongoose.Schema({
id: {
type: String,
required: true,
unique: true,
- sparse: true
+ sparse: true,
},
content: {
type: String,
trim: true,
- required: true
- }
-})
+ required: true,
+ },
+});
const CommentSchema = new mongoose.Schema({
id: {
type: String,
required: true,
unique: true,
- sparse: true
+ sparse: true,
},
author: {
type: String,
trim: true,
- required: true
+ required: true,
},
content: {
type: String,
trim: true,
- required: true
+ required: true,
},
timestamp: {
type: Date,
trim: true,
- required: true
+ required: true,
},
activityJson: {
type: String,
- trim: true
+ trim: true,
},
actorJson: {
type: String,
- trim: true
+ trim: true,
},
activityId: {
type: String,
- trim: true
+ trim: true,
},
actorId: {
type: String,
- trim: true
+ trim: true,
},
- replies: [ReplySchema]
-})
+ replies: [ReplySchema],
+});
const EventSchema = new mongoose.Schema({
id: {
type: String,
required: true,
- unique: true
+ unique: true,
},
type: {
type: String,
trim: true,
- required: true
+ required: true,
},
name: {
type: String,
trim: true,
- required: true
+ required: true,
},
location: {
type: String,
trim: true,
- required: true
+ required: true,
},
- start: { // Stored as a UTC timestamp
+ start: {
+ // Stored as a UTC timestamp
type: Date,
trim: true,
- required: true
+ required: true,
},
- end: { // Stored as a UTC timestamp
+ end: {
+ // Stored as a UTC timestamp
type: Date,
trim: true,
- required: true
+ required: true,
},
timezone: {
type: String,
- default: 'Etc/UTC'
+ default: "Etc/UTC",
},
description: {
type: String,
trim: true,
- required: true
+ required: true,
},
image: {
type: String,
- trim: true
+ trim: true,
},
url: {
type: String,
- trim: true
+ trim: true,
},
creatorEmail: {
type: String,
- trim: true
+ trim: true,
},
hostName: {
type: String,
- trim: true
+ trim: true,
},
viewPassword: {
type: String,
- trim: true
+ trim: true,
},
editPassword: {
type: String,
- trim: true
+ trim: true,
},
editToken: {
type: String,
trim: true,
minlength: 32,
- maxlength: 32
+ maxlength: 32,
},
- eventGroup: { type: mongoose.Schema.Types.ObjectId, ref: 'EventGroup' },
+ eventGroup: { type: mongoose.Schema.Types.ObjectId, ref: "EventGroup" },
usersCanAttend: {
type: Boolean,
trim: true,
- default: false
+ default: false,
},
showUsersList: {
type: Boolean,
trim: true,
- default: false
+ default: false,
},
usersCanComment: {
type: Boolean,
trim: true,
- default: false
+ default: false,
},
firstLoad: {
type: Boolean,
trim: true,
- default: true
+ default: true,
},
attendees: [Attendees],
maxAttendees: {
- type: Number
+ type: Number,
},
comments: [CommentSchema],
activityPubActor: {
type: String,
- trim: true
+ trim: true,
},
activityPubEvent: {
type: String,
- trim: true
+ trim: true,
},
publicKey: {
type: String,
- trim: true
+ trim: true,
},
privateKey: {
type: String,
- trim: true
+ trim: true,
},
followers: [Followers],
- activityPubMessages: [ActivityPubMessages]
+ activityPubMessages: [ActivityPubMessages],
});
-module.exports = mongoose.model('Event', EventSchema);
+module.exports = mongoose.model("Event", EventSchema);
diff --git a/models/EventGroup.js b/src/models/EventGroup.js
index c70ef95..1a4ac64 100755
--- a/models/EventGroup.js
+++ b/src/models/EventGroup.js
@@ -1,57 +1,57 @@
-const mongoose = require('mongoose');
+const mongoose = require("mongoose");
const Subscriber = new mongoose.Schema({
email: {
type: String,
- trim: true
+ trim: true,
},
-})
+});
const EventGroupSchema = new mongoose.Schema({
id: {
type: String,
required: true,
- unique: true
+ unique: true,
},
name: {
type: String,
trim: true,
- required: true
+ required: true,
},
description: {
type: String,
trim: true,
- required: true
+ required: true,
},
image: {
type: String,
- trim: true
+ trim: true,
},
url: {
type: String,
- trim: true
+ trim: true,
},
creatorEmail: {
type: String,
- trim: true
+ trim: true,
},
hostName: {
type: String,
- trim: true
+ trim: true,
},
editToken: {
type: String,
trim: true,
minlength: 32,
- maxlength: 32
+ maxlength: 32,
},
firstLoad: {
type: Boolean,
trim: true,
- default: true
+ default: true,
},
- events: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Event' }],
+ events: [{ type: mongoose.Schema.Types.ObjectId, ref: "Event" }],
subscribers: [Subscriber],
});
-module.exports = mongoose.model('EventGroup', EventGroupSchema);
+module.exports = mongoose.model("EventGroup", EventGroupSchema);
diff --git a/models/Log.js b/src/models/Log.js
index 95a3ab3..b048a45 100755
--- a/models/Log.js
+++ b/src/models/Log.js
@@ -1,26 +1,26 @@
-const mongoose = require('mongoose');
+const mongoose = require("mongoose");
const LogSchema = new mongoose.Schema({
status: {
type: String,
trim: true,
- required: true
+ required: true,
},
process: {
type: String,
trim: true,
- required: true
+ required: true,
},
message: {
type: String,
trim: true,
- required: true
+ required: true,
},
timestamp: {
type: Date,
trim: true,
- required: true
- }
+ required: true,
+ },
});
-module.exports = mongoose.model('Log', LogSchema);
+module.exports = mongoose.model("Log", LogSchema);
diff --git a/src/routes.js b/src/routes.js
new file mode 100755
index 0000000..0d59b65
--- /dev/null
+++ b/src/routes.js
@@ -0,0 +1,2853 @@
+const fs = require("fs");
+
+const express = require("express");
+
+const mongoose = require("mongoose");
+
+// This alphabet (used to generate all event, group, etc. IDs) is missing '-'
+// because ActivityPub doesn't like it in IDs
+const { customAlphabet } = require("nanoid");
+const nanoid = customAlphabet(
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_",
+ 21
+);
+
+const randomstring = require("randomstring");
+
+const { body, validationResult } = require("express-validator");
+
+const router = express.Router();
+
+const Event = mongoose.model("Event");
+const EventGroup = mongoose.model("EventGroup");
+const addToLog = require("./helpers.js").addToLog;
+
+var moment = require("moment-timezone");
+
+const marked = require("marked");
+
+const generateRSAKeypair = require("generate-rsa-keypair");
+const crypto = require("crypto");
+const request = require("request");
+const niceware = require("niceware");
+
+const domain = require("./config/domain.js").domain;
+const contactEmail = require("./config/domain.js").email;
+const mailService = require("./config/domain.js").mailService;
+const siteName = require("./config/domain.js").sitename;
+const siteLogo = require("./config/domain.js").logo_url;
+let isFederated = require("./config/domain.js").isFederated;
+let showKofi = require("./config/domain.js").showKofi;
+// if the federation config isn't set, things are federated by default
+if (isFederated === undefined) {
+ isFederated = true;
+}
+const ap = require("./activitypub.js");
+
+// Extra marked renderer (used to render plaintext event description for page metadata)
+// Adapted from https://dustinpfister.github.io/2017/11/19/nodejs-marked/
+// &#63; to ? helper
+function htmlEscapeToText(text) {
+ return text.replace(/\&\#[0-9]*;|&amp;/g, function (escapeCode) {
+ if (escapeCode.match(/amp/)) {
+ return "&";
+ }
+ return String.fromCharCode(escapeCode.match(/[0-9]+/));
+ });
+}
+
+function render_plain() {
+ var render = new marked.Renderer();
+ // render just the text of a link, strong, em
+ render.link = function (href, title, text) {
+ return text;
+ };
+ render.strong = function (text) {
+ return text;
+ };
+ render.em = function (text) {
+ return text;
+ };
+ // render just the text of a paragraph
+ render.paragraph = function (text) {
+ return htmlEscapeToText(text) + "\r\n";
+ };
+ // render nothing for headings, images, and br
+ render.heading = function (text, level) {
+ return "";
+ };
+ render.image = function (href, title, text) {
+ return "";
+ };
+ render.br = function () {
+ return "";
+ };
+ return render;
+}
+
+const ical = require("ical");
+const { exportIcal } = require("./helpers.js");
+
+const sgMail = require("@sendgrid/mail");
+const nodemailer = require("nodemailer");
+
+const apiCredentials = require("./config/api.js");
+
+let sendEmails = false;
+let nodemailerTransporter;
+if (mailService) {
+ switch (mailService) {
+ case "sendgrid":
+ sgMail.setApiKey(apiCredentials.sendgrid);
+ console.log("Sendgrid is ready to send emails.");
+ sendEmails = true;
+ break;
+ case "nodemailer":
+ nodemailerTransporter = nodemailer.createTransport({
+ host: apiCredentials.smtpServer,
+ port: apiCredentials.smtpPort,
+ secure: false, // true for 465, false for other ports
+ auth: {
+ user: apiCredentials.smtpUsername, // generated ethereal user
+ pass: apiCredentials.smtpPassword, // generated ethereal password
+ },
+ });
+ nodemailerTransporter.verify((error, success) => {
+ if (error) {
+ console.log(error);
+ } else {
+ console.log("Nodemailer SMTP server is ready to send emails.");
+ sendEmails = true;
+ }
+ });
+ break;
+ default:
+ console.error(
+ "You have not configured this Gathio instance to send emails! This means that event creators will not receive emails when their events are created, which means they may end up locked out of editing events. Consider setting up an email service."
+ );
+ }
+}
+
+const fileUpload = require("express-fileupload");
+var Jimp = require("jimp");
+router.use(fileUpload());
+
+// SCHEDULED DELETION
+const schedule = require("node-schedule");
+schedule.scheduleJob("59 23 * * *", function (fireDate) {
+ const too_old = moment.tz("Etc/UTC").subtract(7, "days").toDate();
+ console.log(
+ "Old event deletion running! Deleting all events concluding before ",
+ too_old
+ );
+
+ Event.find({ end: { $lte: too_old } })
+ .then((oldEvents) => {
+ oldEvents.forEach((event) => {
+ const deleteEventFromDB = (id) => {
+ Event.remove({ _id: id })
+ .then((response) => {
+ addToLog(
+ "deleteOldEvents",
+ "success",
+ "Old event " + id + " deleted"
+ );
+ })
+ .catch((err) => {
+ addToLog(
+ "deleteOldEvents",
+ "error",
+ "Attempt to delete old event " +
+ id +
+ " failed with error: " +
+ err
+ );
+ });
+ };
+
+ if (event.image) {
+ fs.unlink(global.appRoot + "/public/events/" + event.image, (err) => {
+ if (err) {
+ addToLog(
+ "deleteOldEvents",
+ "error",
+ "Attempt to delete event image for old event " +
+ event.id +
+ " failed with error: " +
+ err
+ );
+ }
+ // Image removed
+ addToLog(
+ "deleteOldEvents",
+ "error",
+ "Image deleted for old event " + event.id
+ );
+ });
+ }
+ // Check if event has ActivityPub fields
+ if (event.activityPubActor && event.activityPubEvent) {
+ // Broadcast a Delete profile message to all followers so that at least Mastodon servers will delete their local profile information
+ const guidUpdateObject = crypto.randomBytes(16).toString("hex");
+ const jsonUpdateObject = JSON.parse(event.activityPubActor);
+ const jsonEventObject = JSON.parse(event.activityPubEvent);
+ // first broadcast AP messages, THEN delete from DB
+ ap.broadcastDeleteMessage(
+ jsonUpdateObject,
+ event.followers,
+ event.id,
+ function (statuses) {
+ ap.broadcastDeleteMessage(
+ jsonEventObject,
+ event.followers,
+ event.id,
+ function (statuses) {
+ deleteEventFromDB(event._id);
+ }
+ );
+ }
+ );
+ } else {
+ // No ActivityPub data - simply delete the event
+ deleteEventFromDB(event._id);
+ }
+ });
+ })
+ .catch((err) => {
+ addToLog(
+ "deleteOldEvents",
+ "error",
+ "Attempt to delete old event " + event.id + " failed with error: " + err
+ );
+ });
+
+ // TODO: While we're here, also remove all provisioned event attendees over a day
+ // old (they're not going to become active)
+});
+
+// FRONTEND ROUTES
+
+router.get("/", (req, res) => {
+ res.render("home", {
+ domain,
+ email: contactEmail,
+ siteName,
+ showKofi,
+ });
+});
+
+router.get("/new", (req, res) => {
+ res.render("home");
+});
+
+router.get("/new/event", (req, res) => {
+ res.render("newevent", {
+ domain: domain,
+ email: contactEmail,
+ siteName: siteName,
+ });
+});
+router.get("/new/event/public", (req, res) => {
+ let isPrivate = false;
+ let isPublic = true;
+ let isOrganisation = false;
+ let isUnknownType = false;
+ res.render("newevent", {
+ title: "New event",
+ isPrivate: isPrivate,
+ isPublic: isPublic,
+ isOrganisation: isOrganisation,
+ isUnknownType: isUnknownType,
+ eventType: "public",
+ domain: domain,
+ email: contactEmail,
+ siteName: siteName,
+ });
+});
+
+// return the JSON for the featured/pinned post for this event
+router.get("/:eventID/featured", (req, res) => {
+ if (!isFederated) return res.sendStatus(404);
+ const { eventID } = req.params;
+ const guidObject = crypto.randomBytes(16).toString("hex");
+ const featured = {
+ "@context": "https://www.w3.org/ns/activitystreams",
+ id: `https://${domain}/${eventID}/featured`,
+ type: "OrderedCollection",
+ orderedItems: [ap.createFeaturedPost(eventID)],
+ };
+ res.json(featured);
+});
+
+// return the JSON for a given activitypub message
+router.get("/:eventID/m/:hash", (req, res) => {
+ if (!isFederated) return res.sendStatus(404);
+ const { hash, eventID } = req.params;
+ const id = `https://${domain}/${eventID}/m/${hash}`;
+
+ Event.findOne({
+ id: eventID,
+ })
+ .then((event) => {
+ if (!event) {
+ res.status(404);
+ res.render("404", { url: req.url });
+ } else {
+ const message = event.activityPubMessages.find((el) => el.id === id);
+ if (message) {
+ return res.json(JSON.parse(message.content));
+ } else {
+ res.status(404);
+ return res.render("404", { url: req.url });
+ }
+ }
+ })
+ .catch((err) => {
+ addToLog(
+ "getActivityPubMessage",
+ "error",
+ "Attempt to get Activity Pub Message for " +
+ id +
+ " failed with error: " +
+ err
+ );
+ res.status(404);
+ res.render("404", { url: req.url });
+ return;
+ });
+});
+
+// return the webfinger record required for the initial activitypub handshake
+router.get("/.well-known/webfinger", (req, res) => {
+ if (!isFederated) return res.sendStatus(404);
+ let resource = req.query.resource;
+ if (!resource || !resource.includes("acct:")) {
+ return res
+ .status(400)
+ .send(
+ 'Bad request. Please make sure "acct:USER@DOMAIN" is what you are sending as the "resource" query parameter.'
+ );
+ } else {
+ // "foo@domain"
+ let activityPubAccount = resource.replace("acct:", "");
+ // "foo"
+ let eventID = activityPubAccount.replace(/@.*/, "");
+ Event.findOne({
+ id: eventID,
+ })
+ .then((event) => {
+ if (!event) {
+ res.status(404);
+ res.render("404", { url: req.url });
+ } else {
+ res.json(ap.createWebfinger(eventID, domain));
+ }
+ })
+ .catch((err) => {
+ addToLog(
+ "renderWebfinger",
+ "error",
+ "Attempt to render webfinger for " +
+ req.params.eventID +
+ " failed with error: " +
+ err
+ );
+ res.status(404);
+ res.render("404", { url: req.url });
+ return;
+ });
+ }
+});
+
+router.get("/:eventID", (req, res) => {
+ Event.findOne({
+ id: req.params.eventID,
+ })
+ .lean() // Required, see: https://stackoverflow.com/questions/59690923/handlebars-access-has-been-denied-to-resolve-the-property-from-because-it-is
+ .populate("eventGroup")
+ .then((event) => {
+ if (event) {
+ const parsedLocation = event.location.replace(/\s+/g, "+");
+ let displayDate;
+ if (moment.tz(event.end, event.timezone).isSame(event.start, "day")) {
+ // Happening during one day
+ displayDate =
+ moment
+ .tz(event.start, event.timezone)
+ .format(
+ 'dddd D MMMM YYYY [<span class="text-muted">from</span>] h:mm a'
+ ) +
+ moment
+ .tz(event.end, event.timezone)
+ .format(
+ ' [<span class="text-muted">to</span>] h:mm a [<span class="text-muted">](z)[</span>]'
+ );
+ } else {
+ displayDate =
+ moment
+ .tz(event.start, event.timezone)
+ .format(
+ 'dddd D MMMM YYYY [<span class="text-muted">at</span>] h:mm a'
+ ) +
+ moment
+ .tz(event.end, event.timezone)
+ .format(
+ ' [<span class="text-muted">–</span>] dddd D MMMM YYYY [<span class="text-muted">at</span>] h:mm a [<span class="text-muted">](z)[</span>]'
+ );
+ }
+ let eventStartISO = moment.tz(event.start, "Etc/UTC").toISOString();
+ let eventEndISO = moment.tz(event.end, "Etc/UTC").toISOString();
+ let parsedStart = moment
+ .tz(event.start, event.timezone)
+ .format("YYYYMMDD[T]HHmmss");
+ let parsedEnd = moment
+ .tz(event.end, event.timezone)
+ .format("YYYYMMDD[T]HHmmss");
+ let eventHasConcluded = false;
+ if (
+ moment
+ .tz(event.end, event.timezone)
+ .isBefore(moment.tz(event.timezone))
+ ) {
+ eventHasConcluded = true;
+ }
+ let eventHasBegun = false;
+ if (
+ moment
+ .tz(event.start, event.timezone)
+ .isBefore(moment.tz(event.timezone))
+ ) {
+ eventHasBegun = true;
+ }
+ let fromNow = moment.tz(event.start, event.timezone).fromNow();
+ let parsedDescription = marked.parse(event.description);
+ let eventEditToken = event.editToken;
+
+ let escapedName = event.name.replace(/\s+/g, "+");
+
+ let eventHasCoverImage = false;
+ if (event.image) {
+ eventHasCoverImage = true;
+ } else {
+ eventHasCoverImage = false;
+ }
+ let eventHasHost = false;
+ if (event.hostName) {
+ eventHasHost = true;
+ } else {
+ eventHasHost = false;
+ }
+ let firstLoad = false;
+ if (event.firstLoad === true) {
+ firstLoad = true;
+ Event.findOneAndUpdate(
+ { id: req.params.eventID },
+ { firstLoad: false },
+ function (err, raw) {
+ if (err) {
+ res.send(err);
+ }
+ }
+ );
+ }
+ let editingEnabled = false;
+ if (Object.keys(req.query).length !== 0) {
+ if (!req.query.e) {
+ editingEnabled = false;
+ console.log("No edit token set");
+ } else {
+ if (req.query.e === eventEditToken) {
+ editingEnabled = true;
+ } else {
+ editingEnabled = false;
+ }
+ }
+ }
+ let eventAttendees = event.attendees
+ .sort((a, b) => (a.name > b.name ? 1 : b.name > a.name ? -1 : 0))
+ .map((el) => {
+ if (!el.id) {
+ el.id = el._id;
+ }
+ if (el.number > 1) {
+ el.name = `${el.name} (${el.number} people)`;
+ }
+ return el;
+ })
+ .filter((obj, pos, arr) => {
+ return (
+ obj.status === "attending" &&
+ arr.map((mapObj) => mapObj.id).indexOf(obj.id) === pos
+ );
+ });
+
+ let spotsRemaining, noMoreSpots;
+ let numberOfAttendees = eventAttendees.reduce((acc, attendee) => {
+ if (attendee.status === "attending") {
+ return acc + attendee.number || 1;
+ }
+ return acc;
+ }, 0);
+ if (event.maxAttendees) {
+ spotsRemaining = event.maxAttendees - numberOfAttendees;
+ if (spotsRemaining <= 0) {
+ noMoreSpots = true;
+ }
+ }
+ let metadata = {
+ title: event.name,
+ description: marked
+ .parse(event.description, { renderer: render_plain() })
+ .split(" ")
+ .splice(0, 40)
+ .join(" ")
+ .trim(),
+ image: eventHasCoverImage
+ ? `https://${domain}/events/` + event.image
+ : null,
+ url: `https://${domain}/` + req.params.eventID,
+ };
+ if (
+ req.headers.accept &&
+ (req.headers.accept.includes("application/activity+json") ||
+ req.headers.accept.includes("application/json") ||
+ req.headers.accept.includes("application/json+ld"))
+ ) {
+ res.json(JSON.parse(event.activityPubActor));
+ } else {
+ res.set("X-Robots-Tag", "noindex");
+ res.render("event", {
+ domain: domain,
+ isFederated: isFederated,
+ email: contactEmail,
+ title: event.name,
+ escapedName: escapedName,
+ eventData: event,
+ eventAttendees: eventAttendees,
+ numberOfAttendees,
+ spotsRemaining: spotsRemaining,
+ noMoreSpots: noMoreSpots,
+ eventStartISO: eventStartISO,
+ eventEndISO: eventEndISO,
+ parsedLocation: parsedLocation,
+ parsedStart: parsedStart,
+ parsedEnd: parsedEnd,
+ displayDate: displayDate,
+ fromNow: fromNow,
+ timezone: event.timezone,
+ parsedDescription: parsedDescription,
+ editingEnabled: editingEnabled,
+ eventHasCoverImage: eventHasCoverImage,
+ eventHasHost: eventHasHost,
+ firstLoad: firstLoad,
+ eventHasConcluded: eventHasConcluded,
+ eventHasBegun: eventHasBegun,
+ metadata: metadata,
+ siteName: siteName,
+ });
+ }
+ } else {
+ res.status(404);
+ res.render("404", { url: req.url });
+ }
+ })
+ .catch((err) => {
+ addToLog(
+ "displayEvent",
+ "error",
+ "Attempt to display event " +
+ req.params.eventID +
+ " failed with error: " +
+ err
+ );
+ console.log(err);
+ res.status(404);
+ res.render("404", { url: req.url });
+ return;
+ });
+});
+
+router.get("/:eventID/followers", (req, res) => {
+ if (!isFederated) return res.sendStatus(404);
+ const eventID = req.params.eventID;
+ Event.findOne({
+ id: eventID,
+ }).then((event) => {
+ if (event) {
+ const followers = event.followers.map((el) => el.actorId);
+ let followersCollection = {
+ type: "OrderedCollection",
+ totalItems: followers.length,
+ id: `https://${domain}/${eventID}/followers`,
+ first: {
+ type: "OrderedCollectionPage",
+ totalItems: followers.length,
+ partOf: `https://${domain}/${eventID}/followers`,
+ orderedItems: followers,
+ id: `https://${domain}/${eventID}/followers?page=1`,
+ },
+ "@context": ["https://www.w3.org/ns/activitystreams"],
+ };
+ return res.json(followersCollection);
+ } else {
+ return res.status(400).send("Bad request.");
+ }
+ });
+});
+
+router.get("/group/:eventGroupID", (req, res) => {
+ EventGroup.findOne({
+ id: req.params.eventGroupID,
+ })
+ .lean() // Required, see: https://stackoverflow.com/questions/59690923/handlebars-access-has-been-denied-to-resolve-the-property-from-because-it-is
+ .then(async (eventGroup) => {
+ if (eventGroup) {
+ let parsedDescription = marked.parse(eventGroup.description);
+ let eventGroupEditToken = eventGroup.editToken;
+
+ let escapedName = eventGroup.name.replace(/\s+/g, "+");
+
+ let eventGroupHasCoverImage = false;
+ if (eventGroup.image) {
+ eventGroupHasCoverImage = true;
+ } else {
+ eventGroupHasCoverImage = false;
+ }
+ let eventGroupHasHost = false;
+ if (eventGroup.hostName) {
+ eventGroupHasHost = true;
+ } else {
+ eventGroupHasHost = false;
+ }
+
+ let events = await Event.find({ eventGroup: eventGroup._id })
+ .lean()
+ .sort("start");
+
+ events.map((event) => {
+ if (moment.tz(event.end, event.timezone).isSame(event.start, "day")) {
+ // Happening during one day
+ event.displayDate = moment
+ .tz(event.start, event.timezone)
+ .format("D MMM YYYY");
+ } else {
+ event.displayDate =
+ moment.tz(event.start, event.timezone).format("D MMM YYYY") +
+ moment.tz(event.end, event.timezone).format(" - D MMM YYYY");
+ }
+ if (
+ moment
+ .tz(event.end, event.timezone)
+ .isBefore(moment.tz(event.timezone))
+ ) {
+ event.eventHasConcluded = true;
+ } else {
+ event.eventHasConcluded = false;
+ }
+ return (({ id, name, displayDate, eventHasConcluded }) => ({
+ id,
+ name,
+ displayDate,
+ eventHasConcluded,
+ }))(event);
+ });
+
+ let upcomingEventsExist = false;
+ if (events.some((e) => e.eventHasConcluded === false)) {
+ upcomingEventsExist = true;
+ }
+
+ let firstLoad = false;
+ if (eventGroup.firstLoad === true) {
+ firstLoad = true;
+ EventGroup.findOneAndUpdate(
+ { id: req.params.eventGroupID },
+ { firstLoad: false },
+ function (err, raw) {
+ if (err) {
+ res.send(err);
+ }
+ }
+ );
+ }
+ let editingEnabled = false;
+ if (Object.keys(req.query).length !== 0) {
+ if (!req.query.e) {
+ editingEnabled = false;
+ console.log("No edit token set");
+ } else {
+ if (req.query.e === eventGroupEditToken) {
+ editingEnabled = true;
+ } else {
+ editingEnabled = false;
+ }
+ }
+ }
+ let metadata = {
+ title: eventGroup.name,
+ description: marked
+ .parse(eventGroup.description, { renderer: render_plain() })
+ .split(" ")
+ .splice(0, 40)
+ .join(" ")
+ .trim(),
+ image: eventGroupHasCoverImage
+ ? `https://${domain}/events/` + eventGroup.image
+ : null,
+ url: `https://${domain}/` + req.params.eventID,
+ };
+ res.set("X-Robots-Tag", "noindex");
+ res.render("eventgroup", {
+ domain: domain,
+ title: eventGroup.name,
+ eventGroupData: eventGroup,
+ escapedName: escapedName,
+ events: events,
+ upcomingEventsExist: upcomingEventsExist,
+ parsedDescription: parsedDescription,
+ editingEnabled: editingEnabled,
+ eventGroupHasCoverImage: eventGroupHasCoverImage,
+ eventGroupHasHost: eventGroupHasHost,
+ firstLoad: firstLoad,
+ metadata: metadata,
+ });
+ } else {
+ res.status(404);
+ res.render("404", { url: req.url });
+ }
+ })
+ .catch((err) => {
+ addToLog(
+ "displayEventGroup",
+ "error",
+ "Attempt to display event group " +
+ req.params.eventGroupID +
+ " failed with error: " +
+ err
+ );
+ console.log(err);
+ res.status(404);
+ res.render("404", { url: req.url });
+ return;
+ });
+});
+
+router.get("/group/:eventGroupID/feed.ics", (req, res) => {
+ EventGroup.findOne({
+ id: req.params.eventGroupID,
+ })
+ .lean() // Required, see: https://stackoverflow.com/questions/59690923/handlebars-access-has-been-denied-to-resolve-the-property-from-because-it-is
+ .then(async (eventGroup) => {
+ if (eventGroup) {
+ let events = await Event.find({ eventGroup: eventGroup._id })
+ .lean()
+ .sort("start");
+ const string = exportIcal(events, eventGroup.name);
+ res.set("Content-Type", "text/calendar");
+ return res.send(string);
+ }
+ })
+ .catch((err) => {
+ addToLog(
+ "eventGroupFeed",
+ "error",
+ "Attempt to display event group feed for " +
+ req.params.eventGroupID +
+ " failed with error: " +
+ err
+ );
+ console.log(err);
+ res.status(404);
+ res.render("404", { url: req.url });
+ return;
+ });
+});
+
+router.get("/exportevent/:eventID", (req, res) => {
+ Event.findOne({
+ id: req.params.eventID,
+ })
+ .populate("eventGroup")
+ .then((event) => {
+ if (event) {
+ const string = exportIcal([event]);
+ res.send(string);
+ }
+ })
+ .catch((err) => {
+ addToLog(
+ "exportEvent",
+ "error",
+ "Attempt to export event " +
+ req.params.eventID +
+ " failed with error: " +
+ err
+ );
+ console.log(err);
+ res.status(404);
+ res.render("404", { url: req.url });
+ return;
+ });
+});
+
+router.get("/exportgroup/:eventGroupID", (req, res) => {
+ EventGroup.findOne({
+ id: req.params.eventGroupID,
+ })
+ .lean() // Required, see: https://stackoverflow.com/questions/59690923/handlebars-access-has-been-denied-to-resolve-the-property-from-because-it-is
+ .then(async (eventGroup) => {
+ if (eventGroup) {
+ let events = await Event.find({ eventGroup: eventGroup._id })
+ .lean()
+ .sort("start");
+ const string = exportIcal(events);
+ res.send(string);
+ }
+ })
+ .catch((err) => {
+ addToLog(
+ "exportEvent",
+ "error",
+ "Attempt to export event group " +
+ req.params.eventGroupID +
+ " failed with error: " +
+ err
+ );
+ console.log(err);
+ res.status(404);
+ res.render("404", { url: req.url });
+ return;
+ });
+});
+
+// BACKEND ROUTES
+
+router.post("/newevent", async (req, res) => {
+ let eventID = nanoid();
+ let editToken = randomstring.generate();
+ let eventImageFilename = "";
+ let isPartOfEventGroup = false;
+ if (req.files && Object.keys(req.files).length !== 0) {
+ let eventImageBuffer = req.files.imageUpload.data;
+ eventImageFilename = await Jimp.read(eventImageBuffer)
+ .then((img) => {
+ img
+ .resize(920, Jimp.AUTO) // resize
+ .quality(80) // set JPEG quality
+ .write("./public/events/" + eventID + ".jpg"); // save
+ const filename = eventID + ".jpg";
+ return filename;
+ })
+ .catch((err) => {
+ addToLog(
+ "Jimp",
+ "error",
+ "Attempt to edit image failed with error: " + err
+ );
+ });
+ }
+ let startUTC = moment.tz(
+ req.body.eventStart,
+ "D MMMM YYYY, hh:mm a",
+ req.body.timezone
+ );
+ let endUTC = moment.tz(
+ req.body.eventEnd,
+ "D MMMM YYYY, hh:mm a",
+ req.body.timezone
+ );
+ let eventGroup;
+ if (req.body.eventGroupCheckbox) {
+ eventGroup = await EventGroup.findOne({
+ id: req.body.eventGroupID,
+ editToken: req.body.eventGroupEditToken,
+ });
+ if (eventGroup) {
+ isPartOfEventGroup = true;
+ }
+ }
+
+ // generate RSA keypair for ActivityPub
+ let pair = generateRSAKeypair();
+
+ const event = new Event({
+ id: eventID,
+ type: req.body.eventType,
+ name: req.body.eventName,
+ location: req.body.eventLocation,
+ start: startUTC,
+ end: endUTC,
+ timezone: req.body.timezone,
+ description: req.body.eventDescription,
+ image: eventImageFilename,
+ creatorEmail: req.body.creatorEmail,
+ url: req.body.eventURL,
+ hostName: req.body.hostName,
+ viewPassword: req.body.viewPassword,
+ editPassword: req.body.editPassword,
+ editToken: editToken,
+ eventGroup: isPartOfEventGroup ? eventGroup._id : null,
+ usersCanAttend: req.body.joinCheckbox ? true : false,
+ showUsersList: req.body.guestlistCheckbox ? true : false,
+ usersCanComment: req.body.interactionCheckbox ? true : false,
+ maxAttendees: req.body.maxAttendees,
+ firstLoad: true,
+ activityPubActor: ap.createActivityPubActor(
+ eventID,
+ domain,
+ pair.public,
+ marked.parse(req.body.eventDescription),
+ req.body.eventName,
+ req.body.eventLocation,
+ eventImageFilename,
+ startUTC,
+ endUTC,
+ req.body.timezone
+ ),
+ activityPubEvent: ap.createActivityPubEvent(
+ req.body.eventName,
+ startUTC,
+ endUTC,
+ req.body.timezone,
+ req.body.eventDescription,
+ req.body.eventLocation
+ ),
+ activityPubMessages: [
+ {
+ id: `https://${domain}/${eventID}/m/featuredPost`,
+ content: JSON.stringify(
+ ap.createFeaturedPost(
+ eventID,
+ req.body.eventName,
+ startUTC,
+ endUTC,
+ req.body.timezone,
+ req.body.eventDescription,
+ req.body.eventLocation
+ )
+ ),
+ },
+ ],
+ publicKey: pair.public,
+ privateKey: pair.private,
+ });
+ event
+ .save()
+ .then((event) => {
+ addToLog("createEvent", "success", "Event " + eventID + "created");
+ // Send email with edit link
+ if (req.body.creatorEmail && sendEmails) {
+ req.app.get("hbsInstance").renderView(
+ "./views/emails/createevent.handlebars",
+ {
+ eventID,
+ editToken,
+ siteName,
+ siteLogo,
+ domain,
+ cache: true,
+ layout: "email.handlebars",
+ },
+ function (err, html) {
+ const msg = {
+ to: req.body.creatorEmail,
+ from: {
+ name: siteName,
+ email: contactEmail,
+ address: contactEmail,
+ },
+ subject: `${siteName}: ${req.body.eventName}`,
+ html,
+ };
+ switch (mailService) {
+ case "sendgrid":
+ sgMail.send(msg).catch((e) => {
+ console.error(e.toString());
+ res.status(500).end();
+ });
+ break;
+ case "nodemailer":
+ nodemailerTransporter.sendMail(msg).catch((e) => {
+ console.error(e.toString());
+ res.status(500).end();
+ });
+ break;
+ }
+ }
+ );
+ }
+ // If the event was added to a group, send an email to any group
+ // subscribers
+ if (event.eventGroup && sendEmails) {
+ EventGroup.findOne({ _id: event.eventGroup._id }).then((eventGroup) => {
+ const subscribers = eventGroup.subscribers.reduce((acc, current) => {
+ if (acc.includes(current.email)) {
+ return acc;
+ }
+ return [current.email, ...acc];
+ }, []);
+ subscribers.forEach((emailAddress) => {
+ req.app.get("hbsInstance").renderView(
+ "./views/emails/eventgroupupdated.handlebars",
+ {
+ siteName,
+ siteLogo,
+ domain,
+ eventID: req.params.eventID,
+ eventGroupName: eventGroup.name,
+ eventName: event.name,
+ eventID: event.id,
+ eventGroupID: eventGroup.id,
+ emailAddress: encodeURIComponent(emailAddress),
+ cache: true,
+ layout: "email.handlebars",
+ },
+ function (err, html) {
+ const msg = {
+ to: emailAddress,
+ from: {
+ name: siteName,
+ email: contactEmail,
+ },
+ subject: `${siteName}: New event in ${eventGroup.name}`,
+ html,
+ };
+ switch (mailService) {
+ case "sendgrid":
+ sgMail.send(msg).catch((e) => {
+ console.error(e.toString());
+ res.status(500).end();
+ });
+ break;
+ case "nodemailer":
+ nodemailerTransporter.sendMail(msg).catch((e) => {
+ console.error(e.toString());
+ res.status(500).end();
+ });
+ break;
+ }
+ }
+ );
+ });
+ });
+ }
+ res.writeHead(302, {
+ Location: "/" + eventID + "?e=" + editToken,
+ });
+ res.end();
+ })
+ .catch((err) => {
+ res.status(500).send("Database error, please try again :( - " + err);
+ addToLog(
+ "createEvent",
+ "error",
+ "Attempt to create event failed with error: " + err
+ );
+ });
+});
+
+router.post("/importevent", (req, res) => {
+ let eventID = nanoid();
+ let editToken = randomstring.generate();
+ if (req.files && Object.keys(req.files).length !== 0) {
+ let iCalObject = ical.parseICS(
+ req.files.icsImportControl.data.toString("utf8")
+ );
+ let importedEventData = iCalObject[Object.keys(iCalObject)];
+
+ let creatorEmail;
+ if (req.body.creatorEmail) {
+ creatorEmail = req.body.creatorEmail;
+ } else if (importedEventData.organizer) {
+ creatorEmail = importedEventData.organizer.val.replace("MAILTO:", "");
+ }
+
+ const event = new Event({
+ id: eventID,
+ type: "public",
+ name: importedEventData.summary,
+ location: importedEventData.location,
+ start: importedEventData.start,
+ end: importedEventData.end,
+ timezone:
+ typeof importedEventData.start.tz !== "undefined"
+ ? importedEventData.start.tz
+ : "Etc/UTC",
+ description: importedEventData.description,
+ image: "",
+ creatorEmail: creatorEmail,
+ url: "",
+ hostName: importedEventData.organizer
+ ? importedEventData.organizer.params.CN.replace(/["]+/g, "")
+ : "",
+ viewPassword: "",
+ editPassword: "",
+ editToken: editToken,
+ usersCanAttend: false,
+ showUsersList: false,
+ usersCanComment: false,
+ firstLoad: true,
+ });
+ event
+ .save()
+ .then(() => {
+ addToLog("createEvent", "success", "Event " + eventID + " created");
+ // Send email with edit link
+ if (creatorEmail && sendEmails) {
+ req.app.get("hbsInstance").renderView(
+ "./views/emails/createevent.handlebars",
+ {
+ eventID,
+ editToken,
+ siteName,
+ siteLogo,
+ domain,
+ cache: true,
+ layout: "email.handlebars",
+ },
+ function (err, html) {
+ const msg = {
+ to: req.body.creatorEmail,
+ from: {
+ name: siteName,
+ email: contactEmail,
+ address: contactEmail,
+ },
+ subject: `${siteName}: ${importedEventData.summary}`,
+ html,
+ };
+ switch (mailService) {
+ case "sendgrid":
+ sgMail.send(msg).catch((e) => {
+ console.error(e.toString());
+ res.status(500).end();
+ });
+ break;
+ case "nodemailer":
+ nodemailerTransporter.sendMail(msg).catch((e) => {
+ console.error(e.toString());
+ res.status(500).end();
+ });
+ break;
+ }
+ }
+ );
+ }
+ res.writeHead(302, {
+ Location: "/" + eventID + "?e=" + editToken,
+ });
+ res.end();
+ })
+ .catch((err) => {
+ res.send("Database error, please try again :(");
+ addToLog(
+ "createEvent",
+ "error",
+ "Attempt to create event failed with error: " + err
+ );
+ });
+ } else {
+ console.log("Files array is empty!");
+ res.status(500).end();
+ }
+});
+
+router.post("/neweventgroup", (req, res) => {
+ let eventGroupID = nanoid();
+ let editToken = randomstring.generate();
+ let eventGroupImageFilename = "";
+ if (req.files && Object.keys(req.files).length !== 0) {
+ let eventImageBuffer = req.files.imageUpload.data;
+ Jimp.read(eventImageBuffer, (err, img) => {
+ if (err)
+ addToLog(
+ "Jimp",
+ "error",
+ "Attempt to edit image failed with error: " + err
+ );
+ img
+ .resize(920, Jimp.AUTO) // resize
+ .quality(80) // set JPEG quality
+ .write("./public/events/" + eventGroupID + ".jpg"); // save
+ });
+ eventGroupImageFilename = eventGroupID + ".jpg";
+ }
+ const eventGroup = new EventGroup({
+ id: eventGroupID,
+ name: req.body.eventGroupName,
+ description: req.body.eventGroupDescription,
+ image: eventGroupImageFilename,
+ creatorEmail: req.body.creatorEmail,
+ url: req.body.eventGroupURL,
+ hostName: req.body.hostName,
+ editToken: editToken,
+ firstLoad: true,
+ });
+ eventGroup
+ .save()
+ .then(() => {
+ addToLog(
+ "createEventGroup",
+ "success",
+ "Event group " + eventGroupID + " created"
+ );
+ // Send email with edit link
+ if (req.body.creatorEmail && sendEmails) {
+ req.app.get("hbsInstance").renderView(
+ "./views/emails/createeventgroup.handlebars",
+ {
+ eventGroupID,
+ editToken,
+ siteName,
+ siteLogo,
+ domain,
+ cache: true,
+ layout: "email.handlebars",
+ },
+ function (err, html) {
+ const msg = {
+ to: req.body.creatorEmail,
+ from: {
+ name: siteName,
+ email: contactEmail,
+ address: contactEmail,
+ },
+ subject: `${siteName}: ${req.body.eventGroupName}`,
+ html,
+ };
+ switch (mailService) {
+ case "sendgrid":
+ sgMail.send(msg).catch((e) => {
+ console.error(e.toString());
+ res.status(500).end();
+ });
+ break;
+ case "nodemailer":
+ nodemailerTransporter.sendMail(msg).catch((e) => {
+ console.error(e.toString());
+ res.status(500).end();
+ });
+ break;
+ }
+ }
+ );
+ }
+ res.writeHead(302, {
+ Location: "/group/" + eventGroupID + "?e=" + editToken,
+ });
+ res.end();
+ })
+ .catch((err) => {
+ res.send("Database error, please try again :( - " + err);
+ addToLog(
+ "createEvent",
+ "error",
+ "Attempt to create event failed with error: " + err
+ );
+ });
+});
+
+router.post("/verifytoken/event/:eventID", (req, res) => {
+ Event.findOne({
+ id: req.params.eventID,
+ editToken: req.body.editToken,
+ }).then((event) => {
+ if (event) return res.sendStatus(200);
+ return res.sendStatus(404);
+ });
+});
+
+router.post("/verifytoken/group/:eventGroupID", (req, res) => {
+ EventGroup.findOne({
+ id: req.params.eventGroupID,
+ editToken: req.body.editToken,
+ }).then((group) => {
+ if (group) return res.sendStatus(200);
+ return res.sendStatus(404);
+ });
+});
+
+router.post("/editevent/:eventID/:editToken", (req, res) => {
+ let submittedEditToken = req.params.editToken;
+ Event.findOne({
+ id: req.params.eventID,
+ })
+ .then(async (event) => {
+ if (event.editToken === submittedEditToken) {
+ // Token matches
+
+ // If there is a new image, upload that first
+ let eventID = req.params.eventID;
+ let eventImageFilename = event.image;
+ if (req.files && Object.keys(req.files).length !== 0) {
+ let eventImageBuffer = req.files.imageUpload.data;
+ Jimp.read(eventImageBuffer, (err, img) => {
+ if (err) throw err;
+ img
+ .resize(920, Jimp.AUTO) // resize
+ .quality(80) // set JPEG
+ .write("./public/events/" + eventID + ".jpg"); // save
+ });
+ eventImageFilename = eventID + ".jpg";
+ }
+ let startUTC = moment.tz(
+ req.body.eventStart,
+ "D MMMM YYYY, hh:mm a",
+ req.body.timezone
+ );
+ let endUTC = moment.tz(
+ req.body.eventEnd,
+ "D MMMM YYYY, hh:mm a",
+ req.body.timezone
+ );
+
+ let isPartOfEventGroup = false;
+ let eventGroup;
+ if (req.body.eventGroupCheckbox) {
+ eventGroup = await EventGroup.findOne({
+ id: req.body.eventGroupID,
+ editToken: req.body.eventGroupEditToken,
+ });
+ if (eventGroup) {
+ isPartOfEventGroup = true;
+ }
+ }
+ const updatedEvent = {
+ name: req.body.eventName,
+ location: req.body.eventLocation,
+ start: startUTC,
+ end: endUTC,
+ timezone: req.body.timezone,
+ description: req.body.eventDescription,
+ url: req.body.eventURL,
+ hostName: req.body.hostName,
+ image: eventImageFilename,
+ usersCanAttend: req.body.joinCheckbox ? true : false,
+ showUsersList: req.body.guestlistCheckbox ? true : false,
+ usersCanComment: req.body.interactionCheckbox ? true : false,
+ maxAttendees: req.body.maxAttendeesCheckbox
+ ? req.body.maxAttendees
+ : null,
+ eventGroup: isPartOfEventGroup ? eventGroup._id : null,
+ activityPubActor: event.activityPubActor
+ ? ap.updateActivityPubActor(
+ JSON.parse(event.activityPubActor),
+ req.body.eventDescription,
+ req.body.eventName,
+ req.body.eventLocation,
+ eventImageFilename,
+ startUTC,
+ endUTC,
+ req.body.timezone
+ )
+ : null,
+ activityPubEvent: event.activityPubEvent
+ ? ap.updateActivityPubEvent(
+ JSON.parse(event.activityPubEvent),
+ req.body.eventName,
+ req.body.startUTC,
+ req.body.endUTC,
+ req.body.timezone
+ )
+ : null,
+ };
+ let diffText =
+ "<p>This event was just updated with new information.</p><ul>";
+ let displayDate;
+ if (event.name !== updatedEvent.name) {
+ diffText += `<li>the event name changed to ${updatedEvent.name}</li>`;
+ }
+ if (event.location !== updatedEvent.location) {
+ diffText += `<li>the location changed to ${updatedEvent.location}</li>`;
+ }
+ if (event.start.toISOString() !== updatedEvent.start.toISOString()) {
+ displayDate = moment
+ .tz(updatedEvent.start, updatedEvent.timezone)
+ .format("dddd D MMMM YYYY h:mm a");
+ diffText += `<li>the start time changed to ${displayDate}</li>`;
+ }
+ if (event.end.toISOString() !== updatedEvent.end.toISOString()) {
+ displayDate = moment
+ .tz(updatedEvent.end, updatedEvent.timezone)
+ .format("dddd D MMMM YYYY h:mm a");
+ diffText += `<li>the end time changed to ${displayDate}</li>`;
+ }
+ if (event.timezone !== updatedEvent.timezone) {
+ diffText += `<li>the time zone changed to ${updatedEvent.timezone}</li>`;
+ }
+ if (event.description !== updatedEvent.description) {
+ diffText += `<li>the event description changed</li>`;
+ }
+ diffText += `</ul>`;
+ Event.findOneAndUpdate(
+ { id: req.params.eventID },
+ updatedEvent,
+ function (err, raw) {
+ if (err) {
+ addToLog(
+ "editEvent",
+ "error",
+ "Attempt to edit event " +
+ req.params.eventID +
+ " failed with error: " +
+ err
+ );
+ res.send(err);
+ }
+ }
+ )
+ .then(() => {
+ addToLog(
+ "editEvent",
+ "success",
+ "Event " + req.params.eventID + " edited"
+ );
+ // send update to ActivityPub subscribers
+ Event.findOne({ id: req.params.eventID }, function (err, event) {
+ if (!event) return;
+ let attendees = event.attendees.filter((el) => el.id);
+ if (!err) {
+ // broadcast an identical message to all followers, will show in home timeline
+ const guidObject = crypto.randomBytes(16).toString("hex");
+ const jsonObject = {
+ "@context": "https://www.w3.org/ns/activitystreams",
+ id: `https://${domain}/${req.params.eventID}/m/${guidObject}`,
+ name: `RSVP to ${event.name}`,
+ type: "Note",
+ cc: "https://www.w3.org/ns/activitystreams#Public",
+ content: `${diffText} See here: <a href="https://${domain}/${req.params.eventID}">https://${domain}/${req.params.eventID}</a>`,
+ };
+ ap.broadcastCreateMessage(jsonObject, event.followers, eventID);
+ // also broadcast an Update profile message to all followers so that at least Mastodon servers will update the local profile information
+ const jsonUpdateObject = JSON.parse(event.activityPubActor);
+ ap.broadcastUpdateMessage(
+ jsonUpdateObject,
+ event.followers,
+ eventID
+ );
+ // also broadcast an Update/Event for any calendar apps that are consuming our Events
+ const jsonEventObject = JSON.parse(event.activityPubEvent);
+ ap.broadcastUpdateMessage(
+ jsonEventObject,
+ event.followers,
+ eventID
+ );
+
+ // DM to attendees
+ for (const attendee of attendees) {
+ const jsonObject = {
+ "@context": "https://www.w3.org/ns/activitystreams",
+ name: `RSVP to ${event.name}`,
+ type: "Note",
+ content: `<span class=\"h-card\"><a href="${attendee.id}" class="u-url mention">@<span>${attendee.name}</span></a></span> ${diffText} See here: <a href="https://${domain}/${req.params.eventID}">https://${domain}/${req.params.eventID}</a>`,
+ tag: [
+ {
+ type: "Mention",
+ href: attendee.id,
+ name: attendee.name,
+ },
+ ],
+ };
+ // send direct message to user
+ ap.sendDirectMessage(jsonObject, attendee.id, eventID);
+ }
+ }
+ });
+ // Send update to all attendees
+ if (sendEmails) {
+ Event.findOne({ id: req.params.eventID }).then((event) => {
+ const attendeeEmails = event.attendees
+ .filter((o) => o.status === "attending" && o.email)
+ .map((o) => o.email);
+ if (attendeeEmails.length) {
+ console.log("Sending emails to: " + attendeeEmails);
+ req.app.get("hbsInstance").renderView(
+ "./views/emails/editevent.handlebars",
+ {
+ diffText,
+ eventID: req.params.eventID,
+ siteName,
+ siteLogo,
+ domain,
+ cache: true,
+ layout: "email.handlebars",
+ },
+ function (err, html) {
+ const msg = {
+ to: attendeeEmails,
+ from: {
+ name: siteName,
+ email: contactEmail,
+ address: contactEmail,
+ },
+ subject: `${siteName}: ${event.name} was just edited`,
+ html,
+ };
+ switch (mailService) {
+ case "sendgrid":
+ sgMail.sendMultiple(msg).catch((e) => {
+ console.error(e.toString());
+ res.status(500).end();
+ });
+ break;
+ case "nodemailer":
+ nodemailerTransporter.sendMail(msg).catch((e) => {
+ console.error(e.toString());
+ res.status(500).end();
+ });
+ break;
+ }
+ }
+ );
+ } else {
+ console.log("Nothing to send!");
+ }
+ });
+ }
+ res.writeHead(302, {
+ Location: "/" + req.params.eventID + "?e=" + req.params.editToken,
+ });
+ res.end();
+ })
+ .catch((err) => {
+ console.error(err);
+ res.send("Sorry! Something went wrong!");
+ addToLog(
+ "editEvent",
+ "error",
+ "Attempt to edit event " +
+ req.params.eventID +
+ " failed with error: " +
+ err
+ );
+ });
+ } else {
+ // Token doesn't match
+ res.send("Sorry! Something went wrong");
+ addToLog(
+ "editEvent",
+ "error",
+ "Attempt to edit event " +
+ req.params.eventID +
+ " failed with error: token does not match"
+ );
+ }
+ })
+ .catch((err) => {
+ console.error(err);
+ res.send("Sorry! Something went wrong!");
+ addToLog(
+ "editEvent",
+ "error",
+ "Attempt to edit event " +
+ req.params.eventID +
+ " failed with error: " +
+ err
+ );
+ });
+});
+
+router.post("/editeventgroup/:eventGroupID/:editToken", (req, res) => {
+ let submittedEditToken = req.params.editToken;
+ EventGroup.findOne({
+ id: req.params.eventGroupID,
+ })
+ .then((eventGroup) => {
+ if (eventGroup.editToken === submittedEditToken) {
+ // Token matches
+
+ // If there is a new image, upload that first
+ let eventGroupID = req.params.eventGroupID;
+ let eventGroupImageFilename = eventGroup.image;
+ if (req.files && Object.keys(req.files).length !== 0) {
+ let eventImageBuffer = req.files.eventGroupImageUpload.data;
+ Jimp.read(eventImageBuffer, (err, img) => {
+ if (err) throw err;
+ img
+ .resize(920, Jimp.AUTO) // resize
+ .quality(80) // set JPEG
+ .write("./public/events/" + eventGroupID + ".jpg"); // save
+ });
+ eventGroupImageFilename = eventGroupID + ".jpg";
+ }
+ const updatedEventGroup = {
+ name: req.body.eventGroupName,
+ description: req.body.eventGroupDescription,
+ url: req.body.eventGroupURL,
+ hostName: req.body.hostName,
+ image: eventGroupImageFilename,
+ };
+ EventGroup.findOneAndUpdate(
+ { id: req.params.eventGroupID },
+ updatedEventGroup,
+ function (err, raw) {
+ if (err) {
+ addToLog(
+ "editEventGroup",
+ "error",
+ "Attempt to edit event group " +
+ req.params.eventGroupID +
+ " failed with error: " +
+ err
+ );
+ res.send(err);
+ }
+ }
+ )
+ .then(() => {
+ addToLog(
+ "editEventGroup",
+ "success",
+ "Event group " + req.params.eventGroupID + " edited"
+ );
+ res.writeHead(302, {
+ Location:
+ "/group/" +
+ req.params.eventGroupID +
+ "?e=" +
+ req.params.editToken,
+ });
+ res.end();
+ })
+ .catch((err) => {
+ console.error(err);
+ res.send("Sorry! Something went wrong!");
+ addToLog(
+ "editEventGroup",
+ "error",
+ "Attempt to edit event group " +
+ req.params.eventGroupID +
+ " failed with error: " +
+ err
+ );
+ });
+ } else {
+ // Token doesn't match
+ res.send("Sorry! Something went wrong");
+ addToLog(
+ "editEventGroup",
+ "error",
+ "Attempt to edit event group " +
+ req.params.eventGroupID +
+ " failed with error: token does not match"
+ );
+ }
+ })
+ .catch((err) => {
+ console.error(err);
+ res.send("Sorry! Something went wrong!");
+ addToLog(
+ "editEventGroup",
+ "error",
+ "Attempt to edit event group " +
+ req.params.eventGroupID +
+ " failed with error: " +
+ err
+ );
+ });
+});
+
+router.post("/deleteimage/:eventID/:editToken", (req, res) => {
+ let submittedEditToken = req.params.editToken;
+ Event.findOne({
+ id: req.params.eventID,
+ }).then((event) => {
+ if (event.editToken === submittedEditToken) {
+ // Token matches
+ if (event.image) {
+ eventImage = event.image;
+ } else {
+ res
+ .status(500)
+ .send(
+ "This event doesn't have a linked image. What are you even doing"
+ );
+ }
+ fs.unlink(global.appRoot + "/public/events/" + eventImage, (err) => {
+ if (err) {
+ res.status(500).send(err);
+ addToLog(
+ "deleteEventImage",
+ "error",
+ "Attempt to delete event image for event " +
+ req.params.eventID +
+ " failed with error: " +
+ err
+ );
+ }
+ // Image removed
+ addToLog(
+ "deleteEventImage",
+ "success",
+ "Image for event " + req.params.eventID + " deleted"
+ );
+ event.image = "";
+ event
+ .save()
+ .then((response) => {
+ res.status(200).send("Success");
+ })
+ .catch((err) => {
+ res.status(500).send(err);
+ addToLog(
+ "deleteEventImage",
+ "error",
+ "Attempt to delete event image for event " +
+ req.params.eventID +
+ " failed with error: " +
+ err
+ );
+ });
+ });
+ }
+ });
+});
+
+router.post("/deleteevent/:eventID/:editToken", (req, res) => {
+ let submittedEditToken = req.params.editToken;
+ let eventImage;
+ Event.findOne({
+ id: req.params.eventID,
+ })
+ .then((event) => {
+ if (event.editToken === submittedEditToken) {
+ // Token matches
+
+ let eventImage;
+ if (event.image) {
+ eventImage = event.image;
+ }
+
+ // broadcast a Delete profile message to all followers so that at least Mastodon servers will delete their local profile information
+ const guidUpdateObject = crypto.randomBytes(16).toString("hex");
+ const jsonUpdateObject = JSON.parse(event.activityPubActor);
+ // first broadcast AP messages, THEN delete from DB
+ ap.broadcastDeleteMessage(
+ jsonUpdateObject,
+ event.followers,
+ req.params.eventID,
+ function (statuses) {
+ Event.deleteOne({ id: req.params.eventID }, function (err, raw) {
+ if (err) {
+ res.send(err);
+ addToLog(
+ "deleteEvent",
+ "error",
+ "Attempt to delete event " +
+ req.params.eventID +
+ " failed with error: " +
+ err
+ );
+ }
+ })
+ .then(() => {
+ // Delete image
+ if (eventImage) {
+ fs.unlink(
+ global.appRoot + "/public/events/" + eventImage,
+ (err) => {
+ if (err) {
+ res.send(err);
+ addToLog(
+ "deleteEvent",
+ "error",
+ "Attempt to delete event image for event " +
+ req.params.eventID +
+ " failed with error: " +
+ err
+ );
+ }
+ // Image removed
+ addToLog(
+ "deleteEvent",
+ "success",
+ "Event " + req.params.eventID + " deleted"
+ );
+ }
+ );
+ }
+ res.writeHead(302, {
+ Location: "/",
+ });
+ res.end();
+
+ // Send emails here otherwise they don't exist lol
+ if (sendEmails) {
+ const attendeeEmails = event.attendees
+ .filter((o) => o.status === "attending" && o.email)
+ .map((o) => o.email);
+ if (attendeeEmails.length) {
+ console.log("Sending emails to: " + attendeeEmails);
+ req.app.get("hbsInstance").renderView(
+ "./views/emails/deleteevent.handlebars",
+ {
+ siteName,
+ siteLogo,
+ domain,
+ eventName: event.name,
+ cache: true,
+ layout: "email.handlebars",
+ },
+ function (err, html) {
+ const msg = {
+ to: attendeeEmails,
+ from: {
+ name: siteName,
+ email: contactEmail,
+ address: contactEmail,
+ },
+ subject: `${siteName}: ${event.name} was deleted`,
+ html,
+ };
+ switch (mailService) {
+ case "sendgrid":
+ sgMail.sendMultiple(msg).catch((e) => {
+ console.error(e.toString());
+ res.status(500).end();
+ });
+ break;
+ case "nodemailer":
+ nodemailerTransporter.sendMail(msg).catch((e) => {
+ console.error(e.toString());
+ res.status(500).end();
+ });
+ break;
+ }
+ }
+ );
+ } else {
+ console.log("Nothing to send!");
+ }
+ }
+ })
+ .catch((err) => {
+ res.send(
+ "Sorry! Something went wrong (error deleting): " + err
+ );
+ addToLog(
+ "deleteEvent",
+ "error",
+ "Attempt to delete event " +
+ req.params.eventID +
+ " failed with error: " +
+ err
+ );
+ });
+ }
+ );
+ } else {
+ // Token doesn't match
+ res.send("Sorry! Something went wrong");
+ addToLog(
+ "deleteEvent",
+ "error",
+ "Attempt to delete event " +
+ req.params.eventID +
+ " failed with error: token does not match"
+ );
+ }
+ })
+ .catch((err) => {
+ res.send("Sorry! Something went wrong: " + err);
+ addToLog(
+ "deleteEvent",
+ "error",
+ "Attempt to delete event " +
+ req.params.eventID +
+ " failed with error: " +
+ err
+ );
+ });
+});
+
+router.post("/deleteeventgroup/:eventGroupID/:editToken", (req, res) => {
+ let submittedEditToken = req.params.editToken;
+ EventGroup.findOne({
+ id: req.params.eventGroupID,
+ })
+ .then(async (eventGroup) => {
+ if (eventGroup.editToken === submittedEditToken) {
+ // Token matches
+
+ let linkedEvents = await Event.find({ eventGroup: eventGroup._id });
+
+ let linkedEventIDs = linkedEvents.map((event) => event._id);
+ let eventGroupImage = false;
+ if (eventGroup.image) {
+ eventGroupImage = eventGroup.image;
+ }
+
+ EventGroup.deleteOne(
+ { id: req.params.eventGroupID },
+ function (err, raw) {
+ if (err) {
+ res.send(err);
+ addToLog(
+ "deleteEventGroup",
+ "error",
+ "Attempt to delete event group " +
+ req.params.eventGroupID +
+ " failed with error: " +
+ err
+ );
+ }
+ }
+ )
+ .then(() => {
+ // Delete image
+ if (eventGroupImage) {
+ fs.unlink(
+ global.appRoot + "/public/events/" + eventGroupImage,
+ (err) => {
+ if (err) {
+ res.send(err);
+ addToLog(
+ "deleteEventGroup",
+ "error",
+ "Attempt to delete event image for event group " +
+ req.params.eventGroupID +
+ " failed with error: " +
+ err
+ );
+ }
+ }
+ );
+ }
+ Event.update(
+ { _id: { $in: linkedEventIDs } },
+ { $set: { eventGroup: null } },
+ { multi: true }
+ )
+ .then((response) => {
+ console.log(response);
+ addToLog(
+ "deleteEventGroup",
+ "success",
+ "Event group " + req.params.eventGroupID + " deleted"
+ );
+ res.writeHead(302, {
+ Location: "/",
+ });
+ res.end();
+ })
+ .catch((err) => {
+ res.send(
+ "Sorry! Something went wrong (error deleting): " + err
+ );
+ addToLog(
+ "deleteEventGroup",
+ "error",
+ "Attempt to delete event group " +
+ req.params.eventGroupID +
+ " failed with error: " +
+ err
+ );
+ });
+ })
+ .catch((err) => {
+ res.send("Sorry! Something went wrong (error deleting): " + err);
+ addToLog(
+ "deleteEventGroup",
+ "error",
+ "Attempt to delete event group " +
+ req.params.eventGroupID +
+ " failed with error: " +
+ err
+ );
+ });
+ } else {
+ // Token doesn't match
+ res.send("Sorry! Something went wrong");
+ addToLog(
+ "deleteEventGroup",
+ "error",
+ "Attempt to delete event group " +
+ req.params.eventGroupID +
+ " failed with error: token does not match"
+ );
+ }
+ })
+ .catch((err) => {
+ res.send("Sorry! Something went wrong: " + err);
+ addToLog(
+ "deleteEventGroup",
+ "error",
+ "Attempt to delete event group " +
+ req.params.eventGroupID +
+ " failed with error: " +
+ err
+ );
+ });
+});
+
+router.post("/attendee/provision", async (req, res) => {
+ const removalPassword = niceware.generatePassphrase(6).join("-");
+ const newAttendee = {
+ status: "provisioned",
+ removalPassword,
+ created: Date.now(),
+ };
+
+ const event = await Event.findOne({ id: req.query.eventID }).catch((e) => {
+ addToLog(
+ "provisionEventAttendee",
+ "error",
+ "Attempt to provision attendee in event " +
+ req.query.eventID +
+ " failed with error: " +
+ e
+ );
+ return res.sendStatus(500);
+ });
+
+ if (!event) {
+ return res.sendStatus(404);
+ }
+
+ event.attendees.push(newAttendee);
+ await event.save().catch((e) => {
+ console.log(e);
+ addToLog(
+ "provisionEventAttendee",
+ "error",
+ "Attempt to provision attendee in event " +
+ req.query.eventID +
+ " failed with error: " +
+ e
+ );
+ return res.sendStatus(500);
+ });
+ addToLog(
+ "provisionEventAttendee",
+ "success",
+ "Attendee provisioned in event " + req.query.eventID
+ );
+
+ // Return the removal password and the number of free spots remaining
+ let freeSpots;
+ if (event.maxAttendees !== null && event.maxAttendees !== undefined) {
+ freeSpots =
+ event.maxAttendees -
+ event.attendees.reduce(
+ (acc, a) => acc + (a.status === "attending" ? a.number || 1 : 0),
+ 0
+ );
+ } else {
+ freeSpots = undefined;
+ }
+ return res.json({ removalPassword, freeSpots });
+});
+
+router.post("/attendevent/:eventID", async (req, res) => {
+ // Do not allow empty removal passwords
+ if (!req.body.removalPassword) {
+ return res.sendStatus(500);
+ }
+ const event = await Event.findOne({ id: req.params.eventID }).catch((e) => {
+ addToLog(
+ "attendEvent",
+ "error",
+ "Attempt to attend event " +
+ req.params.eventID +
+ " failed with error: " +
+ e
+ );
+ return res.sendStatus(500);
+ });
+ if (!event) {
+ return res.sendStatus(404);
+ }
+ const attendee = event.attendees.find(
+ (a) => a.removalPassword === req.body.removalPassword
+ );
+ if (!attendee) {
+ return res.sendStatus(404);
+ }
+ // Do we have enough free spots in this event to accomodate this attendee?
+ // First, check if the event has a max number of attendees
+ if (event.maxAttendees !== null && event.maxAttendees !== undefined) {
+ const freeSpots =
+ event.maxAttendees -
+ event.attendees.reduce(
+ (acc, a) => acc + (a.status === "attending" ? a.number || 1 : 0),
+ 0
+ );
+ if (req.body.attendeeNumber > freeSpots) {
+ return res.sendStatus(403);
+ }
+ }
+
+ Event.findOneAndUpdate(
+ {
+ id: req.params.eventID,
+ "attendees.removalPassword": req.body.removalPassword,
+ },
+ {
+ $set: {
+ "attendees.$.status": "attending",
+ "attendees.$.name": req.body.attendeeName,
+ "attendees.$.email": req.body.attendeeEmail,
+ "attendees.$.number": req.body.attendeeNumber,
+ },
+ }
+ )
+ .then((event) => {
+ addToLog(
+ "addEventAttendee",
+ "success",
+ "Attendee added to event " + req.params.eventID
+ );
+ if (sendEmails) {
+ if (req.body.attendeeEmail) {
+ req.app.get("hbsInstance").renderView(
+ "./views/emails/addeventattendee.handlebars",
+ {
+ eventID: req.params.eventID,
+ siteName,
+ siteLogo,
+ domain,
+ removalPassword: req.body.removalPassword,
+ cache: true,
+ layout: "email.handlebars",
+ },
+ function (err, html) {
+ const msg = {
+ to: req.body.attendeeEmail,
+ from: {
+ name: siteName,
+ email: contactEmail,
+ },
+ subject: `${siteName}: You're RSVPed to ${event.name}`,
+ html,
+ };
+ switch (mailService) {
+ case "sendgrid":
+ sgMail.send(msg).catch((e) => {
+ console.error(e.toString());
+ res.status(500).end();
+ });
+ break;
+ case "nodemailer":
+ nodemailerTransporter.sendMail(msg).catch((e) => {
+ console.error(e.toString());
+ res.status(500).end();
+ });
+ break;
+ }
+ }
+ );
+ }
+ }
+ res.redirect(`/${req.params.eventID}`);
+ })
+ .catch((error) => {
+ res.send("Database error, please try again :(");
+ addToLog(
+ "addEventAttendee",
+ "error",
+ "Attempt to add attendee to event " +
+ req.params.eventID +
+ " failed with error: " +
+ error
+ );
+ });
+});
+
+router.post("/unattendevent/:eventID", (req, res) => {
+ const removalPassword = req.body.removalPassword;
+ // Don't allow blank removal passwords!
+ if (!removalPassword) {
+ return res.sendStatus(500);
+ }
+
+ Event.update(
+ { id: req.params.eventID },
+ { $pull: { attendees: { removalPassword } } }
+ )
+ .then((response) => {
+ console.log(response);
+ addToLog(
+ "unattendEvent",
+ "success",
+ "Attendee removed self from event " + req.params.eventID
+ );
+ if (sendEmails) {
+ if (req.body.attendeeEmail) {
+ req.app.get("hbsInstance").renderView(
+ "./views/emails/unattendevent.handlebars",
+ {
+ eventID: req.params.eventID,
+ siteName,
+ siteLogo,
+ domain,
+ cache: true,
+ layout: "email.handlebars",
+ },
+ function (err, html) {
+ const msg = {
+ to: req.body.attendeeEmail,
+ from: {
+ name: siteName,
+ email: contactEmail,
+ },
+ subject: `${siteName}: You have been removed from an event`,
+ html,
+ };
+ switch (mailService) {
+ case "sendgrid":
+ sgMail.send(msg).catch((e) => {
+ console.error(e.toString());
+ res.status(500).end();
+ });
+ break;
+ case "nodemailer":
+ nodemailerTransporter.sendMail(msg).catch((e) => {
+ console.error(e.toString());
+ res.status(500).end();
+ });
+ break;
+ }
+ }
+ );
+ }
+ }
+ res.writeHead(302, {
+ Location: "/" + req.params.eventID,
+ });
+ res.end();
+ })
+ .catch((err) => {
+ res.send("Database error, please try again :(");
+ addToLog(
+ "removeEventAttendee",
+ "error",
+ "Attempt to remove attendee from event " +
+ req.params.eventID +
+ " failed with error: " +
+ err
+ );
+ });
+});
+
+// this is a one-click unattend that requires a secret URL that only the person who RSVPed over
+// activitypub knows
+router.get("/oneclickunattendevent/:eventID/:attendeeID", (req, res) => {
+ // Mastodon will "click" links that sent to its users, presumably as a prefetch?
+ // Anyway, this ignores the automated clicks that are done without the user's knowledge
+ if (
+ req.headers["user-agent"] &&
+ req.headers["user-agent"].includes("Mastodon")
+ ) {
+ return res.sendStatus(200);
+ }
+ Event.update(
+ { id: req.params.eventID },
+ { $pull: { attendees: { _id: req.params.attendeeID } } }
+ )
+ .then((response) => {
+ addToLog(
+ "oneClickUnattend",
+ "success",
+ "Attendee removed via one click unattend " + req.params.eventID
+ );
+ if (sendEmails) {
+ // currently this is never called because we don't have the email address
+ if (req.body.attendeeEmail) {
+ req.app.get("hbsInstance").renderView(
+ "./views/emails/removeeventattendee.handlebars",
+ {
+ eventName: req.params.eventName,
+ siteName,
+ domain,
+ cache: true,
+ layout: "email.handlebars",
+ },
+ function (err, html) {
+ const msg = {
+ to: req.body.attendeeEmail,
+ from: {
+ name: siteName,
+ email: contactEmail,
+ },
+ subject: `${siteName}: You have been removed from an event`,
+ html,
+ };
+ switch (mailService) {
+ case "sendgrid":
+ sgMail.send(msg).catch((e) => {
+ console.error(e.toString());
+ res.status(500).end();
+ });
+ break;
+ case "nodemailer":
+ nodemailerTransporter.sendMail(msg).catch((e) => {
+ console.error(e.toString());
+ res.status(500).end();
+ });
+ break;
+ }
+ }
+ );
+ }
+ }
+ res.writeHead(302, {
+ Location: "/" + req.params.eventID,
+ });
+ res.end();
+ })
+ .catch((err) => {
+ res.send("Database error, please try again :(");
+ addToLog(
+ "removeEventAttendee",
+ "error",
+ "Attempt to remove attendee by admin from event " +
+ req.params.eventID +
+ " failed with error: " +
+ err
+ );
+ });
+});
+
+router.post("/removeattendee/:eventID/:attendeeID", (req, res) => {
+ Event.update(
+ { id: req.params.eventID },
+ { $pull: { attendees: { _id: req.params.attendeeID } } }
+ )
+ .then((response) => {
+ console.log(response);
+ addToLog(
+ "removeEventAttendee",
+ "success",
+ "Attendee removed by admin from event " + req.params.eventID
+ );
+ if (sendEmails) {
+ // currently this is never called because we don't have the email address
+ if (req.body.attendeeEmail) {
+ req.app.get("hbsInstance").renderView(
+ "./views/emails/removeeventattendee.handlebars",
+ {
+ eventName: req.params.eventName,
+ siteName,
+ siteLogo,
+ domain,
+ cache: true,
+ layout: "email.handlebars",
+ },
+ function (err, html) {
+ const msg = {
+ to: req.body.attendeeEmail,
+ from: {
+ name: siteName,
+ email: contactEmail,
+ },
+ subject: `${siteName}: You have been removed from an event`,
+ html,
+ };
+ switch (mailService) {
+ case "sendgrid":
+ sgMail.send(msg).catch((e) => {
+ console.error(e.toString());
+ res.status(500).end();
+ });
+ break;
+ case "nodemailer":
+ nodemailerTransporter.sendMail(msg).catch((e) => {
+ console.error(e.toString());
+ res.status(500).end();
+ });
+ break;
+ }
+ }
+ );
+ }
+ }
+ res.writeHead(302, {
+ Location: "/" + req.params.eventID,
+ });
+ res.end();
+ })
+ .catch((err) => {
+ res.send("Database error, please try again :(");
+ addToLog(
+ "removeEventAttendee",
+ "error",
+ "Attempt to remove attendee by admin from event " +
+ req.params.eventID +
+ " failed with error: " +
+ err
+ );
+ });
+});
+
+/*
+ * Create an email subscription on an event group.
+ */
+router.post("/subscribe/:eventGroupID", (req, res) => {
+ const subscriber = {
+ email: req.body.emailAddress,
+ };
+ if (!subscriber.email) {
+ return res.sendStatus(500);
+ }
+
+ EventGroup.findOne({
+ id: req.params.eventGroupID,
+ })
+ .then((eventGroup) => {
+ if (!eventGroup) {
+ return res.sendStatus(404);
+ }
+ eventGroup.subscribers.push(subscriber);
+ eventGroup.save();
+ if (sendEmails) {
+ req.app.get("hbsInstance").renderView(
+ "./views/emails/subscribed.handlebars",
+ {
+ eventGroupName: eventGroup.name,
+ eventGroupID: eventGroup.id,
+ emailAddress: encodeURIComponent(subscriber.email),
+ siteName,
+ siteLogo,
+ domain,
+ cache: true,
+ layout: "email.handlebars",
+ },
+ function (err, html) {
+ const msg = {
+ to: subscriber.email,
+ from: {
+ name: siteName,
+ email: contactEmail,
+ },
+ subject: `${siteName}: You have subscribed to an event group`,
+ html,
+ };
+ switch (mailService) {
+ case "sendgrid":
+ sgMail.send(msg).catch((e) => {
+ console.error(e.toString());
+ res.status(500).end();
+ });
+ break;
+ case "nodemailer":
+ nodemailerTransporter.sendMail(msg).catch((e) => {
+ console.error(e.toString());
+ res.status(500).end();
+ });
+ break;
+ }
+ }
+ );
+ }
+ return res.redirect(`/group/${eventGroup.id}`);
+ })
+ .catch((error) => {
+ addToLog(
+ "addSubscription",
+ "error",
+ "Attempt to subscribe " +
+ req.body.emailAddress +
+ " to event group " +
+ req.params.eventGroupID +
+ " failed with error: " +
+ error
+ );
+ return res.sendStatus(500);
+ });
+});
+
+/*
+ * Delete an existing email subscription on an event group.
+ */
+router.get("/unsubscribe/:eventGroupID", (req, res) => {
+ const email = req.query.email;
+ console.log(email);
+ if (!email) {
+ return res.sendStatus(500);
+ }
+
+ EventGroup.update(
+ { id: req.params.eventGroupID },
+ { $pull: { subscribers: { email } } }
+ )
+ .then((response) => {
+ return res.redirect("/");
+ })
+ .catch((error) => {
+ addToLog(
+ "removeSubscription",
+ "error",
+ "Attempt to unsubscribe " +
+ req.query.email +
+ " from event group " +
+ req.params.eventGroupID +
+ " failed with error: " +
+ error
+ );
+ return res.sendStatus(500);
+ });
+});
+
+router.post("/post/comment/:eventID", (req, res) => {
+ let commentID = nanoid();
+ const newComment = {
+ id: commentID,
+ author: req.body.commentAuthor,
+ content: req.body.commentContent,
+ timestamp: moment(),
+ };
+
+ Event.findOne(
+ {
+ id: req.params.eventID,
+ },
+ function (err, event) {
+ if (!event) return;
+ event.comments.push(newComment);
+ event
+ .save()
+ .then(() => {
+ addToLog(
+ "addEventComment",
+ "success",
+ "Comment added to event " + req.params.eventID
+ );
+ // broadcast an identical message to all followers, will show in their home timeline
+ // and in the home timeline of the event
+ const guidObject = crypto.randomBytes(16).toString("hex");
+ const jsonObject = {
+ "@context": "https://www.w3.org/ns/activitystreams",
+ id: `https://${domain}/${req.params.eventID}/m/${guidObject}`,
+ name: `Comment on ${event.name}`,
+ type: "Note",
+ cc: "https://www.w3.org/ns/activitystreams#Public",
+ content: `<p>${req.body.commentAuthor} commented: ${req.body.commentContent}.</p><p><a href="https://${domain}/${req.params.eventID}/">See the full conversation here.</a></p>`,
+ };
+ ap.broadcastCreateMessage(
+ jsonObject,
+ event.followers,
+ req.params.eventID
+ );
+ if (sendEmails) {
+ Event.findOne({ id: req.params.eventID }).then((event) => {
+ const attendeeEmails = event.attendees
+ .filter((o) => o.status === "attending" && o.email)
+ .map((o) => o.email);
+ if (attendeeEmails.length) {
+ console.log("Sending emails to: " + attendeeEmails);
+ req.app.get("hbsInstance").renderView(
+ "./views/emails/addeventcomment.handlebars",
+ {
+ siteName,
+ siteLogo,
+ domain,
+ eventID: req.params.eventID,
+ commentAuthor: req.body.commentAuthor,
+ cache: true,
+ layout: "email.handlebars",
+ },
+ function (err, html) {
+ const msg = {
+ to: attendeeEmails,
+ from: {
+ name: siteName,
+ email: contactEmail,
+ },
+ subject: `${siteName}: New comment in ${event.name}`,
+ html,
+ };
+ switch (mailService) {
+ case "sendgrid":
+ sgMail.sendMultiple(msg).catch((e) => {
+ console.error(e.toString());
+ res.status(500).end();
+ });
+ break;
+ case "nodemailer":
+ nodemailerTransporter.sendMail(msg).catch((e) => {
+ console.error(e.toString());
+ res.status(500).end();
+ });
+ break;
+ }
+ }
+ );
+ } else {
+ console.log("Nothing to send!");
+ }
+ });
+ }
+ res.writeHead(302, {
+ Location: "/" + req.params.eventID,
+ });
+ res.end();
+ })
+ .catch((err) => {
+ res.send("Database error, please try again :(" + err);
+ addToLog(
+ "addEventComment",
+ "error",
+ "Attempt to add comment to event " +
+ req.params.eventID +
+ " failed with error: " +
+ err
+ );
+ });
+ }
+ );
+});
+
+router.post("/post/reply/:eventID/:commentID", (req, res) => {
+ let replyID = nanoid();
+ let commentID = req.params.commentID;
+ const newReply = {
+ id: replyID,
+ author: req.body.replyAuthor,
+ content: req.body.replyContent,
+ timestamp: moment(),
+ };
+ Event.findOne(
+ {
+ id: req.params.eventID,
+ },
+ function (err, event) {
+ if (!event) return;
+ var parentComment = event.comments.id(commentID);
+ parentComment.replies.push(newReply);
+ event
+ .save()
+ .then(() => {
+ addToLog(
+ "addEventReply",
+ "success",
+ "Reply added to comment " +
+ commentID +
+ " in event " +
+ req.params.eventID
+ );
+ // broadcast an identical message to all followers, will show in their home timeline
+ const guidObject = crypto.randomBytes(16).toString("hex");
+ const jsonObject = {
+ "@context": "https://www.w3.org/ns/activitystreams",
+ id: `https://${domain}/${req.params.eventID}/m/${guidObject}`,
+ name: `Comment on ${event.name}`,
+ type: "Note",
+ cc: "https://www.w3.org/ns/activitystreams#Public",
+ content: `<p>${req.body.replyAuthor} commented: ${req.body.replyContent}</p><p><a href="https://${domain}/${req.params.eventID}/">See the full conversation here.</a></p>`,
+ };
+ ap.broadcastCreateMessage(
+ jsonObject,
+ event.followers,
+ req.params.eventID
+ );
+ if (sendEmails) {
+ Event.findOne({ id: req.params.eventID }).then((event) => {
+ const attendeeEmails = event.attendees
+ .filter((o) => o.status === "attending" && o.email)
+ .map((o) => o.email);
+ if (attendeeEmails.length) {
+ console.log("Sending emails to: " + attendeeEmails);
+ req.app.get("hbsInstance").renderView(
+ "./views/emails/addeventcomment.handlebars",
+ {
+ siteName,
+ siteLogo,
+ domain,
+ eventID: req.params.eventID,
+ commentAuthor: req.body.replyAuthor,
+ cache: true,
+ layout: "email.handlebars",
+ },
+ function (err, html) {
+ const msg = {
+ to: attendeeEmails,
+ from: {
+ name: siteName,
+ email: contactEmail,
+ },
+ subject: `${siteName}: New comment in ${event.name}`,
+ html,
+ };
+ switch (mailService) {
+ case "sendgrid":
+ sgMail.sendMultiple(msg).catch((e) => {
+ console.error(e.toString());
+ res.status(500).end();
+ });
+ break;
+ case "nodemailer":
+ nodemailerTransporter.sendMail(msg).catch((e) => {
+ console.error(e.toString());
+ res.status(500).end();
+ });
+ break;
+ }
+ }
+ );
+ } else {
+ console.log("Nothing to send!");
+ }
+ });
+ }
+ res.writeHead(302, {
+ Location: "/" + req.params.eventID,
+ });
+ res.end();
+ })
+ .catch((err) => {
+ res.send("Database error, please try again :(");
+ addToLog(
+ "addEventReply",
+ "error",
+ "Attempt to add reply to comment " +
+ commentID +
+ " in event " +
+ req.params.eventID +
+ " failed with error: " +
+ err
+ );
+ });
+ }
+ );
+});
+
+router.post("/deletecomment/:eventID/:commentID/:editToken", (req, res) => {
+ let submittedEditToken = req.params.editToken;
+ Event.findOne({
+ id: req.params.eventID,
+ })
+ .then((event) => {
+ if (event.editToken === submittedEditToken) {
+ // Token matches
+ event.comments.id(req.params.commentID).remove();
+ event
+ .save()
+ .then(() => {
+ addToLog(
+ "deleteComment",
+ "success",
+ "Comment deleted from event " + req.params.eventID
+ );
+ res.writeHead(302, {
+ Location: "/" + req.params.eventID + "?e=" + req.params.editToken,
+ });
+ res.end();
+ })
+ .catch((err) => {
+ res.send("Sorry! Something went wrong (error deleting): " + err);
+ addToLog(
+ "deleteComment",
+ "error",
+ "Attempt to delete comment " +
+ req.params.commentID +
+ "from event " +
+ req.params.eventID +
+ " failed with error: " +
+ err
+ );
+ });
+ } else {
+ // Token doesn't match
+ res.send("Sorry! Something went wrong");
+ addToLog(
+ "deleteComment",
+ "error",
+ "Attempt to delete comment " +
+ req.params.commentID +
+ "from event " +
+ req.params.eventID +
+ " failed with error: token does not match"
+ );
+ }
+ })
+ .catch((err) => {
+ res.send("Sorry! Something went wrong: " + err);
+ addToLog(
+ "deleteComment",
+ "error",
+ "Attempt to delete comment " +
+ req.params.commentID +
+ "from event " +
+ req.params.eventID +
+ " failed with error: " +
+ err
+ );
+ });
+});
+
+router.post("/activitypub/inbox", (req, res) => {
+ if (!isFederated) return res.sendStatus(404);
+ // validate the incoming message
+ const signature = req.get("Signature");
+ let signature_header = signature
+ .split(",")
+ .map((pair) => {
+ return pair.split("=").map((value) => {
+ return value.replace(/^"/g, "").replace(/"$/g, "");
+ });
+ })
+ .reduce((acc, el) => {
+ acc[el[0]] = el[1];
+ return acc;
+ }, {});
+
+ // get the actor
+ // TODO if this is a Delete for an Actor this won't work
+ request(
+ {
+ url: signature_header.keyId,
+ headers: {
+ Accept: "application/activity+json",
+ "Content-Type": "application/activity+json",
+ },
+ },
+ function (error, response, actor) {
+ let publicKey = "";
+
+ try {
+ if (JSON.parse(actor).publicKey) {
+ publicKey = JSON.parse(actor).publicKey.publicKeyPem;
+ }
+ } catch (err) {
+ return res.status(500).send("Actor could not be parsed" + err);
+ }
+
+ let comparison_string = signature_header.headers
+ .split(" ")
+ .map((header) => {
+ if (header === "(request-target)") {
+ return "(request-target): post /activitypub/inbox";
+ } else {
+ return `${header}: ${req.get(header)}`;
+ }
+ })
+ .join("\n");
+
+ const verifier = crypto.createVerify("RSA-SHA256");
+ verifier.update(comparison_string, "ascii");
+ const publicKeyBuf = new Buffer(publicKey, "ascii");
+ const signatureBuf = new Buffer(signature_header.signature, "base64");
+ try {
+ const result = verifier.verify(publicKeyBuf, signatureBuf);
+ if (result) {
+ // actually process the ActivityPub message now that it's been verified
+ ap.processInbox(req, res);
+ } else {
+ return res.status(401).send("Signature could not be verified.");
+ }
+ } catch (err) {
+ return res.status(401).send("Signature could not be verified: " + err);
+ }
+ }
+ );
+});
+
+router.use(function (req, res, next) {
+ res.status(404);
+ res.render("404", { url: req.url });
+ return;
+});
+
+addToLog("startup", "success", "Started up successfully");
+
+module.exports = router;
diff --git a/src/start.js b/src/start.js
new file mode 100755
index 0000000..a6ecfbf
--- /dev/null
+++ b/src/start.js
@@ -0,0 +1,38 @@
+require("dotenv").config();
+
+const path = require("path");
+
+const mongoose = require("mongoose");
+
+const databaseCredentials = require("./config/database.js");
+const port = require("./config/domain.js").port;
+
+mongoose.connect(databaseCredentials.url, {
+ useNewUrlParser: true,
+ useUnifiedTopology: true,
+});
+mongoose.set("useCreateIndex", true);
+mongoose.Promise = global.Promise;
+mongoose.connection
+ .on("connected", () => {
+ console.log("Mongoose connection open!");
+ })
+ .on("error", (err) => {
+ console.log("Connection error: ${err.message}");
+ });
+
+require("./models/Event");
+require("./models/Log");
+require("./models/EventGroup");
+
+const app = require("./app.js");
+
+global.appRoot = path.resolve(__dirname);
+
+const server = app.listen(port, () => {
+ console.log(
+ `Welcome to gathio! The app is now running on http://localhost:${
+ server.address().port
+ }`
+ );
+});
diff --git a/start.js b/start.js
deleted file mode 100755
index 325e9e0..0000000
--- a/start.js
+++ /dev/null
@@ -1,32 +0,0 @@
-require('dotenv').config();
-
-const path = require('path');
-
-const mongoose = require('mongoose');
-
-const databaseCredentials = require('./config/database.js');
-const port = require('./config/domain.js').port;
-
-mongoose.connect(databaseCredentials.url, { useNewUrlParser: true, useUnifiedTopology: true });
-mongoose.set('useCreateIndex', true);
-mongoose.Promise = global.Promise;
-mongoose.connection
- .on('connected', () => {
- console.log('Mongoose connection open!');
- })
- .on('error', (err) => {
- console.log('Connection error: ${err.message}');
- });
-
-
-require('./models/Event');
-require('./models/Log');
-require('./models/EventGroup');
-
-const app = require('./app');
-
-global.appRoot = path.resolve(__dirname);
-
-const server = app.listen(port, () => {
- console.log(`Welcome to gathio! The app is now running on http://localhost:${server.address().port}`);
-});
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..04519ef
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,22 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "module": "ES2020",
+ "allowJs": true,
+ "checkJs": true,
+ "removeComments": true,
+ "resolveJsonModule": true,
+ "typeRoots": ["./node_modules/@types"],
+ "sourceMap": true,
+ "outDir": "dist",
+ "strict": true,
+ "baseUrl": ".",
+ "forceConsistentCasingInFileNames": true,
+ "esModuleInterop": true,
+ "experimentalDecorators": true,
+ "emitDecoratorMetadata": true,
+ "moduleResolution": "nodenext",
+ "skipLibCheck": true
+ },
+ "include": ["src/**/*"]
+}