From 5da7a5818108bdf1d31d4e10d8b17d1577d0bba6 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Fri, 29 Oct 2021 19:30:50 -0400 Subject: [PATCH 01/72] - Implement attendance preference for hackers. Questions: - Do we need to write unit tests for this? - Do we need to update/regenerate api docs to reflect the change in response data for the hacker model. --- constants/general.constant.js | 2 ++ middlewares/validators/hacker.validator.js | 6 ++++++ models/hacker.model.js | 10 ++++++++-- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/constants/general.constant.js b/constants/general.constant.js index c9a15d95..5e23d2fe 100644 --- a/constants/general.constant.js +++ b/constants/general.constant.js @@ -84,6 +84,7 @@ const SPONSOR_T5 = "SponsorT5"; const JOB_INTERESTS = ["Internship", "Full Time", "None"]; const SHIRT_SIZES = ["XS", "S", "M", "L", "XL", "XXL"]; const PREVIOUS_HACKATHONS = [0, 1, 2, 3, 4, 5]; +const ATTENDANCE_PREFERENCES = ["Remote", "In Person"]; const ROLE_CATEGORIES = { SELF: ":self", @@ -198,6 +199,7 @@ module.exports = { JOB_INTERESTS: JOB_INTERESTS, SHIRT_SIZES: SHIRT_SIZES, PREVIOUS_HACKATHONS: PREVIOUS_HACKATHONS, + ATTENDANCE_PREFERENCES: ATTENDANCE_PREFERENCES, USER_TYPES: USER_TYPES, SPONSOR_TIERS: SPONSOR_TIERS, EXTENDED_USER_TYPES: EXTENDED_USER_TYPES, diff --git a/middlewares/validators/hacker.validator.js b/middlewares/validators/hacker.validator.js index 4d9b3b81..1e9cc699 100644 --- a/middlewares/validators/hacker.validator.js +++ b/middlewares/validators/hacker.validator.js @@ -38,6 +38,12 @@ module.exports = { "application.accommodation.barriers", true ), + VALIDATOR.enumValidator( + "body", + "application.accomodation.attendancePreference", + Constants.ATTENDANCE_PREFERENCES, + false + ), VALIDATOR.stringValidator( "body", "application.general.URL.resume", diff --git a/models/hacker.model.js b/models/hacker.model.js index 678570c1..f59f8087 100644 --- a/models/hacker.model.js +++ b/models/hacker.model.js @@ -126,7 +126,12 @@ const HackerSchema = new mongoose.Schema({ enum: Constants.SHIRT_SIZES, required: true }, - travel: { type: Number, default: 0 } + travel: { type: Number, default: 0 }, + attendancePreference: { + type: String, + enum: Constants.ATTENDANCE_PREFERENCES, + required: true + } }, team: { type: mongoose.Schema.Types.ObjectId, @@ -167,7 +172,8 @@ HackerSchema.methods.isApplicationComplete = function() { const question1Done = !!hs.application.shortAnswer.question1; const question2Done = !!hs.application.shortAnswer.question2; const previousHackathonsDone = !!hs.application.shortAnswer.previousHackathons; - return portfolioDone && jobInterestDone && question1Done && question2Done && previousHackathonsDone; + const attendancePreferenceDone = !!hs.application.accommodation.attendancePreference; + return portfolioDone && jobInterestDone && question1Done && question2Done && previousHackathonsDone && attendancePreferenceDone; }; /** From 84600b8ea64da5f00082189f58a116a08d06f07e Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Fri, 29 Oct 2021 20:02:04 -0400 Subject: [PATCH 02/72] Fix spelling errors for accommodation in the codebase. - Drew JSON for testing from the api docs and was getting a validator error, on closer inspection, the spelling of acccommodation was incorrect in the docs, and in my own commit for hacker.validator.js. --- docs/api/api_data.json | 12 ++++++------ middlewares/validators/hacker.validator.js | 2 +- routes/api/hacker.js | 12 ++++++------ 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/api/api_data.json b/docs/api/api_data.json index 2c40a0dd..cfc8a3ab 100644 --- a/docs/api/api_data.json +++ b/docs/api/api_data.json @@ -1501,7 +1501,7 @@ "examples": [ { "title": "application: ", - "content": "{\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accomodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n}", + "content": "{\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accommodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n}", "type": "Json" } ] @@ -1528,7 +1528,7 @@ "examples": [ { "title": "Success-Response: ", - "content": "{\n \"message\": \"Hacker creation successful\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accomodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n}", + "content": "{\n \"message\": \"Hacker creation successful\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accommodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n}", "type": "object" } ] @@ -1610,7 +1610,7 @@ "examples": [ { "title": "Success-Response: ", - "content": "{\n \"message\": \"Successfully retrieved hacker information\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"Applied\",\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accomodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n }\n }", + "content": "{\n \"message\": \"Successfully retrieved hacker information\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"Applied\",\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accommodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n }\n }", "type": "object" } ] @@ -1692,7 +1692,7 @@ "examples": [ { "title": "Success-Response: ", - "content": "{\n \"message\": \"Successfully retrieved hacker information\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"Applied\",\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accomodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n }\n }", + "content": "{\n \"message\": \"Successfully retrieved hacker information\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"Applied\",\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accommodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n }\n }", "type": "object" } ] @@ -1927,7 +1927,7 @@ "examples": [ { "title": "application: ", - "content": "{\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accomodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n }", + "content": "{\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accommodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n }", "type": "Json" } ] @@ -1954,7 +1954,7 @@ "examples": [ { "title": "Success-Response: ", - "content": "{\n \"message\": \"Changed hacker information\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"Applied\",\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accomodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n }\n}", + "content": "{\n \"message\": \"Changed hacker information\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"Applied\",\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accommodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n }\n}", "type": "object" } ] diff --git a/middlewares/validators/hacker.validator.js b/middlewares/validators/hacker.validator.js index 1e9cc699..37b1f705 100644 --- a/middlewares/validators/hacker.validator.js +++ b/middlewares/validators/hacker.validator.js @@ -40,7 +40,7 @@ module.exports = { ), VALIDATOR.enumValidator( "body", - "application.accomodation.attendancePreference", + "application.accommodation.attendancePreference", Constants.ATTENDANCE_PREFERENCES, false ), diff --git a/routes/api/hacker.js b/routes/api/hacker.js index 83412352..d3da1d65 100644 --- a/routes/api/hacker.js +++ b/routes/api/hacker.js @@ -125,7 +125,7 @@ module.exports = { "privacyPolicy": true, "codeOfConduct": true, } - "accomodation": { + "accommodation": { "travel": 0 }, "location": { @@ -173,7 +173,7 @@ module.exports = { "privacyPolicy": true, "codeOfConduct": true, } - "accomodation": { + "accommodation": { "travel": 0 }, "location": { @@ -469,7 +469,7 @@ module.exports = { "privacyPolicy": true, "codeOfConduct": true, } - "accomodation": { + "accommodation": { "travel": 0 }, "location": { @@ -517,7 +517,7 @@ module.exports = { "privacyPolicy": true, "codeOfConduct": true, } - "accomodation": { + "accommodation": { "travel": 0 }, "location": { @@ -594,7 +594,7 @@ module.exports = { "privacyPolicy": true, "codeOfConduct": true, } - "accomodation": { + "accommodation": { "travel": 0 }, "location": { @@ -667,7 +667,7 @@ module.exports = { "privacyPolicy": true, "codeOfConduct": true, } - "accomodation": { + "accommodation": { "travel": 0 }, "location": { From bdb2cb57f86dadb55a9aa5ad7f1bc5f9590a5c6d Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Mon, 29 Nov 2021 13:46:29 -0500 Subject: [PATCH 03/72] feat: start of the major refactor. - Migrate from JavaScript to TypeScript for model and service layer. - Migrate from MongoDB to Postgres. - Migrate from Mongoose to TypeORM. - Upgrade outdated packages - express-winston & winston. - Create start script for building and testing. Incomplete Features: - Adding, removing, and updating members from teams. - RBAC seems to be completely broken as the relevant data is not being loaded into the database. - Setting's do not load into the database (this is broken by purpose as this should be a configuration file?). - Search Service is currently commented out as the logic needs to be rewritten to support SQL. To Do (For Team?): - Flesh out a finalized database schema and verify that all relations between entities are valid. - Change testing kit to support SQL instead of Mongo (simply modifying the identifier's on the dummy objects). - Maybe migrate to Jest? - Migrate controllers and middleware to TypeScript. - The middleware will be the more challenging portion for this. Further Vision: - Migrate to a decorator based approach to controllers and middleware. - A library already exists for the controller's portion. - https://www.npmjs.com/package/@decorators/express - It allows us to add middleware as a parameter onto the route but I would prefer if authentication and authorization were their own decorators. - Example: @Authorize("Admin,User,...") - Example: @Authenticated() - I could be swayed the other way if we find an elegant implementation for both using the inbuilt parameters. - Proper dependency injection. - Find library similar to Guice (TSyringe maybe?). --- .gitignore | 3 + app.js | 4 +- bin/www.js | 1 + constants/role.constant.js | 19 +- constants/routes.constant.js | 133 +- controllers/auth.controller.js | 4 +- docs/api/api_data.js | 12 +- middlewares/account.middleware.js | 7 +- middlewares/auth.middleware.js | 2 +- middlewares/hacker.middleware.js | 2 +- models/account.model.js | 99 - models/account.model.ts | 88 + models/accountConfirmationToken.model.js | 40 - models/accountConfirmationToken.model.ts | 44 + models/application.model.ts | 77 + models/bus.model.js | 52 - models/bus.model.ts | 33 + models/emailTemplate.model.js | 28 - models/emailTemplate.model.ts | 19 + models/hacker.model.js | 194 - models/hacker.model.ts | 58 + models/passwordResetToken.model.js | 23 - models/passwordResetToken.model.ts | 28 + models/role.model.js | 39 - models/role.model.ts | 33 + models/roleBinding.model.js | 30 - models/roleBinding.model.ts | 33 + models/settings.model.js | 31 - models/settings.model.ts | 25 + models/sponsor.model.js | 42 - models/sponsor.model.ts | 21 + models/staff.model.js | 20 - models/staff.model.ts | 7 + models/team.model.js | 40 - models/team.model.ts | 37 + models/travel.model.js | 41 - models/travel.model.ts | 39 + models/volunteer.model.js | 20 - models/volunteer.model.ts | 7 + package-lock.json | 18165 +++++++++++----- package.json | 26 +- services/account.service.js | 158 - services/account.service.ts | 146 + ...vice.js => accountConfirmation.service.ts} | 124 +- services/{auth.service.js => auth.service.ts} | 124 +- services/database.service.js | 78 - services/database.service.ts | 118 + .../{email.service.js => email.service.ts} | 64 +- services/{env.service.js => env.service.ts} | 41 +- .../{hacker.service.js => hacker.service.ts} | 113 +- .../{logger.service.js => logger.service.ts} | 71 +- services/parsePatch.service.js | 21 - services/parsePatch.service.ts | 20 + ...rd.service.js => resetPassword.service.ts} | 106 +- services/role.service.js | 68 - services/role.service.ts | 66 + services/roleBinding.service.js | 119 - services/roleBinding.service.ts | 130 + .../{search.service.js => search.service.ts} | 20 +- ...ettings.service.js => settings.service.ts} | 19 +- services/sponsor.service.js | 76 - services/sponsor.service.ts | 73 + ...{storage.service.js => storage.service.ts} | 30 +- services/{team.service.js => team.service.ts} | 124 +- services/travel.service.js | 112 - services/travel.service.ts | 94 + services/version.service.js | 10 - services/version.service.ts | 7 + services/volunteer.service.js | 56 - services/volunteer.service.ts | 45 + tsconfig.json | 22 + 71 files changed, 14438 insertions(+), 7443 deletions(-) delete mode 100644 models/account.model.js create mode 100644 models/account.model.ts delete mode 100644 models/accountConfirmationToken.model.js create mode 100644 models/accountConfirmationToken.model.ts create mode 100644 models/application.model.ts delete mode 100644 models/bus.model.js create mode 100644 models/bus.model.ts delete mode 100644 models/emailTemplate.model.js create mode 100644 models/emailTemplate.model.ts delete mode 100644 models/hacker.model.js create mode 100644 models/hacker.model.ts delete mode 100644 models/passwordResetToken.model.js create mode 100644 models/passwordResetToken.model.ts delete mode 100644 models/role.model.js create mode 100644 models/role.model.ts delete mode 100644 models/roleBinding.model.js create mode 100644 models/roleBinding.model.ts delete mode 100644 models/settings.model.js create mode 100644 models/settings.model.ts delete mode 100644 models/sponsor.model.js create mode 100644 models/sponsor.model.ts delete mode 100644 models/staff.model.js create mode 100644 models/staff.model.ts delete mode 100644 models/team.model.js create mode 100644 models/team.model.ts delete mode 100644 models/travel.model.js create mode 100644 models/travel.model.ts delete mode 100644 models/volunteer.model.js create mode 100644 models/volunteer.model.ts delete mode 100644 services/account.service.js create mode 100644 services/account.service.ts rename services/{accountConfirmation.service.js => accountConfirmation.service.ts} (67%) rename services/{auth.service.js => auth.service.ts} (68%) delete mode 100644 services/database.service.js create mode 100644 services/database.service.ts rename services/{email.service.js => email.service.ts} (76%) rename services/{env.service.js => env.service.ts} (66%) rename services/{hacker.service.js => hacker.service.ts} (74%) rename services/{logger.service.js => logger.service.ts} (54%) delete mode 100644 services/parsePatch.service.js create mode 100644 services/parsePatch.service.ts rename services/{resetPassword.service.js => resetPassword.service.ts} (56%) delete mode 100644 services/role.service.js create mode 100644 services/role.service.ts delete mode 100644 services/roleBinding.service.js create mode 100644 services/roleBinding.service.ts rename services/{search.service.js => search.service.ts} (90%) rename services/{settings.service.js => settings.service.ts} (67%) delete mode 100644 services/sponsor.service.js create mode 100644 services/sponsor.service.ts rename services/{storage.service.js => storage.service.ts} (76%) rename services/{team.service.js => team.service.ts} (64%) delete mode 100644 services/travel.service.js create mode 100644 services/travel.service.ts delete mode 100644 services/version.service.js create mode 100644 services/version.service.ts delete mode 100644 services/volunteer.service.js create mode 100644 services/volunteer.service.ts create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore index 1017d8ff..8910be12 100755 --- a/.gitignore +++ b/.gitignore @@ -68,3 +68,6 @@ assets/.DS_Store #secrets secret.yaml + +# compile output folder. +dist/ diff --git a/app.js b/app.js index 05434539..99e529a4 100755 --- a/app.js +++ b/app.js @@ -1,6 +1,6 @@ "use strict"; const express = require("express"); -const path = require("path"); +import path from "path"; const cookieParser = require("cookie-parser"); const cookieSession = require("cookie-session"); const cors = require("cors"); @@ -11,7 +11,7 @@ const Services = { env: require("./services/env.service") }; -const envLoadResult = Services.env.load(path.join(__dirname, "./.env")); +const envLoadResult = Services.env.load(path.resolve(__dirname, ".env")); if (envLoadResult.error) { Services.log.warn(envLoadResult.error); } diff --git a/bin/www.js b/bin/www.js index b76aea16..3dcc082c 100755 --- a/bin/www.js +++ b/bin/www.js @@ -2,6 +2,7 @@ /** * Module dependencies. */ +import "reflect-metadata"; const app = require("../app").app; const debug = require("debug")("hackboard:server"); const http = require("http"); diff --git a/constants/role.constant.js b/constants/role.constant.js index dfee5c3e..55d59205 100644 --- a/constants/role.constant.js +++ b/constants/role.constant.js @@ -3,10 +3,9 @@ const Constants = { General: require("./general.constant"), Routes: require("./routes.constant") }; -const mongoose = require("mongoose"); const accountRole = { - _id: mongoose.Types.ObjectId("00000000e285ec4f6ec7e5c2"), + identifier: 0, name: "account", routes: [ Constants.Routes.authRoutes.login, @@ -21,13 +20,13 @@ const accountRole = { }; const adminRole = { - _id: mongoose.Types.ObjectId.createFromTime(1), + identifier: 1, name: Constants.General.STAFF, routes: Constants.Routes.listAllRoutes() }; const hackerRole = { - _id: mongoose.Types.ObjectId.createFromTime(2), + identifier: 2, name: Constants.General.HACKER, routes: [ Constants.Routes.hackerRoutes.post, @@ -51,7 +50,7 @@ const hackerRole = { }; const volunteerRole = { - _id: mongoose.Types.ObjectId.createFromTime(3), + identifier: 3, name: Constants.General.VOLUNTEER, routes: [ Constants.Routes.volunteerRoutes.getSelfById, @@ -65,7 +64,7 @@ const volunteerRole = { }; const sponsorT1Role = { - _id: mongoose.Types.ObjectId.createFromTime(4), + identifier: 4, name: Constants.General.SPONSOR_T1, routes: [ Constants.Routes.sponsorRoutes.post, @@ -80,7 +79,7 @@ const sponsorT1Role = { }; const sponsorT2Role = { - _id: mongoose.Types.ObjectId.createFromTime(5), + identifier: 5, name: Constants.General.SPONSOR_T2, routes: [ Constants.Routes.sponsorRoutes.post, @@ -95,7 +94,7 @@ const sponsorT2Role = { }; const sponsorT3Role = { - _id: mongoose.Types.ObjectId.createFromTime(6), + identifier: 6, name: Constants.General.SPONSOR_T3, routes: [ Constants.Routes.sponsorRoutes.post, @@ -110,7 +109,7 @@ const sponsorT3Role = { }; const sponsorT4Role = { - _id: mongoose.Types.ObjectId.createFromTime(7), + identifier: 7, name: Constants.General.SPONSOR_T4, routes: [ Constants.Routes.sponsorRoutes.post, @@ -125,7 +124,7 @@ const sponsorT4Role = { }; const sponsorT5Role = { - _id: mongoose.Types.ObjectId.createFromTime(8), + identifier: 8, name: Constants.General.SPONSOR_T5, routes: [ Constants.Routes.sponsorRoutes.post, diff --git a/constants/routes.constant.js b/constants/routes.constant.js index 79d4c460..031d72f6 100644 --- a/constants/routes.constant.js +++ b/constants/routes.constant.js @@ -14,33 +14,32 @@ */ const Constants = require("./general.constant"); -const mongoose = require("mongoose"); const authRoutes = { login: { requestType: Constants.REQUEST_TYPES.POST, uri: "/api/auth/login", - _id: mongoose.Types.ObjectId.createFromTime(100) + _id: 100 }, logout: { requestType: Constants.REQUEST_TYPES.POST, uri: "/api/auth/logout", - _id: mongoose.Types.ObjectId.createFromTime(101) + _id: 101 }, getSelfRoleBindindings: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/auth/rolebindings/" + Constants.ROLE_CATEGORIES.SELF, - _id: mongoose.Types.ObjectId.createFromTime(102) + _id: 102 }, getAnyRoleBindings: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/auth/rolebindings/" + Constants.ROLE_CATEGORIES.ALL, - _id: mongoose.Types.ObjectId.createFromTime(103) + _id: 103 }, changePassword: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/auth/password/change", - _id: mongoose.Types.ObjectId.createFromTime(104) + _id: 104 } }; @@ -48,37 +47,37 @@ const accountRoutes = { getSelf: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/account/self", - _id: mongoose.Types.ObjectId.createFromTime(105) + _id: 105 }, getSelfById: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/account/" + Constants.ROLE_CATEGORIES.SELF, - _id: mongoose.Types.ObjectId.createFromTime(106) + _id: 106 }, getAnyById: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/account/" + Constants.ROLE_CATEGORIES.ALL, - _id: mongoose.Types.ObjectId.createFromTime(107) + _id: 107 }, post: { requestType: Constants.REQUEST_TYPES.POST, uri: "/api/account/", - _id: mongoose.Types.ObjectId.createFromTime(108) + _id: 108 }, patchSelfById: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/account/" + Constants.ROLE_CATEGORIES.SELF, - _id: mongoose.Types.ObjectId.createFromTime(109) + _id: 109 }, patchAnyById: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/account/" + Constants.ROLE_CATEGORIES.ALL, - _id: mongoose.Types.ObjectId.createFromTime(110) + _id: 110 }, inviteAccount: { requestType: Constants.REQUEST_TYPES.POST, uri: "/api/account/invite", - _id: mongoose.Types.ObjectId.createFromTime(111) + _id: 111 } }; @@ -86,122 +85,122 @@ const hackerRoutes = { getSelf: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/hacker/self/", - _id: mongoose.Types.ObjectId.createFromTime(112) + _id: 112 }, getSelfById: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/hacker/" + Constants.ROLE_CATEGORIES.SELF, - _id: mongoose.Types.ObjectId.createFromTime(113) + _id: 113 }, getAnyById: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/hacker/" + Constants.ROLE_CATEGORIES.ALL, - _id: mongoose.Types.ObjectId.createFromTime(114) + _id: 114 }, getSelfByEmail: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/hacker/email/" + Constants.ROLE_CATEGORIES.SELF, - _id: mongoose.Types.ObjectId.createFromTime(115) + _id: 115 }, getAnyByEmail: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/hacker/email/" + Constants.ROLE_CATEGORIES.ALL, - _id: mongoose.Types.ObjectId.createFromTime(116) + _id: 116 }, getSelfResumeById: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/hacker/resume/" + Constants.ROLE_CATEGORIES.SELF, - _id: mongoose.Types.ObjectId.createFromTime(117) + _id: 117 }, getAnyResumeById: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/hacker/resume/" + Constants.ROLE_CATEGORIES.ALL, - _id: mongoose.Types.ObjectId.createFromTime(118) + _id: 118 }, post: { requestType: Constants.REQUEST_TYPES.POST, uri: "/api/hacker/", - _id: mongoose.Types.ObjectId.createFromTime(119) + _id: 119 }, postSelfResumeById: { requestType: Constants.REQUEST_TYPES.POST, uri: "/api/hacker/resume/" + Constants.ROLE_CATEGORIES.SELF, - _id: mongoose.Types.ObjectId.createFromTime(120) + _id: 120 }, postAnyResumeById: { requestType: Constants.REQUEST_TYPES.POST, uri: "/api/hacker/resume/" + Constants.ROLE_CATEGORIES.ALL, - _id: mongoose.Types.ObjectId.createFromTime(121) + _id: 121 }, patchSelfById: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/hacker/" + Constants.ROLE_CATEGORIES.SELF, - _id: mongoose.Types.ObjectId.createFromTime(122) + _id: 122 }, patchAnyById: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/hacker/" + Constants.ROLE_CATEGORIES.ALL, - _id: mongoose.Types.ObjectId.createFromTime(123) + _id: 123 }, patchAnyStatusById: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/hacker/status/" + Constants.ROLE_CATEGORIES.ALL, - _id: mongoose.Types.ObjectId.createFromTime(124) + _id: 124 }, patchSelfStatusById: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/hacker/status/" + Constants.ROLE_CATEGORIES.SELF, - _id: mongoose.Types.ObjectId.createFromTime(125) + _id: 125 }, patchSelfCheckInById: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/hacker/checkin/" + Constants.ROLE_CATEGORIES.SELF, - _id: mongoose.Types.ObjectId.createFromTime(126) + _id: 126 }, patchAnyCheckInById: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/hacker/checkin/" + Constants.ROLE_CATEGORIES.ALL, - _id: mongoose.Types.ObjectId.createFromTime(127) + _id: 127 }, patchSelfConfirmationById: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/hacker/confirmation/" + Constants.ROLE_CATEGORIES.SELF, - _id: mongoose.Types.ObjectId.createFromTime(128) + _id: 128 }, patchAcceptHackerById: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/hacker/accept/" + Constants.ROLE_CATEGORIES.ALL, - _id: mongoose.Types.ObjectId.createFromTime(129) + _id: 129 }, patchAcceptHackerByEmail: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/hacker/acceptEmail/" + Constants.ROLE_CATEGORIES.ALL, - _id: mongoose.Types.ObjectId.createFromTime(130) + _id: 130 }, patchAcceptHackerByArrayOfIds: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/hacker/batchAccept", - _id: mongoose.Types.ObjectId.createFromTime(165) + _id: 165 }, postAnySendWeekOfEmail: { requestType: Constants.REQUEST_TYPES.POST, uri: "/api/hacker/email/weekOf/" + Constants.ROLE_CATEGORIES.ALL, - _id: mongoose.Types.ObjectId.createFromTime(131) + _id: 131 }, postSelfSendWeekOfEmail: { requestType: Constants.REQUEST_TYPES.POST, uri: "/api/hacker/email/weekOf/" + Constants.ROLE_CATEGORIES.SELF, - _id: mongoose.Types.ObjectId.createFromTime(132) + _id: 132 }, postAnySendDayOfEmail: { requestType: Constants.REQUEST_TYPES.POST, uri: "/api/hacker/email/dayOf/" + Constants.ROLE_CATEGORIES.ALL, - _id: mongoose.Types.ObjectId.createFromTime(133) + _id: 133 }, postSelfSendDayOfEmail: { requestType: Constants.REQUEST_TYPES.POST, uri: "/api/hacker/email/dayOf/" + Constants.ROLE_CATEGORIES.SELF, - _id: mongoose.Types.ObjectId.createFromTime(134) + _id: 134 } }; @@ -209,42 +208,42 @@ const travelRoutes = { getSelf: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/travel/self/", - _id: mongoose.Types.ObjectId.createFromTime(135) + _id: 135 }, getSelfById: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/travel/" + Constants.ROLE_CATEGORIES.SELF, - _id: mongoose.Types.ObjectId.createFromTime(136) + _id: 136 }, getAnyById: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/travel/" + Constants.ROLE_CATEGORIES.ALL, - _id: mongoose.Types.ObjectId.createFromTime(137) + _id: 137 }, getSelfByEmail: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/travel/email/" + Constants.ROLE_CATEGORIES.SELF, - _id: mongoose.Types.ObjectId.createFromTime(138) + _id: 138 }, getAnyByEmail: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/travel/email/" + Constants.ROLE_CATEGORIES.ALL, - _id: mongoose.Types.ObjectId.createFromTime(139) + _id: 139 }, post: { requestType: Constants.REQUEST_TYPES.POST, uri: "/api/travel/", - _id: mongoose.Types.ObjectId.createFromTime(140) + _id: 140 }, patchAnyStatusById: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/travel/status/" + Constants.ROLE_CATEGORIES.ALL, - _id: mongoose.Types.ObjectId.createFromTime(141) + _id: 141 }, patchAnyOfferById: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/travel/offer/" + Constants.ROLE_CATEGORIES.ALL, - _id: mongoose.Types.ObjectId.createFromTime(142) + _id: 142 } }; @@ -252,32 +251,32 @@ const sponsorRoutes = { getSelf: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/sponsor/self/", - _id: mongoose.Types.ObjectId.createFromTime(143) + _id: 143 }, getSelfById: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/sponsor/" + Constants.ROLE_CATEGORIES.SELF, - _id: mongoose.Types.ObjectId.createFromTime(144) + _id: 144 }, getAnyById: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/sponsor/" + Constants.ROLE_CATEGORIES.ALL, - _id: mongoose.Types.ObjectId.createFromTime(145) + _id: 145 }, post: { requestType: Constants.REQUEST_TYPES.POST, uri: "/api/sponsor/", - _id: mongoose.Types.ObjectId.createFromTime(146) + _id: 146 }, patchSelfById: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/sponsor/" + Constants.ROLE_CATEGORIES.SELF, - _id: mongoose.Types.ObjectId.createFromTime(147) + _id: 147 }, patchAnyById: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/sponsor/" + Constants.ROLE_CATEGORIES.ALL, - _id: mongoose.Types.ObjectId.createFromTime(148) + _id: 148 } }; @@ -285,32 +284,32 @@ const teamRoutes = { get: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/team/" + Constants.ROLE_CATEGORIES.ALL, - _id: mongoose.Types.ObjectId.createFromTime(149) + _id: 149 }, post: { requestType: Constants.REQUEST_TYPES.POST, uri: "/api/team/", - _id: mongoose.Types.ObjectId.createFromTime(150) + _id: 150 }, join: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/team/join/", - _id: mongoose.Types.ObjectId.createFromTime(151) + _id: 151 }, patchSelfById: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/team/" + Constants.ROLE_CATEGORIES.SELF, - _id: mongoose.Types.ObjectId.createFromTime(152) + _id: 152 }, patchAnyById: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/team/" + Constants.ROLE_CATEGORIES.ALL, - _id: mongoose.Types.ObjectId.createFromTime(153) + _id: 153 }, leave: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/team/leave/", - _id: mongoose.Types.ObjectId.createFromTime(154) + _id: 154 } }; @@ -318,17 +317,17 @@ const volunteerRoutes = { getSelfById: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/volunteer/" + Constants.ROLE_CATEGORIES.SELF, - _id: mongoose.Types.ObjectId.createFromTime(155) + _id: 155 }, getAnyById: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/volunteer/" + Constants.ROLE_CATEGORIES.ALL, - _id: mongoose.Types.ObjectId.createFromTime(156) + _id: 156 }, post: { requestType: Constants.REQUEST_TYPES.POST, uri: "/api/volunteer/", - _id: mongoose.Types.ObjectId.createFromTime(157) + _id: 157 } }; @@ -336,7 +335,7 @@ const roleRoutes = { post: { requestType: Constants.REQUEST_TYPES.POST, uri: "/api/role/", - _id: mongoose.Types.ObjectId.createFromTime(158) + _id: 158 } }; @@ -344,7 +343,7 @@ const searchRoutes = { get: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/search/", - _id: mongoose.Types.ObjectId.createFromTime(159) + _id: 159 } }; @@ -352,17 +351,17 @@ const staffRoutes = { hackerStats: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/hacker/stats", - _id: mongoose.Types.ObjectId.createFromTime(160) + _id: 160 }, postInvite: { requestType: Constants.REQUEST_TYPES.POST, uri: "/api/account/invite", - _id: mongoose.Types.ObjectId.createFromTime(161) + _id: 161 }, getInvite: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/account/invite", - _id: mongoose.Types.ObjectId.createFromTime(162) + _id: 162 } }; @@ -370,12 +369,12 @@ const settingsRoutes = { getSettings: { requestType: Constants.REQUEST_TYPES.GET, uri: "/api/settings", - _id: mongoose.Types.ObjectId.createFromTime(163) + _id: 163 }, patchSettings: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/settings", - _id: mongoose.Types.ObjectId.createFromTime(164) + _id: 164 } }; diff --git a/controllers/auth.controller.js b/controllers/auth.controller.js index b3438811..885275bd 100644 --- a/controllers/auth.controller.js +++ b/controllers/auth.controller.js @@ -5,14 +5,14 @@ const Success = require("../constants/success.constant"); module.exports = { onSuccessfulLogin: function(req, res) { return res.status(200).json({ - message: Success.LOGIN, + message: Success.AUTH_LOGIN, data: {} }); }, logout: function(req, res) { req.logout(); return res.status(200).json({ - message: Success.LOGOUT, + message: Success.AUTH_LOGOUT, data: {} }); }, diff --git a/docs/api/api_data.js b/docs/api/api_data.js index 25e0c5a6..af1aa91e 100644 --- a/docs/api/api_data.js +++ b/docs/api/api_data.js @@ -1501,7 +1501,7 @@ define({ "api": [ "examples": [ { "title": "application: ", - "content": "{\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accomodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n}", + "content": "{\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accommodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n}", "type": "Json" } ] @@ -1528,7 +1528,7 @@ define({ "api": [ "examples": [ { "title": "Success-Response: ", - "content": "{\n \"message\": \"Hacker creation successful\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accomodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n}", + "content": "{\n \"message\": \"Hacker creation successful\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accommodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n}", "type": "object" } ] @@ -1610,7 +1610,7 @@ define({ "api": [ "examples": [ { "title": "Success-Response: ", - "content": "{\n \"message\": \"Successfully retrieved hacker information\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"Applied\",\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accomodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n }\n }", + "content": "{\n \"message\": \"Successfully retrieved hacker information\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"Applied\",\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accommodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n }\n }", "type": "object" } ] @@ -1692,7 +1692,7 @@ define({ "api": [ "examples": [ { "title": "Success-Response: ", - "content": "{\n \"message\": \"Successfully retrieved hacker information\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"Applied\",\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accomodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n }\n }", + "content": "{\n \"message\": \"Successfully retrieved hacker information\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"Applied\",\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accommodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n }\n }", "type": "object" } ] @@ -1927,7 +1927,7 @@ define({ "api": [ "examples": [ { "title": "application: ", - "content": "{\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accomodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n }", + "content": "{\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accommodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n }", "type": "Json" } ] @@ -1954,7 +1954,7 @@ define({ "api": [ "examples": [ { "title": "Success-Response: ", - "content": "{\n \"message\": \"Changed hacker information\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"Applied\",\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accomodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n }\n}", + "content": "{\n \"message\": \"Changed hacker information\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"Applied\",\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accommodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n }\n}", "type": "object" } ] diff --git a/middlewares/account.middleware.js b/middlewares/account.middleware.js index ad4df867..a39751be 100644 --- a/middlewares/account.middleware.js +++ b/middlewares/account.middleware.js @@ -1,7 +1,6 @@ "use strict"; const TAG = `[ ADDRESS.MIDDLEWARE.js ]`; -const mongoose = require("mongoose"); const Services = { RoleBinding: require("../services/roleBinding.service"), Logger: require("../services/logger.service"), @@ -29,7 +28,7 @@ const Constants = { * @description Delete the req.body.id that was added by the validation of route parameter. */ function parsePatch(req, res, next) { - delete req.body.id; + delete req.body.identifier; return next(); } @@ -46,7 +45,7 @@ function parsePatch(req, res, next) { */ function parseAccount(req, res, next) { const accountDetails = { - _id: mongoose.Types.ObjectId(), + _id: req.body.identifier, firstName: req.body.firstName, lastName: req.body.lastName, pronoun: req.body.pronoun, @@ -96,7 +95,7 @@ async function updatePassword(req, res, next) { * @description Retrieves an account's information from mongoId specified in req.body.id, and places it in req.body.account */ async function getById(req, res, next) { - const acc = await Services.Account.findById(req.body.id); + const acc = await Services.Account.findById(req.body.identifier); if (!acc) { return next({ diff --git a/middlewares/auth.middleware.js b/middlewares/auth.middleware.js index eeb898c7..3231a0f2 100644 --- a/middlewares/auth.middleware.js +++ b/middlewares/auth.middleware.js @@ -31,7 +31,7 @@ const Constants = { * Failed authentication returns a AUTH 401 error, and errors during login will return res with a LOGIN 500 error. */ function login(req, res, next) { - passport.authenticate("emailAndPass", function(err, user) { + passport.authenticate(Services.Auth.emailAndPassStrategy, function(err, user) { if (err) { return next({ status: 500, diff --git a/middlewares/hacker.middleware.js b/middlewares/hacker.middleware.js index 1c70829c..d3aabbfe 100644 --- a/middlewares/hacker.middleware.js +++ b/middlewares/hacker.middleware.js @@ -502,7 +502,7 @@ async function sendWeekOfEmail(req, res, next) { const ticketSVG = await Services.Hacker.generateQRCode( singleHackerViewLink ); - const account = await Services.Account.findById(hacker.accountId); + const account = await Services.Account.findById(hacker.identifier); if (!account || !ticketSVG) { return next({ status: 500, diff --git a/models/account.model.js b/models/account.model.js deleted file mode 100644 index 292cd66e..00000000 --- a/models/account.model.js +++ /dev/null @@ -1,99 +0,0 @@ -"use strict"; -const mongoose = require("mongoose"); -const bcrypt = require("bcrypt"); -const Constants = require("../constants/general.constant"); -//describes the data type -const AccountSchema = new mongoose.Schema({ - firstName: { - type: String, - required: true - }, - lastName: { - type: String, - required: true - }, - pronoun: { - type: String, - default: "Prefer not to say" - }, - gender: { - type: String, - default: "Prefer not to say" - }, - email: { - type: String, - trim: true, - lowercase: true, - unique: true, - required: "Email address is required", - match: [Constants.EMAIL_REGEX, "Please fill a valid email address"] - }, - password: { - type: String, - required: true - }, - dietaryRestrictions: [ - { - type: String - } - ], - confirmed: { - type: Boolean, - default: false - }, - accountType: { - type: String, - enum: Constants.EXTENDED_USER_TYPES, - default: Constants.HACKER - }, - birthDate: { - type: Date, - required: true - }, - phoneNumber: { - type: Number - } -}); - -AccountSchema.methods.toJSON = function() { - const as = this.toObject(); - delete as.__v; - as.id = as._id; - delete as._id; - return as; -}; -//deletes password -AccountSchema.methods.toStrippedJSON = function() { - const as = this.toJSON(); - delete as.password; - return as; -}; -/** - * Pass in an un-encrypted password and see whether it matches the - * encrypted password - * @param {String} password - */ -AccountSchema.methods.comparePassword = function(password) { - return bcrypt.compareSync(password, this.password); -}; -/** - * Returns if the accountType corresponds to a sponsor - */ -AccountSchema.methods.isSponsor = function() { - return ( - Constants.SPONSOR_TIERS.includes(this.accountType) || - this.accountType == Constants.SPONSOR - ); -}; -/** - * Calculates the user's age - */ -AccountSchema.methods.getAge = function() { - // birthday is a date - var ageDifMs = Date.now() - this.birthDate.getTime(); - var ageDate = new Date(ageDifMs); // miliseconds from epoch - return Math.abs(ageDate.getUTCFullYear() - 1970); -}; - -//export the model -module.exports = mongoose.model("Account", AccountSchema); diff --git a/models/account.model.ts b/models/account.model.ts new file mode 100644 index 00000000..23102f06 --- /dev/null +++ b/models/account.model.ts @@ -0,0 +1,88 @@ +import { Column, Entity, PrimaryGeneratedColumn, BaseEntity } from "typeorm"; +import { compareSync } from "bcrypt"; +import { IsEmail, IsPhoneNumber } from "class-validator"; +import * as Constants from "../constants/general.constant"; + +@Entity() +export class Account extends BaseEntity { + @PrimaryGeneratedColumn() + identifier: number; + + @Column("varchar", { nullable: false }) + firstName: string; + + @Column("varchar", { nullable: false }) + lastName: string; + + @Column("varchar", { default: "Prefer not to say" }) + pronoun: string; + + @Column("varchar", { default: "Prefer not to say" }) + gender: string; + + @Column("varchar", { nullable: false, unique: true }) + @IsEmail() + email: string; + + @Column("varchar", { nullable: false }) + password: string; + + @Column("varchar") + dietaryRestrictions: string; + + @Column("bool", { default: false }) + confirmed: Boolean; + + @Column({ + enum: Constants.EXTENDED_USER_TYPES, + default: Constants.HACKER + }) + accountType: string; + + @Column("date", { nullable: false }) + birthDate: Date; + + @Column() + @IsPhoneNumber() + phoneNumber: number; + + toJSON() { + return this; + } + + // Delete's Password + toStrippedJSON() { + return { ...this, password: undefined }; + } + + /** + * Pass in an un-encrypted password and see whether it matches the + * encrypted password + * @param {String} password + */ + comparePassword(password: string) { + return compareSync(password, this.password); + } + + /** + * Returns if the accountType corresponds to a sponsor + */ + isSponsor() { + return ( + Constants.SPONSOR_TIERS.includes(this.accountType) || + this.accountType == Constants.SPONSOR + ); + } + + /** + * Calculates the user's age + */ + getAge() { + // birthday is a date + var ageDifMs = Date.now() - this.birthDate.getTime(); + var ageDate = new Date(ageDifMs); // miliseconds from epoch + return Math.abs(ageDate.getUTCFullYear() - 1970); + } +} + +export default Account; diff --git a/models/accountConfirmationToken.model.js b/models/accountConfirmationToken.model.js deleted file mode 100644 index a05eca85..00000000 --- a/models/accountConfirmationToken.model.js +++ /dev/null @@ -1,40 +0,0 @@ -"use strict"; -const mongoose = require("mongoose"); -const Constants = { - General: require("../constants/general.constant") -}; - -const AccountConfirmationSchema = new mongoose.Schema({ - accountId: { - type: mongoose.Schema.Types.ObjectId, - ref: "Account", - required: false - }, - accountType: { - type: String, - enum: Constants.General.EXTENDED_USER_TYPES, - default: Constants.General.HACKER - }, - email: { - type: String, - required: true - }, - confirmationType: { - type: String, - enum: Constants.General.CONFIRMATION_TYPES, - default: Constants.General.CONFIRMATION_TYPE_ORGANIC - } -}); - -AccountConfirmationSchema.methods.toJSON = function() { - const resetObj = this.toObject(); - delete resetObj.__v; - resetObj.id = resetObj._id; - delete resetObj._id; - return resetObj; -}; - -module.exports = mongoose.model( - "AccountConfirmationToken", - AccountConfirmationSchema -); diff --git a/models/accountConfirmationToken.model.ts b/models/accountConfirmationToken.model.ts new file mode 100644 index 00000000..459fb2a8 --- /dev/null +++ b/models/accountConfirmationToken.model.ts @@ -0,0 +1,44 @@ +import { + Entity, + BaseEntity, + Column, + JoinColumn, + OneToOne, + PrimaryGeneratedColumn +} from "typeorm"; +import Account from "./account.model"; + +const Constants = { + General: require("../constants/general.constant") +}; + +@Entity() +class AccountConfirmation extends BaseEntity { + @PrimaryGeneratedColumn() + identifier: number; + + @OneToOne(() => Account) + @JoinColumn() + account?: Account; + + @Column({ + enum: Constants.General.EXTENDED_USER_TYPES, + default: Constants.General.HACKER + }) + accountType: string; + + @Column({ nullable: false }) + email: string; + + @Column({ + enum: Constants.General.CONFIRMATION_TYPES, + default: Constants.General.CONFIRMATION_TYPE_ORGANIC + }) + confirmationType: string; + + toJSON() { + return this; + } +} + +export default AccountConfirmation; diff --git a/models/application.model.ts b/models/application.model.ts new file mode 100644 index 00000000..9f4931f3 --- /dev/null +++ b/models/application.model.ts @@ -0,0 +1,77 @@ +import { + Entity, + BaseEntity, + PrimaryGeneratedColumn, + Column, + ManyToOne, + JoinColumn +} from "typeorm"; +import Hacker from "./hacker.model"; + +interface ApplicationSchema { + general: { + school: string; + degree: string; + fieldOfStudy: string[]; + graduationYear: number; + jobInterest: string; + URL: { + //gcloud bucket link + resume: string; + github?: string; + dribbble?: string; + personal?: string; + linkedIn?: string; + other?: string; + }; + }; + shortAnswer: { + skills: string[]; + //any miscelaneous comments that the user has + comments: string; + //"Why do you want to come to our hackathon?" + question1: string; + // "Some Q" + question2: string; + previousHackathons: number; + }; + other: { + ethnicity: string[]; + privacyPolicy: boolean; + codeOfConduct: boolean; + }; + accommodation: { + impairments?: string; + barriers?: string; + shirtSize: string; + travel: number; + attendancePreference: string; + }; + //TODO: Add team back? + location: { + timeZone?: string; + country?: string; + city?: string; + }; +} + +@Entity() +class Application extends BaseEntity { + @PrimaryGeneratedColumn() + identifier: number; + + @Column({ nullable: false }) + year: number; + + @Column("jsonb", { nullable: false }) + data: ApplicationSchema; + + @ManyToOne( + () => Hacker, + (hacker: Hacker) => hacker.applications + ) + @JoinColumn() + hacker: Hacker; +} + +export default Application; diff --git a/models/bus.model.js b/models/bus.model.js deleted file mode 100644 index 1419e694..00000000 --- a/models/bus.model.js +++ /dev/null @@ -1,52 +0,0 @@ -"use strict"; -const mongoose = require("mongoose"); -//describes the data type -const BusSchema = new mongoose.Schema({ - origin: { - country: { - type: String, - required: true - }, - provinceOrState: { - type: String, - required: true - }, - zip: { - type: String, - required: true - }, - city: { - type: String, - required: true - }, - addr1: { - type: String, - required: true - }, - addr2: String - }, - capacity: { - type: Number, - required: true, - min: 0 - }, - hackers: { - type: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: "Hacker" - } - ] - // TODO: find way to validate that this array size is smaller than the max capacity - } -}); - -BusSchema.methods.toJSON = function() { - const bs = this.toObject(); - delete bs.__v; - bs.id = bs._id; - delete bs._id; - return bs; -}; -//export the model -module.exports = mongoose.model("Bus", BusSchema); diff --git a/models/bus.model.ts b/models/bus.model.ts new file mode 100644 index 00000000..a5933603 --- /dev/null +++ b/models/bus.model.ts @@ -0,0 +1,33 @@ +import { Entity, BaseEntity, Column, ManyToOne, JoinColumn, PrimaryGeneratedColumn } from "typeorm"; +import Hacker from "./hacker.model"; + +interface OriginSchema { + country: string; + region: string; // Province or State + postal: string; + city: string; + addr1: string; + addr2?: string; +} + +@Entity() +class Bus extends BaseEntity { + @PrimaryGeneratedColumn() + identifier: number; + + @Column("jsonb", { nullable: false }) + origin: OriginSchema; + + @Column({ nullable: false }) + capacity: number; + + @ManyToOne(() => Hacker) + @JoinColumn() + hackers: Hacker[]; + + toJSON() { + return this; + } +} + +export default Bus; diff --git a/models/emailTemplate.model.js b/models/emailTemplate.model.js deleted file mode 100644 index 11343bc8..00000000 --- a/models/emailTemplate.model.js +++ /dev/null @@ -1,28 +0,0 @@ -"use strict"; -const mongoose = require("mongoose"); - -// describes the data type -const EmailTemplateSchema = new mongoose.Schema({ - name: { - type: String, - required: true - }, - content: { - type: String, - required: true - } -}); - -EmailTemplateSchema.methods.toJSON = function () { - const emailTemplateObj = this.toObject(); - delete emailTemplateObj.__v; - emailTemplateObj.id = emailTemplateObj._id; - delete emailTemplateObj._id; - return emailTemplateObj; -}; - -// export the model -module.exports = mongoose.model( - "EmailTemplate", - EmailTemplateSchema -); diff --git a/models/emailTemplate.model.ts b/models/emailTemplate.model.ts new file mode 100644 index 00000000..21dcf67b --- /dev/null +++ b/models/emailTemplate.model.ts @@ -0,0 +1,19 @@ +import { Entity, BaseEntity, Column, PrimaryGeneratedColumn } from "typeorm"; + +@Entity() +class EmailTemplate extends BaseEntity { + @PrimaryGeneratedColumn() + identifier: number; + + @Column({ nullable: false }) + name: string; + + @Column({ nullable: false }) + content: string; + + toJSON() { + return this; + } +} + +export default EmailTemplate; diff --git a/models/hacker.model.js b/models/hacker.model.js deleted file mode 100644 index f59f8087..00000000 --- a/models/hacker.model.js +++ /dev/null @@ -1,194 +0,0 @@ -"use strict"; -const Constants = require("../constants/general.constant"); -const mongoose = require("mongoose"); -//describes the data type -const HackerSchema = new mongoose.Schema({ - //account id - accountId: { - type: mongoose.Schema.Types.ObjectId, - ref: "Account", - required: true - }, - status: { - type: String, - enum: Constants.HACKER_STATUSES, - required: true, - default: "None" - }, - application: { - general: { - school: { - type: String, - required: true - }, - degree: { - type: String, - required: true - }, - fieldOfStudy: [ - { - type: String, - required: true - } - ], - graduationYear: { - type: Number, - required: true - }, - jobInterest: { - type: String, - enum: Constants.JOB_INTERESTS, - required: true, - default: "None" - }, - URL: { - //gcloud bucket link - resume: { - type: String, - default: "" - }, - github: { - type: String - }, - dribbble: { - type: String - }, - personal: { - type: String - }, - linkedIn: { - type: String - }, - other: { - type: String - } - } - }, - shortAnswer: { - skills: [ - { - type: String - } - ], - //any miscelaneous comments that the user has - comments: { - type: String, - default: "" - }, - //"Why do you want to come to our hackathon?" - question1: { - type: String, - default: "", - required: true - }, - // "Some Q" - question2: { - type: String, - default: "", - required: true - }, - previousHackathons: { - type: Number, - enum: Constants.PREVIOUS_HACKATHONS, - required: true - } - }, - other: { - ethnicity: { - type: [ - { - type: String, - required: true - } - ], - required: true - }, - privacyPolicy: { - type: Boolean, - required: true - }, - codeOfConduct: { - type: Boolean, - required: true - } - }, - accommodation: { - impairments: { - type: String, - default: "" - }, - barriers: { - type: String, - default: "" - }, - shirtSize: { - type: String, - enum: Constants.SHIRT_SIZES, - required: true - }, - travel: { type: Number, default: 0 }, - attendancePreference: { - type: String, - enum: Constants.ATTENDANCE_PREFERENCES, - required: true - } - }, - team: { - type: mongoose.Schema.Types.ObjectId, - ref: "Team" - }, - location: { - timeZone: { - type: String, - default: "" - }, - country: { - type: String, - default: "" - }, - city: { - type: String, - default: "" - } - } - }, - teamId: { - type: mongoose.Schema.Types.ObjectId, - ref: "Team" - }, -}); - -HackerSchema.methods.toJSON = function() { - const hs = this.toObject(); - delete hs.__v; - hs.id = hs._id; - delete hs._id; - return hs; -}; -HackerSchema.methods.isApplicationComplete = function() { - const hs = this.toObject(); - const portfolioDone = !!hs.application.general.URL.resume; - const jobInterestDone = !!hs.application.general.jobInterest; - const question1Done = !!hs.application.shortAnswer.question1; - const question2Done = !!hs.application.shortAnswer.question2; - const previousHackathonsDone = !!hs.application.shortAnswer.previousHackathons; - const attendancePreferenceDone = !!hs.application.accommodation.attendancePreference; - return portfolioDone && jobInterestDone && question1Done && question2Done && previousHackathonsDone && attendancePreferenceDone; -}; - -/** - * @param field the field which should be queried - * @returns {String} type of the field being queried - * @description return the type of the field(if it exists and is allowed to be searched on) - */ -HackerSchema.statics.searchableField = function(field) { - const schemaField = HackerSchema.path(field); - if (schemaField != undefined) { - return schemaField.instance; - } else { - return null; - } -}; - -//export the model -module.exports = mongoose.model("Hacker", HackerSchema); diff --git a/models/hacker.model.ts b/models/hacker.model.ts new file mode 100644 index 00000000..9727c01d --- /dev/null +++ b/models/hacker.model.ts @@ -0,0 +1,58 @@ +import * as Constants from "../constants/general.constant"; +import { Column, Entity, JoinColumn, OneToMany, ManyToOne } from "typeorm"; +import Account from "./account.model"; +import Application from "./application.model"; +import Team from "./team.model"; + +@Entity() +class Hacker extends Account { + @Column({ + enum: Constants.HACKER_STATUSES, + nullable: false, + default: "None" + }) + status: string; + + @OneToMany( + () => Application, + (application) => application.hacker + ) + @JoinColumn() + applications: Application[]; + + //TODO: Implement Team One To One + @ManyToOne( + () => Team, + (team) => team.hackers + ) + team: Team; + + toJSON() { + return this; + } + + isApplicationComplete() { + const application = this.applications[this.applications.length - 1]; + if (application == null) return false; + + const portfolioDone = !!application.data.general.URL.resume; + const jobInterestDone = !!application.data.general.jobInterest; + const questionOneDone = !!application.data.shortAnswer.question1; + const questionTwoDone = !!application.data.shortAnswer.question2; + const previousHackathonsDone = !!application.data.shortAnswer + .previousHackathons; + const attendancePreferenceDone = !!application.data.accommodation + .attendancePreference; + + return ( + portfolioDone && + jobInterestDone && + questionOneDone && + questionTwoDone && + previousHackathonsDone && + attendancePreferenceDone + ); + } +} + +export default Hacker; diff --git a/models/passwordResetToken.model.js b/models/passwordResetToken.model.js deleted file mode 100644 index 012cd6f6..00000000 --- a/models/passwordResetToken.model.js +++ /dev/null @@ -1,23 +0,0 @@ -"use strict"; -const mongoose = require("mongoose"); -const passwordResetSchema = new mongoose.Schema({ - accountId: { - type: mongoose.Schema.Types.ObjectId, - required: true, - ref: "Account" - }, - created: { - type: Date, - required: true - } -}); - -passwordResetSchema.methods.toJSON = function() { - const resetObj = this.toObject(); - delete resetObj.__v; - resetObj.id = resetObj._id; - delete resetObj._id; - return resetObj; -}; - -module.exports = mongoose.model("PasswordResetToken", passwordResetSchema); diff --git a/models/passwordResetToken.model.ts b/models/passwordResetToken.model.ts new file mode 100644 index 00000000..ef107229 --- /dev/null +++ b/models/passwordResetToken.model.ts @@ -0,0 +1,28 @@ +import { + Entity, + BaseEntity, + Column, + JoinColumn, + OneToOne, + PrimaryGeneratedColumn +} from "typeorm"; +import Account from "./account.model"; + +@Entity() +class PasswordReset extends BaseEntity { + @PrimaryGeneratedColumn() + identifier: number; + + @OneToOne(() => Account) + @JoinColumn() + account: Account; + + @Column({ nullable: false }) + createdAt: Date; + + toJSON() { + return this; + } +} + +export default PasswordReset; diff --git a/models/role.model.js b/models/role.model.js deleted file mode 100644 index 810465ea..00000000 --- a/models/role.model.js +++ /dev/null @@ -1,39 +0,0 @@ -"use strict"; -const mongoose = require("mongoose"); -const Constants = require("../constants/general.constant"); -/** - * The name is descriptive of the role - * Each role may have different routes, where route parameters in the uri are replaced with :self or :all - */ -const RoleSchema = new mongoose.Schema({ - // The name should be something like "hacker", or "sponsor". - // For roles with singular routes, the name of the role will be the name of the route plus the api route - // For example, "getSelfAccount" - name: { - type: String, - unique: true, - required: true - }, - //The array of routes that this Role should have access to. - routes: [ - { - uri: { - type: String - }, - requestType: { - type: String, - enum: Object.values(Constants.REQUEST_TYPES) - } - } - ] -}); - -RoleSchema.methods.toJSON = function() { - const ps = this.toObject(); - delete ps.__v; - ps.id = ps._id; - delete ps._id; - return ps; -}; -//export the model -module.exports = mongoose.model("Role", RoleSchema); diff --git a/models/role.model.ts b/models/role.model.ts new file mode 100644 index 00000000..cc8346fb --- /dev/null +++ b/models/role.model.ts @@ -0,0 +1,33 @@ +import { Entity, BaseEntity, Column, PrimaryGeneratedColumn } from "typeorm"; +const Constants = require("../constants/general.constant"); + +export interface RouteSchema { + uri: string; + requestType: string; + // TODO: Above type is a enum: Object.values(Constants.REQUEST_TYPES)} +} + +/** + * The name is descriptive of the role + * Each role may have different routes, where route parameters in the uri are replaced with :self or :all + */ +@Entity() +class Role extends BaseEntity { + @PrimaryGeneratedColumn() + identifier: number; + + // The name should be something like "hacker", or "sponsor". + // For roles with singular routes, the name of the role will be the name of the route plus the api route + // For example, "getSelfAccount" + @Column({ unique: true, nullable: false }) + name: string; + + @Column("jsonb", { nullable: false }) + routes: RouteSchema[]; + + toJSON() { + return this; + } +} + +export default Role; diff --git a/models/roleBinding.model.js b/models/roleBinding.model.js deleted file mode 100644 index e00cc035..00000000 --- a/models/roleBinding.model.js +++ /dev/null @@ -1,30 +0,0 @@ -"use strict"; -const mongoose = require("mongoose"); -//describes the data type -const roleBinding = new mongoose.Schema({ - accountId: { - type: mongoose.Schema.Types.ObjectId, - ref: "Account", - required: true, - unique: true - }, - roles: { - type: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: "Role", - required: true - } - ] - } -}); - -roleBinding.methods.toJSON = function() { - const ps = this.toObject(); - delete ps.__v; - ps.id = ps._id; - delete ps._id; - return ps; -}; -//export the model -module.exports = mongoose.model("RoleBinding", roleBinding); diff --git a/models/roleBinding.model.ts b/models/roleBinding.model.ts new file mode 100644 index 00000000..abcf685e --- /dev/null +++ b/models/roleBinding.model.ts @@ -0,0 +1,33 @@ +import { + Entity, + BaseEntity, + OneToOne, + ManyToOne, + JoinColumn, + Column, + PrimaryGeneratedColumn +} from "typeorm"; +import Account from "./account.model"; +import Role from "./role.model"; + +@Entity() +class RoleBinding extends BaseEntity { + @PrimaryGeneratedColumn() + identifier: number; + + @OneToOne(() => Account) + @JoinColumn() + //@Column({ nullable: false, unique: true }) + account: Account; + + //TODO: This might be broken. (OneToMany?) + @ManyToOne(() => Role) + @JoinColumn() + roles: Role[]; + + toJSON() { + return this; + } +} + +export default RoleBinding; diff --git a/models/settings.model.js b/models/settings.model.js deleted file mode 100644 index ab704535..00000000 --- a/models/settings.model.js +++ /dev/null @@ -1,31 +0,0 @@ -"use strict"; -const mongoose = require("mongoose"); -//describes the data type -const settings = new mongoose.Schema({ - openTime: { - type: Date, - default: Date.now() + 2628000000 // One month from now. - }, - closeTime: { - type: Date, - default: Date.now() + 31540000000 + 2628000000 // One year and 1 month from now. - }, - confirmTime: { - type: Date, - default: Date.now() + 31540000000 + 2628000000 + 2628000000 // 1 year and 2 months from now. - }, - isRemote: { - type: Boolean, - default: false - } -}); - -settings.methods.toJSON = function() { - const ss = this.toObject(); - delete ss.__v; - ss.id = ss._id; - delete ss._id; - return ss; -}; -//export the model -module.exports = mongoose.model("Settings", settings); diff --git a/models/settings.model.ts b/models/settings.model.ts new file mode 100644 index 00000000..48d27611 --- /dev/null +++ b/models/settings.model.ts @@ -0,0 +1,25 @@ +import { Entity, BaseEntity, Column, PrimaryGeneratedColumn } from "typeorm"; + +@Entity() +class Settings extends BaseEntity { + @PrimaryGeneratedColumn() + identifier: number; + + @Column() // One month from now. + openTime: Date; + + @Column() // One year and 1 month from now. + closeTime: Date; + + @Column() // 1 year and 2 months from now. + confirmTime: Date; + + @Column({ default: false }) + isRemote: boolean; + + toJSON() { + return this; + } +} + +export default Settings; diff --git a/models/sponsor.model.js b/models/sponsor.model.js deleted file mode 100644 index 230ffe82..00000000 --- a/models/sponsor.model.js +++ /dev/null @@ -1,42 +0,0 @@ -"use strict"; -const mongoose = require("mongoose"); -//describes the data type -const SponsorSchema = new mongoose.Schema({ - accountId: { - type: mongoose.Schema.Types.ObjectId, - ref: "Account", - required: true - }, - //What tier of sponsor are they? - tier: { - type: Number, - min: 0, - default: 0 - }, - company: { - type: String, - required: true - }, - //URL to the contract between hackathon and sponsor - contractURL: { - type: String, - required: true - }, - //which hackers did the sponsor flag to see again? - nominees: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: "Hacker" - } - ] -}); - -SponsorSchema.methods.toJSON = function() { - const ss = this.toObject(); - delete ss.__v; - ss.id = ss._id; - delete ss._id; - return ss; -}; -//export the model -module.exports = mongoose.model("Sponsor", SponsorSchema); diff --git a/models/sponsor.model.ts b/models/sponsor.model.ts new file mode 100644 index 00000000..c2105805 --- /dev/null +++ b/models/sponsor.model.ts @@ -0,0 +1,21 @@ +import Account from "./account.model"; +import { Entity, Column, ManyToMany, JoinTable } from "typeorm"; +import Hacker from "./hacker.model"; + +@Entity() +class Sponsor extends Account { + @Column({ default: 0 }) + tier: number; + + @Column({ nullable: false }) + company: string; + + @Column({ nullable: false }) + contract: string; + + @ManyToMany(() => Hacker) + @JoinTable() + nominees: Hacker[]; +} + +export default Sponsor; diff --git a/models/staff.model.js b/models/staff.model.js deleted file mode 100644 index 9a7d22f8..00000000 --- a/models/staff.model.js +++ /dev/null @@ -1,20 +0,0 @@ -"use strict"; -const mongoose = require("mongoose"); -//describes the data type -const StaffSchema = new mongoose.Schema({ - accountId: { - type: mongoose.Schema.Types.ObjectId, - ref: "Account", - required: true - } -}); - -StaffSchema.methods.toJSON = function() { - const ss = this.toObject(); - delete ss.__v; - ss.id = ss._id; - delete ss._id; - return ss; -}; -//export the model -module.exports = mongoose.model("Staff", StaffSchema); diff --git a/models/staff.model.ts b/models/staff.model.ts new file mode 100644 index 00000000..a54c6904 --- /dev/null +++ b/models/staff.model.ts @@ -0,0 +1,7 @@ +import Account from "./account.model"; +import { Entity } from "typeorm"; + +@Entity() +class Staff extends Account {} + +export default Staff; diff --git a/models/team.model.js b/models/team.model.js deleted file mode 100644 index 7e339f6a..00000000 --- a/models/team.model.js +++ /dev/null @@ -1,40 +0,0 @@ -"use strict"; -const mongoose = require("mongoose"); -const Constants = require("../constants/general.constant"); - -//describes the data type -const TeamSchema = new mongoose.Schema({ - name: { - type: String, - required: true, - unique: true - }, - members: { - type: [ - { - type: mongoose.Schema.Types.ObjectId, - ref: "Hacker" - } - ], - validate: [validateTeamSize, "{PATH} exceeds the limit"] - }, - devpostURL: { - type: String, - default: undefined - }, - projectName: String -}); - -function validateTeamSize(membersArr) { - return membersArr.length <= Constants.MAX_TEAM_SIZE; -} - -TeamSchema.methods.toJSON = function() { - const ts = this.toObject(); - delete ts.__v; - ts.id = ts._id; - delete ts._id; - return ts; -}; -//export the model -module.exports = mongoose.model("Team", TeamSchema); diff --git a/models/team.model.ts b/models/team.model.ts new file mode 100644 index 00000000..153e7fa3 --- /dev/null +++ b/models/team.model.ts @@ -0,0 +1,37 @@ +import { + Entity, + BaseEntity, + Column, + OneToMany, + PrimaryGeneratedColumn +} from "typeorm"; +import * as Constants from "../constants/general.constant"; +import Hacker from "./hacker.model"; + +@Entity() +class Team extends BaseEntity { + @PrimaryGeneratedColumn() + identifier: number; + + @Column({ nullable: false, unique: true }) + name: string; + + //TODO: Implement max team size. + @OneToMany( + () => Hacker, + (hacker) => hacker.team + ) + hackers: Hacker[]; + + @Column({ default: undefined }) + submission: string; + + @Column() + project: string; + + toJSON() { + return this; + } +} + +export default Team; diff --git a/models/travel.model.js b/models/travel.model.js deleted file mode 100644 index 8e7999e4..00000000 --- a/models/travel.model.js +++ /dev/null @@ -1,41 +0,0 @@ -"use strict"; -const Constants = require("../constants/general.constant"); -const mongoose = require("mongoose"); -//describes the data type -const TravelSchema = new mongoose.Schema({ - accountId: { // The account this travel data is associated with - type: mongoose.Schema.Types.ObjectId, - ref: "Account", - required: true - }, - hackerId: { // The hacker this travel data is associated with - type: mongoose.Schema.Types.ObjectId, - ref: "Hacker", - required: true - }, - status: { // Has this hacker been approved for funds, etc. - type: String, - enum: Constants.TRAVEL_STATUSES, - required: true, - default: "None" - }, - request: { // Amount of money hacker has requested for travel - type: Number, - required: true - }, - offer: { // Amount of money we have offered hacker for travel - type: Number, - default: 0 - } -}); - -TravelSchema.methods.toJSON = function () { - const hs = this.toObject(); - delete hs.__v; - hs.id = hs._id; - delete hs._id; - return hs; -}; - -//export the model -module.exports = mongoose.model("Travel", TravelSchema); diff --git a/models/travel.model.ts b/models/travel.model.ts new file mode 100644 index 00000000..a6ad523d --- /dev/null +++ b/models/travel.model.ts @@ -0,0 +1,39 @@ +import * as Constants from "../constants/general.constant"; +import { + Entity, + BaseEntity, + OneToOne, + JoinColumn, + Column, + PrimaryGeneratedColumn +} from "typeorm"; +import Hacker from "./hacker.model"; + +@Entity() +class Travel extends BaseEntity { + @PrimaryGeneratedColumn() + identifier: number; + + @OneToOne(() => Hacker) + @JoinColumn() + hacker: Hacker; + + @Column({ + enum: Constants.TRAVEL_STATUSES, + nullable: false, + default: "None" + }) + status: String; + + @Column({ nullable: false }) + request: number; + + @Column({ default: 0 }) + offer: number; + + toJSON() { + return this; + } +} + +export default Travel; diff --git a/models/volunteer.model.js b/models/volunteer.model.js deleted file mode 100644 index 6d52d9b9..00000000 --- a/models/volunteer.model.js +++ /dev/null @@ -1,20 +0,0 @@ -"use strict"; -const mongoose = require("mongoose"); -//describes the data type -const VolunteerSchema = new mongoose.Schema({ - accountId: { - type: mongoose.Schema.Types.ObjectId, - ref: "Account", - required: true - } -}); - -VolunteerSchema.methods.toJSON = function() { - const vs = this.toObject(); - delete vs.__v; - vs.id = vs._id; - delete vs._id; - return vs; -}; -//export the model -module.exports = mongoose.model("Volunteer", VolunteerSchema); diff --git a/models/volunteer.model.ts b/models/volunteer.model.ts new file mode 100644 index 00000000..d6016b8c --- /dev/null +++ b/models/volunteer.model.ts @@ -0,0 +1,7 @@ +import Account from "./account.model"; +import { Entity } from "typeorm"; + +@Entity() +class Volunteer extends Account {} + +export default Volunteer; diff --git a/package-lock.json b/package-lock.json index d11c5f3d..e71e9b77 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5725 +1,12752 @@ { - "name": "hackerAPI", - "version": "3.1.3", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", - "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", - "dev": true - }, - "@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } + "name": "hackerAPI", + "version": "3.1.3", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "hackerAPI", + "version": "3.1.3", + "dependencies": { + "@google-cloud/storage": "^5.10.0", + "@sendgrid/mail": "^7.4.5", + "bcrypt": "^5.0.1", + "class-validator": "^0.13.2", + "cookie-parser": "^1.4.5", + "cookie-session": "^2.0.0-rc.1", + "cors": "^2.8.5", + "cryptiles": "^4.1.3", + "debug": "~4.3.2", + "dotenv": "^10.0.0", + "express": "~4.17.1", + "express-validator": "^6.12.0", + "express-winston": "^4.2.0", + "handlebars": "^4.7.7", + "jsonwebtoken": "^8.5.1", + "memory-cache": "^0.2.0", + "mongoose": "^5.13.3", + "multer": "^1.4.2", + "passport": "^0.4.1", + "passport-local": "^1.0.0", + "pg": "^8.7.1", + "promise.allsettled": "^1.0.4", + "q": "^1.5.1", + "qrcode": "^1.4.4", + "reflect-metadata": "^0.1.13", + "typeorm": "^0.2.41", + "typescript": "^4.5.2", + "winston": "^3.3.3" + }, + "devDependencies": { + "@types/bcrypt": "^5.0.0", + "@types/express": "^4.17.13", + "@types/express-winston": "^4.0.0", + "@types/google-cloud__storage": "^1.7.2", + "@types/mongodb": "^3.6.20", + "@types/mongoose": "^5.11.97", + "@types/multer": "^1.4.7", + "@types/passport": "^1.0.7", + "@types/passport-local": "^1.0.34", + "@types/superagent": "^4.1.13", + "@types/validator": "^13.7.0", + "apidoc": "^0.28.1", + "chai": "^4.3.4", + "chai-http": "^4.3.0", + "eslint": "7.31.0", + "eslint-config-prettier": "8.3.0", + "eslint-plugin-prettier": "3.4.0", + "mocha": "^9.0.3", + "nodemon": "^2.0.12", + "prettier": "1.19.1", + "rimraf": "^3.0.2", + "ts-node": "^10.4.0" + } }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } + "node_modules/@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - } - } - }, - "@dabh/diagnostics": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", - "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==", - "dev": true, - "requires": { - "colorspace": "1.1.x", - "enabled": "2.0.x", - "kuler": "^2.0.0" - } - }, - "@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "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 - } - } - }, - "@google-cloud/common": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-3.7.0.tgz", - "integrity": "sha512-oFgpKLjH9JTOAyQd3kB36iSuH8wNSpDKb1TywlB6zcsG0xmJFxLutmfPhz03KUxRMNQOZ1K1Gc9BYvJifVnGVA==", - "requires": { - "@google-cloud/projectify": "^2.0.0", - "@google-cloud/promisify": "^2.0.0", - "arrify": "^2.0.1", - "duplexify": "^4.1.1", - "ent": "^2.2.0", - "extend": "^3.0.2", - "google-auth-library": "^7.0.2", - "retry-request": "^4.2.2", - "teeny-request": "^7.0.0" - } - }, - "@google-cloud/paginator": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-3.0.5.tgz", - "integrity": "sha512-N4Uk4BT1YuskfRhKXBs0n9Lg2YTROZc6IMpkO/8DIHODtm5s3xY8K5vVBo23v/2XulY3azwITQlYWgT4GdLsUw==", - "requires": { - "arrify": "^2.0.0", - "extend": "^3.0.2" - } - }, - "@google-cloud/projectify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-2.1.0.tgz", - "integrity": "sha512-qbpidP/fOvQNz3nyabaVnZqcED1NNzf7qfeOlgtAZd9knTwY+KtsGRkYpiQzcATABy4gnGP2lousM3S0nuWVzA==" - }, - "@google-cloud/promisify": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-2.0.3.tgz", - "integrity": "sha512-d4VSA86eL/AFTe5xtyZX+ePUjE8dIFu2T8zmdeNBSa5/kNgXPCx/o/wbFNHAGLJdGnk1vddRuMESD9HbOC8irw==" - }, - "@google-cloud/storage": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-5.10.0.tgz", - "integrity": "sha512-E0PXhN+8CiiOfrQuITyjALHMsGQFQmhhtHpzz0k/kgnFgM27ldSnLn1JADrWvIlfy8BTkR7u3GQCOtQCLPrVnw==", - "requires": { - "@google-cloud/common": "^3.7.0", - "@google-cloud/paginator": "^3.0.0", - "@google-cloud/promisify": "^2.0.0", - "arrify": "^2.0.0", - "async-retry": "^1.3.1", - "compressible": "^2.0.12", - "date-and-time": "^1.0.0", - "duplexify": "^4.0.0", - "extend": "^3.0.2", - "gcs-resumable-upload": "^3.3.0", - "get-stream": "^6.0.0", - "hash-stream-validation": "^0.2.2", - "mime": "^2.2.0", - "mime-types": "^2.0.8", - "onetime": "^5.1.0", - "p-limit": "^3.0.1", - "pumpify": "^2.0.0", - "snakeize": "^0.1.0", - "stream-events": "^1.0.1", - "xdg-basedir": "^4.0.0" - }, - "dependencies": { - "mime": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", - "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==" + "node_modules/@babel/helper-validator-identifier": { + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "requires": { - "yocto-queue": "^0.1.0" - } - } - } - }, - "@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - } - }, - "@humanwhocodes/object-schema": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", - "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", - "dev": true - }, - "@mapbox/node-pre-gyp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.5.tgz", - "integrity": "sha512-4srsKPXWlIxp5Vbqz5uLfBN+du2fJChBoYn/f2h991WLdk7jUvcSk/McVLSv/X+xQIPI8eGD5GjrnygdyHnhPA==", - "requires": { - "detect-libc": "^1.0.3", - "https-proxy-agent": "^5.0.0", - "make-dir": "^3.1.0", - "node-fetch": "^2.6.1", - "nopt": "^5.0.0", - "npmlog": "^4.1.2", - "rimraf": "^3.0.2", - "semver": "^7.3.4", - "tar": "^6.1.0" - }, - "dependencies": { - "glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } + "node_modules/@babel/highlight": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.0.tgz", + "integrity": "sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.15.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "requires": { - "glob": "^7.1.3" - } + "node_modules/@babel/highlight/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==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "@sendgrid/client": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/@sendgrid/client/-/client-7.4.3.tgz", - "integrity": "sha512-tTaHx893w5iqG0sVtUnMyRchuwYF95k4UOkmov1MouMIeMUbNvbalITo7cG7YSXUTY9rT2t4eBY6HcEBCVeqfg==", - "requires": { - "@sendgrid/helpers": "^7.4.3", - "axios": "^0.21.1" - } - }, - "@sendgrid/helpers": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/@sendgrid/helpers/-/helpers-7.4.3.tgz", - "integrity": "sha512-Wt+68g1sVEM5UspJh34O/cxtv6BBbtAIk7U9B3PB2ySOtPs9e6hI1QkgYVwpNmkt7k2p86muUNyma/Aig25agg==", - "requires": { - "deepmerge": "^4.2.2" - } - }, - "@sendgrid/mail": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@sendgrid/mail/-/mail-7.4.5.tgz", - "integrity": "sha512-adXMvrTUOlYr7+UTigZRGSYR9vheBv1y4fF2mugn29NBdQMfcQPGLQ5vIHgSAfcboBFCagZdamZqM5FeSGU0Hw==", - "requires": { - "@sendgrid/client": "^7.4.3", - "@sendgrid/helpers": "^7.4.3" - } - }, - "@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", - "dev": true - }, - "@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "dev": true, - "requires": { - "defer-to-connect": "^1.0.1" - } - }, - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" - }, - "@types/body-parser": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.1.tgz", - "integrity": "sha512-a6bTJ21vFOGIkwM0kzh9Yr89ziVxq4vYH2fQ6N8AeipEzai/cFK6aGMArIkUeIdRIgpwQa+2bXiLuUJCpSf2Cg==", - "dev": true, - "requires": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "@types/bson": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.4.tgz", - "integrity": "sha512-awqorHvQS0DqxkHQ/FxcPX9E+H7Du51Qw/2F+5TBMSaE3G0hm+8D3eXJ6MAzFw75nE8V7xF0QvzUSdxIjJb/GA==", - "requires": { - "@types/node": "*" - } - }, - "@types/caseless": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.1.tgz", - "integrity": "sha512-FhlMa34NHp9K5MY1Uz8yb+ZvuX0pnvn3jScRSNAb75KHGB8d3rEU6hqMs3Z2vjuytcMfRg6c5CHMc3wtYyD2/A==", - "dev": true - }, - "@types/chai": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.7.tgz", - "integrity": "sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA==", - "dev": true - }, - "@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/cookiejar": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.1.tgz", - "integrity": "sha512-aRnpPa7ysx3aNW60hTiCtLHlQaIFsXFCgQlpakNgDNVFzbtusSY8PwjAQgRWfSk0ekNoBjO51eQRB6upA9uuyw==", - "dev": true - }, - "@types/express": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", - "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", - "dev": true, - "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "@types/express-serve-static-core": { - "version": "4.17.24", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz", - "integrity": "sha512-3UJuW+Qxhzwjq3xhwXm2onQcFHn76frIYVbTu+kn24LFxI+dEhdfISDFovPB8VpEgW8oQCTpRuCe+0zJxB7NEA==", - "dev": true, - "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "@types/form-data": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-2.2.1.tgz", - "integrity": "sha512-JAMFhOaHIciYVh8fb5/83nmuO/AHwmto+Hq7a9y8FzLDcC1KCU344XDOMEmahnrTFlHjgh4L0WJFczNIX2GxnQ==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/google-cloud__storage": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@types/google-cloud__storage/-/google-cloud__storage-1.7.2.tgz", - "integrity": "sha512-RaQJ7+Ht20MRYJu7mgKBpbVNZIPneztKIl/DUKacRC6A8mXRsJfgDdPA7indHmJGIgm+hzUTj44+A3RyuuYZhg==", - "dev": true, - "requires": { - "@types/node": "*", - "@types/request": "*" - } - }, - "@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", - "dev": true - }, - "@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/mongoose": { - "version": "5.11.97", - "resolved": "https://registry.npmjs.org/@types/mongoose/-/mongoose-5.11.97.tgz", - "integrity": "sha512-cqwOVYT3qXyLiGw7ueU2kX9noE8DPGRY6z8eUxudhXY8NZ7DMKYAxyZkLSevGfhCX3dO/AoX5/SO9lAzfjon0Q==", - "dev": true, - "requires": { - "mongoose": "*" - } - }, - "@types/multer": { - "version": "1.4.7", - "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.7.tgz", - "integrity": "sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA==", - "dev": true, - "requires": { - "@types/express": "*" - } - }, - "@types/node": { - "version": "8.10.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.10.tgz", - "integrity": "sha512-p3W/hFzQs76RlYRIZsZc5a9bht6m0TspmWYYbKhRswmLnwj9fsE40EbuGifeu/XWR/c0UJQ1DDbvTxIsm/OOAA==" - }, - "@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", - "dev": true - }, - "@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", - "dev": true - }, - "@types/request": { - "version": "2.47.1", - "resolved": "https://registry.npmjs.org/@types/request/-/request-2.47.1.tgz", - "integrity": "sha512-TV3XLvDjQbIeVxJ1Z3oCTDk/KuYwwcNKVwz2YaT0F5u86Prgc4syDAp6P96rkTQQ4bIdh+VswQIC9zS6NjY7/g==", - "dev": true, - "requires": { - "@types/caseless": "*", - "@types/form-data": "*", - "@types/node": "*", - "@types/tough-cookie": "*" - } - }, - "@types/serve-static": { - "version": "1.13.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", - "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", - "dev": true, - "requires": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "@types/superagent": { - "version": "3.8.7", - "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-3.8.7.tgz", - "integrity": "sha512-9KhCkyXv268A2nZ1Wvu7rQWM+BmdYUVkycFeNnYrUL5Zwu7o8wPQ3wBfW59dDP+wuoxw0ww8YKgTNv8j/cgscA==", - "dev": true, - "requires": { - "@types/cookiejar": "*", - "@types/node": "*" - } - }, - "@types/tough-cookie": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.3.tgz", - "integrity": "sha512-MDQLxNFRLasqS4UlkWMSACMKeSm1x4Q3TxzUC7KQUsh6RK1ZrQ0VEyE3yzXcBu+K8ejVj4wuX32eUG02yNp+YQ==", - "dev": true - }, - "@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "dev": true - }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, - "abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "requires": { - "event-target-shim": "^5.0.0" - } - }, - "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - }, - "dependencies": { - "mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" + "node_modules/@babel/highlight/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==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } }, - "mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", - "requires": { - "mime-db": "1.40.0" - } - } - } - }, - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "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 - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "requires": { - "debug": "4" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "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-align": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", - "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", - "dev": true, - "requires": { - "string-width": "^3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true + "node_modules/@babel/highlight/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==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/@babel/highlight/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": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", - "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=" - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "apidoc": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/apidoc/-/apidoc-0.28.1.tgz", - "integrity": "sha512-vJbRtNnxWqUUfbY4NJwq9vRB8+Fh43nccckhG9nC4nQBxrMDaBYHhwMbls3OZ9Nv36jWN4KexpLrZ5Ivph8GYg==", - "dev": true, - "requires": { - "apidoc-core": "^0.15.0", - "commander": "^2.20.0", - "fs-extra": "^9.0.1", - "handlebars": "^4.7.7", - "lodash": "^4.17.20", - "markdown-it": "^11.0.0", - "nodemon": "^2.0.4", - "winston": "^3.3.3" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } + "node_modules/@babel/highlight/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==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } }, - "winston": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", - "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==", - "dev": true, - "requires": { - "@dabh/diagnostics": "^2.0.2", - "async": "^3.1.0", - "is-stream": "^2.0.0", - "logform": "^2.2.0", - "one-time": "^1.0.0", - "readable-stream": "^3.4.0", - "stack-trace": "0.0.x", - "triple-beam": "^1.3.0", - "winston-transport": "^4.4.0" - } - } - } - }, - "apidoc-core": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/apidoc-core/-/apidoc-core-0.15.0.tgz", - "integrity": "sha512-CJNjRs6R8nc774vUtbv9Uakos5/JbEFpBXgE6oiWUX7OpjI1s04xPuULEoQQJyQM427r5hr55GSHAm5/LRc5TQ==", - "dev": true, - "requires": { - "fs-extra": "^9.0.1", - "glob": "^7.1.6", - "iconv-lite": "^0.6.2", - "klaw-sync": "^6.0.0", - "lodash": "^4.17.20", - "semver": "~7.3.2" - }, - "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "append-field": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", - "integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=" - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" - }, - "are-we-there-yet": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "array.prototype.map": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.3.tgz", - "integrity": "sha512-nNcb30v0wfDyIe26Yif3PcV1JXQp4zEeEfupG7L4SRjnD6HLbO5b2a7eVSba53bOx4YCHYMBHt+Fp4vYstneRA==", - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "es-array-method-boxes-properly": "^1.0.0", - "is-string": "^1.0.5" - }, - "dependencies": { - "es-abstract": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", - "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.10.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - } + "node_modules/@cspotcode/source-map-consumer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", + "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", + "dev": true, + "engines": { + "node": ">= 12" + } }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + "node_modules/@cspotcode/source-map-support": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", + "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-consumer": "0.8.0" + }, + "engines": { + "node": ">=12" + } }, - "is-callable": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==" + "node_modules/@dabh/diagnostics": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", + "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } }, - "is-regex": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", - "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", - "requires": { - "call-bind": "^1.0.2", - "has-symbols": "^1.0.2" - } + "node_modules/@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } }, - "object-inspect": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", - "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==" + "node_modules/@google-cloud/common": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-3.8.1.tgz", + "integrity": "sha512-FOs3NFU6bDt5mXE7IFpwIeqzLwRZNu9lJYl+bHVNkwmxX/w4VyDZAiGjQHhpV1Ek+muNKlX8HPchxaIxNTuOhw==", + "dependencies": { + "@google-cloud/projectify": "^2.0.0", + "@google-cloud/promisify": "^2.0.0", + "arrify": "^2.0.1", + "duplexify": "^4.1.1", + "ent": "^2.2.0", + "extend": "^3.0.2", + "google-auth-library": "^7.9.2", + "retry-request": "^4.2.2", + "teeny-request": "^7.0.0" + }, + "engines": { + "node": ">=10" + } }, - "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - } + "node_modules/@google-cloud/paginator": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-3.0.6.tgz", + "integrity": "sha512-XCTm/GfQIlc1ZxpNtTSs/mnZxC2cePNhxU3X8EzHXKIJ2JFncmJj2Fcd2IP+gbmZaSZnY0juFxbUCkIeuu/2eQ==", + "dependencies": { + "arrify": "^2.0.0", + "extend": "^3.0.2" + }, + "engines": { + "node": ">=10" + } }, - "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } + "node_modules/@google-cloud/projectify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-2.1.1.tgz", + "integrity": "sha512-+rssMZHnlh0twl122gXY4/aCrk0G1acBqkHFfYddtsqpYXGxA29nj9V5V9SfC+GyOG00l650f6lG9KL+EpFEWQ==", + "engines": { + "node": ">=10" + } }, - "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - } - } - }, - "arrify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" - }, - "assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true - }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true - }, - "async": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", - "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==", - "dev": true - }, - "async-retry": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.1.tgz", - "integrity": "sha512-aiieFW/7h3hY0Bq5d+ktDBejxuwR78vRu9hDUdR8rNhSaQ29VzPL4AoIRG7D/c7tdenwOcKvgPM6tIxB3cB6HA==", - "requires": { - "retry": "0.12.0" - } - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true - }, - "axios": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", - "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", - "requires": { - "follow-redirects": "^1.10.0" - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "base64-js": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" - }, - "bcrypt": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.0.1.tgz", - "integrity": "sha512-9BTgmrhZM2t1bNuDtrtIMVSmmxZBrJ71n8Wg+YgdjHuIWYF7SjjmCPZFB+/5i/o/PIeRpwVJR3P+NrpIItUjqw==", - "requires": { - "@mapbox/node-pre-gyp": "^1.0.0", - "node-addon-api": "^3.1.0" - } - }, - "bignumber.js": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", - "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==" - }, - "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 - }, - "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==" - }, - "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", - "requires": { - "bytes": "3.1.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" - }, - "dependencies": { - "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" - } + "node_modules/@google-cloud/promisify": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-2.0.4.tgz", + "integrity": "sha512-j8yRSSqswWi1QqUGKVEKOG03Q7qOoZP6/h2zN2YO+F5h2+DHU0bSrHCK9Y7lo2DI9fBd8qGAw795sf+3Jva4yA==", + "engines": { + "node": ">=10" + } }, - "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" - } + "node_modules/@google-cloud/storage": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-5.16.0.tgz", + "integrity": "sha512-I/1lA78v9c5EbOM/KfcYsjzA7YlHQmhpzHYdKLKdYC8X5fFaQrw5nK+FU8GbEwdPxmREAF2qPbN7Ccq+A/ndWA==", + "dependencies": { + "@google-cloud/common": "^3.8.1", + "@google-cloud/paginator": "^3.0.0", + "@google-cloud/promisify": "^2.0.0", + "arrify": "^2.0.0", + "async-retry": "^1.3.1", + "compressible": "^2.0.12", + "date-and-time": "^2.0.0", + "duplexify": "^4.0.0", + "extend": "^3.0.2", + "gcs-resumable-upload": "^3.5.1", + "get-stream": "^6.0.0", + "hash-stream-validation": "^0.2.2", + "mime": "^3.0.0", + "mime-types": "^2.0.8", + "p-limit": "^3.0.1", + "pumpify": "^2.0.0", + "snakeize": "^0.1.0", + "stream-events": "^1.0.1", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=10" + } }, - "mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" + "node_modules/@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } }, - "mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", - "requires": { - "mime-db": "1.40.0" - } + "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/@mapbox/node-pre-gyp": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.7.tgz", + "integrity": "sha512-PplSvl4pJ5N3BkVjAdDzpPhVUPdC73JgttkR+LnBx2OORC1GCQsBjUeEuipf9uOaAM1SbxcdZFfR3KDTKm2S0A==", + "dependencies": { + "detect-libc": "^1.0.3", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.5", + "nopt": "^5.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } }, - "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + "node_modules/@sendgrid/client": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@sendgrid/client/-/client-7.6.0.tgz", + "integrity": "sha512-cpBVZKLlMTO+vpE18krTixubYmZa98oTbLkqBDuTiA3zRkW+urrxg7pDR24TkI35Mid0Zru8jDHwnOiqrXu0TA==", + "dependencies": { + "@sendgrid/helpers": "^7.6.0", + "axios": "^0.21.4" + }, + "engines": { + "node": "6.* || 8.* || >=10.*" + } }, - "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" - } - } - } - }, - "boxen": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", - "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", - "dev": true, - "requires": { - "ansi-align": "^3.0.0", - "camelcase": "^5.3.1", - "chalk": "^3.0.0", - "cli-boxes": "^2.2.0", - "string-width": "^4.1.0", - "term-size": "^2.1.0", - "type-fest": "^0.8.1", - "widest-line": "^3.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true + "node_modules/@sendgrid/helpers": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@sendgrid/helpers/-/helpers-7.6.0.tgz", + "integrity": "sha512-0uWD+HSXLl4Z/X3cN+UMQC20RE7xwAACgppnfjDyvKG0KvJcUgDGz7HDdQkiMUdcVWfmyk6zKSg7XKfKzBjTwA==", + "dependencies": { + "deepmerge": "^4.2.2" + }, + "engines": { + "node": ">= 6.0.0" + } }, - "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" - } + "node_modules/@sendgrid/mail": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@sendgrid/mail/-/mail-7.6.0.tgz", + "integrity": "sha512-0KdaSZzflJD/vUAZjB3ALBIuaVGoLq22hrb2fvQXZHRepU/yhRNlEOqrr05MfKBnKskzq1blnD1J0fHxiwaolw==", + "dependencies": { + "@sendgrid/client": "^7.6.0", + "@sendgrid/helpers": "^7.6.0" + }, + "engines": { + "node": "6.* || 8.* || >=10.*" + } }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } + "node_modules/@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true, + "engines": { + "node": ">=6" + } }, - "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" - } + "node_modules/@sqltools/formatter": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.3.tgz", + "integrity": "sha512-O3uyB/JbkAEMZaP3YqyHH7TMnex7tWyCbCI4EfJdOCoN6HIhqdJBWTM6aCCiWQ/5f5wxjgU735QAIpJbjDvmzg==" + }, + "node_modules/@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "dependencies": { + "defer-to-connect": "^1.0.1" + }, + "engines": { + "node": ">=6" + } }, - "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/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "engines": { + "node": ">= 10" + } }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "node_modules/@tsconfig/node10": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", + "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", + "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", + "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", + "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", + "dev": true + }, + "node_modules/@types/bcrypt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.0.tgz", + "integrity": "sha512-agtcFKaruL8TmcvqbndlqHPSJgsolhf/qPWchFlgnW1gECTN/nKbFcoFnvKAQRFfKbh+BO6A3SWdJu9t+xF3Lw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } }, - "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 + "node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true + "node_modules/@types/bson": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.2.0.tgz", + "integrity": "sha512-ELCPqAdroMdcuxqwMgUpifQyRoTpyYCNr1V9xKyF40VsBobsj+BbWNRvwGchMgBPGqkw655ypkjj2MEF5ywVwg==", + "deprecated": "This is a stub types definition. bson provides its own type definitions, so you do not need this installed.", + "dependencies": { + "bson": "*" + } }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } + "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==", + "dev": true + }, + "node_modules/@types/chai": { + "version": "4.2.22", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.22.tgz", + "integrity": "sha512-tFfcE+DSTzWAgifkjik9AySNqIyNoYwmR+uecPwwD/XRNfvOjmC/FjCxpiUGDkDVDphPfCUecSQVFw+lN3M3kQ==", + "dev": true + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } + "node_modules/@types/cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } }, - "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" - } - } - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "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" - } - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "bson": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", - "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==" - }, - "buffer": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz", - "integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, - "buffer-alloc": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", - "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", - "requires": { - "buffer-alloc-unsafe": "^1.1.0", - "buffer-fill": "^1.0.0" - } - }, - "buffer-alloc-unsafe": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" - }, - "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": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" - }, - "buffer-fill": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", - "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=" - }, - "buffer-from": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz", - "integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA==" - }, - "busboy": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", - "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", - "requires": { - "dicer": "0.2.5", - "readable-stream": "1.1.x" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + "node_modules/@types/express-serve-static-core": { + "version": "4.17.25", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.25.tgz", + "integrity": "sha512-OUJIVfRMFijZukGGwTpKNFprqCCXk5WjNGvUgB/CxxBR40QWSjsNK86+yvGKlCOGc7sbwfHLaXhkG+NsytwBaQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } + "node_modules/@types/express-winston": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/express-winston/-/express-winston-4.0.0.tgz", + "integrity": "sha512-CCNvkHIRKIJGgt64naW7XvsXvw4NkVHHa3EDy63uZzruXaFhZb2+AE0HRZx90ph528D1gm+fx9dA1gmZZ2uzLw==", + "deprecated": "This is a stub types definition. express-winston provides its own type definitions, so you do not need this installed.", + "dev": true, + "dependencies": { + "express-winston": "*" + } }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - } - } - }, - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" - }, - "cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "dev": true, - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "dependencies": { - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } + "node_modules/@types/google-cloud__storage": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@types/google-cloud__storage/-/google-cloud__storage-1.7.2.tgz", + "integrity": "sha512-RaQJ7+Ht20MRYJu7mgKBpbVNZIPneztKIl/DUKacRC6A8mXRsJfgDdPA7indHmJGIgm+hzUTj44+A3RyuuYZhg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/request": "*" + } }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true - } - } - }, - "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 - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "chai": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.4.tgz", - "integrity": "sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==", - "dev": true, - "requires": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^3.0.1", - "get-func-name": "^2.0.0", - "pathval": "^1.1.1", - "type-detect": "^4.0.5" - } - }, - "chai-http": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/chai-http/-/chai-http-4.3.0.tgz", - "integrity": "sha512-zFTxlN7HLMv+7+SPXZdkd5wUlK+KxH6Q7bIEMiEx0FK3zuuMqL7cwICAQ0V1+yYRozBburYuxN1qZstgHpFZQg==", - "dev": true, - "requires": { - "@types/chai": "4", - "@types/superagent": "^3.8.3", - "cookiejar": "^2.1.1", - "is-ip": "^2.0.0", - "methods": "^1.1.2", - "qs": "^6.5.1", - "superagent": "^3.7.0" - } - }, - "chalk": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", - "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", - "requires": { - "ansi-styles": "~1.0.0", - "has-color": "~0.1.0", - "strip-ansi": "~0.1.0" - }, - "dependencies": { - "strip-ansi": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", - "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=" - } - } - }, - "check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", - "dev": true - }, - "chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", - "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" - } - }, - "chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" - }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", - "dev": true - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true + "node_modules/@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "dev": true + }, + "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": "*" + } }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "node_modules/@types/mongoose": { + "version": "5.11.97", + "resolved": "https://registry.npmjs.org/@types/mongoose/-/mongoose-5.11.97.tgz", + "integrity": "sha512-cqwOVYT3qXyLiGw7ueU2kX9noE8DPGRY6z8eUxudhXY8NZ7DMKYAxyZkLSevGfhCX3dO/AoX5/SO9lAzfjon0Q==", + "deprecated": "Mongoose publishes its own types, so you do not need to install this package.", + "dev": true, + "dependencies": { + "mongoose": "*" + } }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true + "node_modules/@types/multer": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.7.tgz", + "integrity": "sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA==", + "dev": true, + "dependencies": { + "@types/express": "*" + } }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } + "node_modules/@types/node": { + "version": "16.11.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.10.tgz", + "integrity": "sha512-3aRnHa1KlOEEhJ6+CvyHKK5vE9BcLGjtUpwvqYLRvYNQKMfabu3BwfJaA/SLW8dxe28LsNDjtHwePTuzn3gmOA==" + }, + "node_modules/@types/passport": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.7.tgz", + "integrity": "sha512-JtswU8N3kxBYgo+n9of7C97YQBT+AYPP2aBfNGTzABqPAZnK/WOAaKfh3XesUYMZRrXFuoPc2Hv0/G/nQFveHw==", + "dev": true, + "dependencies": { + "@types/express": "*" + } }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } - } - }, - "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" - }, - "color": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", - "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", - "dev": true, - "requires": { - "color-convert": "^1.9.1", - "color-string": "^1.5.2" - } - }, - "color-convert": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", - "requires": { - "color-name": "^1.1.1" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "color-string": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.5.tgz", - "integrity": "sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg==", - "dev": true, - "requires": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=" - }, - "colorspace": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", - "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", - "dev": true, - "requires": { - "color": "3.0.x", - "text-hex": "1.0.x" - } - }, - "combined-stream": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", - "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", - "dev": true - }, - "compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "requires": { - "mime-db": ">= 1.43.0 < 2" - }, - "dependencies": { - "mime-db": { - "version": "1.48.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", - "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==" - } - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "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" - } - }, - "configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "requires": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - } - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" - }, - "content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", - "requires": { - "safe-buffer": "5.1.2" - }, - "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==" - } - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, - "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" - }, - "cookie-parser": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.5.tgz", - "integrity": "sha512-f13bPUj/gG/5mDr+xLmSxxDsB9DQiTIfhJS/sqjrmfAWiAN+x2O4i/XguTL9yDZ+/IFDanJ+5x7hC4CXT9Tdzw==", - "requires": { - "cookie": "0.4.0", - "cookie-signature": "1.0.6" - } - }, - "cookie-session": { - "version": "2.0.0-rc.1", - "resolved": "https://registry.npmjs.org/cookie-session/-/cookie-session-2.0.0-rc.1.tgz", - "integrity": "sha512-zg80EsLe7S1J4y0XxV7SZ8Fbi90ZZoampuX2bfYDOvJfc//98sSlZC41YDzTTjtVbeU1VlVdBbldXOOyi5xzEw==", - "requires": { - "cookies": "0.8.0", - "debug": "3.2.6", - "on-headers": "~1.0.2", - "safe-buffer": "5.2.0" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "requires": { - "ms": "^2.1.1" - } + "node_modules/@types/passport-local": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/@types/passport-local/-/passport-local-1.0.34.tgz", + "integrity": "sha512-PSc07UdYx+jhadySxxIYWuv6sAnY5e+gesn/5lkPKfBeGuIYn9OPR+AAEDq73VRUh6NBTpvE/iPE62rzZUslog==", + "dev": true, + "dependencies": { + "@types/express": "*", + "@types/passport": "*", + "@types/passport-strategy": "*" + } }, - "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/@types/passport-strategy": { + "version": "0.2.35", + "resolved": "https://registry.npmjs.org/@types/passport-strategy/-/passport-strategy-0.2.35.tgz", + "integrity": "sha512-o5D19Jy2XPFoX2rKApykY15et3Apgax00RRLf0RUotPDUsYrQa7x4howLYr9El2mlUApHmCMv5CZ1IXqKFQ2+g==", + "dev": true, + "dependencies": { + "@types/express": "*", + "@types/passport": "*" + } }, - "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" - } - } - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "cookiejar": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", - "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==", - "dev": true - }, - "cookies": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.8.0.tgz", - "integrity": "sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==", - "requires": { - "depd": "~2.0.0", - "keygrip": "~1.1.0" - }, - "dependencies": { - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - } - } - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "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" - } - }, - "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" - } - }, - "cryptiles": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-4.1.3.tgz", - "integrity": "sha512-gT9nyTMSUC1JnziQpPbxKGBbUg8VL7Zn2NB4E1cJYvuXdElHrwxrV9bmltZGDzet45zSDGyYceueke1TjynGzw==", - "requires": { - "boom": "7.x.x" - }, - "dependencies": { - "boom": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/boom/-/boom-7.2.2.tgz", - "integrity": "sha512-IFUbOa8PS7xqmhIjpeStwT3d09hGkNYQ6aj2iELSTxcVs2u0aKn1NzhkdUQSzsRg1FVkj3uit3I6mXQCBixw+A==", - "requires": { - "hoek": "6.x.x" - } + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "node_modules/@types/request": { + "version": "2.48.7", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.7.tgz", + "integrity": "sha512-GWP9AZW7foLd4YQxyFZDBepl0lPsWLMEXDZUjQ/c1gqVPDPECrRZyEzuhJdnPWioFCq3Tv0qoGpMD6U+ygd4ZA==", + "dev": true, + "dependencies": { + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" + } }, - "hoek": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.0.3.tgz", - "integrity": "sha512-TU6RyZ/XaQCTWRLrdqZZtZqwxUVr6PDMfi6MlWNURZ7A6czanQqX4pFE1mdOUQR9FdPCsZ0UzL8jI/izZ+eBSQ==" - } - } - }, - "crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" - }, - "cycle": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", - "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=" - }, - "date-and-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-1.0.1.tgz", - "integrity": "sha512-7u+uNfnjWkX+YFQfivvW24TjaJG6ahvTrfw1auq7KlC7osuGcZBIWGBvB9UcENjH6JnLVhMqlRripk1dSHjAUA==" - }, - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "requires": { - "ms": "2.1.2" - }, - "dependencies": { - "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/@types/serve-static": { + "version": "1.13.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", + "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/superagent": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-4.1.13.tgz", + "integrity": "sha512-YIGelp3ZyMiH0/A09PMAORO0EBGlF5xIKfDpK74wdYvWUs2o96b5CItJcWPdH409b7SAXIIG6p8NdU/4U2Maww==", + "dev": true, + "dependencies": { + "@types/cookiejar": "*", + "@types/node": "*" + } + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.1.tgz", + "integrity": "sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg==", + "dev": true + }, + "node_modules/@types/validator": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.0.tgz", + "integrity": "sha512-+jBxVvXVuggZOrm04NR8z+5+bgoW4VZyLzUO+hmPPW1mVFL/HaitLAkizfv4yg9TbG8lkfHWVMQ11yDqrVVCzA==", + "dev": true + }, + "node_modules/@types/zen-observable": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.3.tgz", + "integrity": "sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw==" + }, + "node_modules/@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "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==" + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dependencies": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "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/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.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==", + "dev": true, + "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-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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==", + "engines": { + "node": ">=8" + } + }, + "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==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/apidoc": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/apidoc/-/apidoc-0.28.1.tgz", + "integrity": "sha512-vJbRtNnxWqUUfbY4NJwq9vRB8+Fh43nccckhG9nC4nQBxrMDaBYHhwMbls3OZ9Nv36jWN4KexpLrZ5Ivph8GYg==", + "dev": true, + "dependencies": { + "apidoc-core": "^0.15.0", + "commander": "^2.20.0", + "fs-extra": "^9.0.1", + "handlebars": "^4.7.7", + "lodash": "^4.17.20", + "markdown-it": "^11.0.0", + "nodemon": "^2.0.4", + "winston": "^3.3.3" + }, + "bin": { + "apidoc": "bin/apidoc" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/apidoc-core": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/apidoc-core/-/apidoc-core-0.15.0.tgz", + "integrity": "sha512-CJNjRs6R8nc774vUtbv9Uakos5/JbEFpBXgE6oiWUX7OpjI1s04xPuULEoQQJyQM427r5hr55GSHAm5/LRc5TQ==", + "dev": true, + "dependencies": { + "fs-extra": "^9.0.1", + "glob": "^7.1.6", + "iconv-lite": "^0.6.2", + "klaw-sync": "^6.0.0", + "lodash": "^4.17.20", + "semver": "~7.3.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/app-root-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.0.0.tgz", + "integrity": "sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw==", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=" + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "node_modules/array.prototype.map": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.4.tgz", + "integrity": "sha512-Qds9QnX7A0qISY7JT5WuJO0NJPE9CMlC6JzHQfhpqAAQQzufVRoeH7EzUY5GcPTx72voG8LV/5eo+b8Qi8hmhA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "engines": { + "node": ">=8" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.2.tgz", + "integrity": "sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g==" + }, + "node_modules/async-retry": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", + "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", + "dependencies": { + "retry": "0.13.1" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/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": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.0.1.tgz", + "integrity": "sha512-9BTgmrhZM2t1bNuDtrtIMVSmmxZBrJ71n8Wg+YgdjHuIWYF7SjjmCPZFB+/5i/o/PIeRpwVJR3P+NrpIItUjqw==", + "hasInstallScript": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "node-addon-api": "^3.1.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/bignumber.js": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", + "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==", + "engines": { + "node": "*" + } + }, + "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/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/bl/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/bl/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/bl/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/bl/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/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/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dependencies": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/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/body-parser/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/body-parser/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/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/body-parser/node_modules/qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/boom": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-7.3.0.tgz", + "integrity": "sha512-Swpoyi2t5+GhOEGw8rEsKvTxFLIDiiKoUc2gsoV6Lyr43LHBIzch3k2MvYUs8RTROrIkVJ3Al0TkaOGjnb+B6A==", + "deprecated": "This module has moved and is now available at @hapi/boom. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues.", + "dependencies": { + "hoek": "6.x.x" + } + }, + "node_modules/boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "dev": true, + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/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/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/bson": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.0.tgz", + "integrity": "sha512-8jw1NU1hglS+Da1jDOUYuNcBJ4cNHCFIqzlwoFNnsTOg2R/ox0aTYcTiBN4dzRa9q7Cvy6XErh3L8ReTEb9AQQ==", + "dependencies": { + "buffer": "^5.6.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "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-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "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/buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/busboy": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", + "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", + "dependencies": { + "dicer": "0.2.5", + "readable-stream": "1.1.x" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/busboy/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "node_modules/busboy/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/busboy/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, + "node_modules/bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "node": ">=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/camelcase": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.1.tgz", + "integrity": "sha512-tVI4q5jjFV5CavAU8DXfza/TJcZutVKo/5Foskmsqcm0MsL91moHvwiGNnqaa2o6PF/7yT5ikDRcVcl8Rj6LCA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chai": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.4.tgz", + "integrity": "sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chai-http": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/chai-http/-/chai-http-4.3.0.tgz", + "integrity": "sha512-zFTxlN7HLMv+7+SPXZdkd5wUlK+KxH6Q7bIEMiEx0FK3zuuMqL7cwICAQ0V1+yYRozBburYuxN1qZstgHpFZQg==", + "dev": true, + "dependencies": { + "@types/chai": "4", + "@types/superagent": "^3.8.3", + "cookiejar": "^2.1.1", + "is-ip": "^2.0.0", + "methods": "^1.1.2", + "qs": "^6.5.1", + "superagent": "^3.7.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chai-http/node_modules/@types/superagent": { + "version": "3.8.7", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-3.8.7.tgz", + "integrity": "sha512-9KhCkyXv268A2nZ1Wvu7rQWM+BmdYUVkycFeNnYrUL5Zwu7o8wPQ3wBfW59dDP+wuoxw0ww8YKgTNv8j/cgscA==", + "dev": true, + "dependencies": { + "@types/cookiejar": "*", + "@types/node": "*" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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/check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "dev": true, + "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/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "node_modules/class-validator": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.13.2.tgz", + "integrity": "sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw==", + "dependencies": { + "libphonenumber-js": "^1.9.43", + "validator": "^13.7.0" + } + }, + "node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-highlight": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", + "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==", + "dependencies": { + "chalk": "^4.0.0", + "highlight.js": "^10.7.1", + "mz": "^2.4.0", + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" + }, + "bin": { + "highlight": "bin/highlight" + }, + "engines": { + "node": ">=8.0.0", + "npm": ">=5.0.0" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + } + }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, + "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==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "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==" + }, + "node_modules/color-string": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.7.4.tgz", + "integrity": "sha512-nVdUvPVgZMpRQad5dcsCMOSB5BXLljklTiaxS6ehhKxDsAI5sD7k5VmFuBt1y3Rlym8uulc/ANUN/bMWtBu6Sg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/color/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/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, + "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==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "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/concat-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/concat-stream/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/concat-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/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dependencies": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "node_modules/content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-disposition/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/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-parser": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", + "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", + "dependencies": { + "cookie": "0.4.1", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-session": { + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/cookie-session/-/cookie-session-2.0.0-rc.1.tgz", + "integrity": "sha512-zg80EsLe7S1J4y0XxV7SZ8Fbi90ZZoampuX2bfYDOvJfc//98sSlZC41YDzTTjtVbeU1VlVdBbldXOOyi5xzEw==", + "dependencies": { + "cookies": "0.8.0", + "debug": "3.2.6", + "on-headers": "~1.0.2", + "safe-buffer": "5.2.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cookie-session/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "node_modules/cookiejar": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.3.tgz", + "integrity": "sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ==", + "dev": true + }, + "node_modules/cookies": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.8.0.tgz", + "integrity": "sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==", + "dependencies": { + "depd": "~2.0.0", + "keygrip": "~1.1.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "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/cryptiles": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-4.1.3.tgz", + "integrity": "sha512-gT9nyTMSUC1JnziQpPbxKGBbUg8VL7Zn2NB4E1cJYvuXdElHrwxrV9bmltZGDzet45zSDGyYceueke1TjynGzw==", + "deprecated": "This module has moved and is now available at @hapi/cryptiles. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues.", + "dependencies": { + "boom": "7.x.x" + } + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/date-and-time": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-2.0.1.tgz", + "integrity": "sha512-O7Xe5dLaqvY/aF/MFWArsAM1J4j7w1CSZlPCX9uHgmb+6SbkPd8Q4YOvfvH/cZGvFlJFfHOZKxQtmMUOoZhc/w==" + }, + "node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "engines": { + "node": ">=4.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.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "dev": true + }, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "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.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dicer": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", + "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", + "dependencies": { + "readable-stream": "1.1.x", + "streamsearch": "0.1.2" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/dicer/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "node_modules/dicer/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/dicer/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dijkstrajs": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.2.tgz", + "integrity": "sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg==" + }, + "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/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "engines": { + "node": ">=10" + } + }, + "node_modules/duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "node_modules/duplexify": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", + "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", + "dependencies": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.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/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, + "node_modules/encode-utf8": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz", + "integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=" + }, + "node_modules/entities": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", + "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", + "dev": true + }, + "node_modules/es-abstract": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", + "object-inspect": "^1.11.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" + }, + "node_modules/es-get-iterator": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", + "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.0", + "has-symbols": "^1.0.1", + "is-arguments": "^1.1.0", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.5", + "isarray": "^2.0.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "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": { + "version": "7.31.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.31.0.tgz", + "integrity": "sha512-vafgJpSh2ia8tnTkNUkwxGmnumgckLh5aAbLa1xRmIn9+owi8qBNGKL+B881kNKNTy7FFqTEkpNkUvmw0n6PkA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", + "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz", + "integrity": "sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "peerDependencies": { + "eslint": ">=5.0.0", + "prettier": ">=1.13.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "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/esquery/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/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/esrecurse/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/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "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": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "dependencies": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express-validator": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-6.13.0.tgz", + "integrity": "sha512-gvLqMFPwEm+C1CQlF3l695ubY1Shd3AtfI5JDYXM0Ju0A2GsGX+VjjQN7TcHXF6cO8wPgU8hSSFqWecBR0Gx1g==", + "dependencies": { + "lodash": "^4.17.21", + "validator": "^13.6.0" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/express-winston": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/express-winston/-/express-winston-4.2.0.tgz", + "integrity": "sha512-EMD74g63nVHi7pFleQw7KHCxiA1pjF5uCwbCfzGqmFxs9KvlDPIVS3cMGpULm6MshExMT9TjC3SqmRGB9kb7yw==", + "dependencies": { + "chalk": "^2.4.2", + "lodash": "^4.17.21" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "winston": ">=3.x <4" + } + }, + "node_modules/express-winston/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/express-winston/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/express-winston/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/express-winston/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "node_modules/express-winston/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": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/express-winston/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "engines": { + "node": ">=4" + } + }, + "node_modules/express-winston/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/express/node_modules/cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/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/express/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/express/node_modules/qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/express/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/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "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==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "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==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/fast-text-encoding": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", + "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig==" + }, + "node_modules/fecha": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz", + "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==" + }, + "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/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.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/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/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "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": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "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.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz", + "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==", + "dev": true + }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, + "node_modules/follow-redirects": { + "version": "1.14.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz", + "integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/formidable": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.6.tgz", + "integrity": "sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==", + "deprecated": "Please upgrade to latest, formidable@v2 or formidable@v3! Check these notes: https://bit.ly/2ZEqIau", + "dev": true, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "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": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "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/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "node_modules/gauge": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.0.tgz", + "integrity": "sha512-F8sU45yQpjQjxKkm1UOAhf0U/O0aFt//Fl7hsrNVto+patMHjs7dPI9mFOGUKbhrgKm0S3EjW3scMFuQmWSROw==", + "dependencies": { + "ansi-regex": "^5.0.1", + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/gaxios": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.3.2.tgz", + "integrity": "sha512-T+ap6GM6UZ0c4E6yb1y/hy2UB6hTrqhglp3XfmU9qbLCGRYhLVV5aRPpC4EmoG8N8zOnkYCgoBz+ScvGAARY6Q==", + "dependencies": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gcp-metadata": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.3.1.tgz", + "integrity": "sha512-x850LS5N7V1F3UcV7PoupzGsyD6iVwTVvsh3tbXfkctZnBnjW5yu5z1/3k3SehF7TyoTIe78rJs02GMMy+LF+A==", + "dependencies": { + "gaxios": "^4.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gcs-resumable-upload": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/gcs-resumable-upload/-/gcs-resumable-upload-3.6.0.tgz", + "integrity": "sha512-IyaNs4tx3Mp2UKn0CltRUiW/ZXYFlBNuK/V+ixs80chzVD+BJq3+8bfiganATFfCoMluAjokF9EswNJdVuOs8A==", + "dependencies": { + "abort-controller": "^3.0.0", + "async-retry": "^1.3.3", + "configstore": "^5.0.0", + "extend": "^3.0.2", + "gaxios": "^4.0.0", + "google-auth-library": "^7.0.0", + "pumpify": "^2.0.0", + "stream-events": "^1.0.4" + }, + "bin": { + "gcs-upload": "build/src/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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/global-dirs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", + "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", + "dev": true, + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globals": { + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", + "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/google-auth-library": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.10.2.tgz", + "integrity": "sha512-M37o9Kxa/TLvOLgF71SXvLeVEP5sbSTmKl1zlIgl72SFy5PtsU3pOdu8G8MIHHpQ3/NZabDI8rQkA9DvQVKkPA==", + "dependencies": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^4.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/google-p12-pem": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.1.2.tgz", + "integrity": "sha512-tjf3IQIt7tWCDsa0ofDQ1qqSCNzahXDxdAGJDbruWqu3eCg5CKLYKN+hi0s6lfvzYZ1GDVr+oDF9OOWlDSdf0A==", + "dependencies": { + "node-forge": "^0.10.0" + }, + "bin": { + "gp12-pem": "build/src/bin/gp12-pem.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/got/node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" + }, + "node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true, + "engines": { + "node": ">=4.x" + } + }, + "node_modules/gtoken": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.3.1.tgz", + "integrity": "sha512-yqOREjzLHcbzz1UrQoxhBtpk8KjrVhuqPE7od1K2uhyxG2BHjKZetlbLw/SPZak/QqTIQW+addS+EcjqQsZbwQ==", + "dependencies": { + "gaxios": "^4.0.0", + "google-p12-pem": "^3.0.3", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "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/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-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, + "node_modules/has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/hash-stream-validation": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/hash-stream-validation/-/hash-stream-validation-0.2.4.tgz", + "integrity": "sha512-Gjzu0Xn7IagXVkSu9cSFuK1fqzwtLwFhNhVL8IFJijRNMgUttFbBSIAzKuSIrsFMO1+g1RlsoN49zPIbwPDMGQ==" + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "engines": { + "node": "*" + } + }, + "node_modules/hoek": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz", + "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==", + "deprecated": "This module has moved and is now available at @hapi/hoek. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues." + }, + "node_modules/http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "node_modules/http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-errors/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-errors/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "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": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "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": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", + "dev": true + }, + "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/import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "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/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dependencies": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "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-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "dev": true, + "dependencies": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ip/-/is-ip-2.0.0.tgz", + "integrity": "sha1-aO6gfooKCpTC0IDdZ0xzGrKkYas=", + "dev": true, + "dependencies": { + "ip-regex": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-npm": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", + "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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-number-object": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", + "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "engines": { + "node": ">=8" + } + }, + "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-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", + "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakref": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", + "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", + "dependencies": { + "call-bind": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/iterate-iterator": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.2.tgz", + "integrity": "sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/iterate-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz", + "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==", + "dependencies": { + "es-get-iterator": "^1.0.2", + "iterate-iterator": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, + "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==", + "dev": true + }, + "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": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=4", + "npm": ">=1.4.28" + } + }, + "node_modules/jsonwebtoken/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/jsonwebtoken/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/jsonwebtoken/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "dependencies": { + "jwa": "^2.0.0", + "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/keygrip": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", + "integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==", + "dependencies": { + "tsscmp": "1.0.6" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.0" + } + }, + "node_modules/klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11" + } + }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, + "node_modules/latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dev": true, + "dependencies": { + "package-json": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "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/libphonenumber-js": { + "version": "1.9.43", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.43.tgz", + "integrity": "sha512-tNB87ZutAiAkl3DE/Bo0Mxqn/XZbNxhPg4v9bYBwQQW4dlhBGqXl1vtmPxeDWbrijzwOA9vRjOOFm5V9SK/W3w==" + }, + "node_modules/linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "dev": true, + "dependencies": { + "uc.micro": "^1.0.1" + } + }, + "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.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, + "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/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/logform": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.3.0.tgz", + "integrity": "sha512-graeoWUH2knKbGthMtuG1EfaSPMZFZBIrhuJHhkS5ZseFBrc7DupCzihOQAzsK/qIKPQaPJ/lFQFctILUY5ARQ==", + "dependencies": { + "colors": "^1.2.1", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^1.1.0", + "triple-beam": "^1.3.0" + } + }, + "node_modules/logform/node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/markdown-it": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-11.0.1.tgz", + "integrity": "sha512-aU1TzmBKcWNNYvH9pjq6u92BML+Hz3h5S/QpfTFwiQF852pLT+9qHsrhM9JYipkOXZxGn+sGH8oyJE9FD9WezQ==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "entities": "~2.0.0", + "linkify-it": "^3.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", + "dev": true + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memory-cache": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/memory-cache/-/memory-cache-0.2.0.tgz", + "integrity": "sha1-eJCwHVLADI68nVM+H46xfjA0hxo=" + }, + "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": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "dependencies": { + "mime-db": "1.51.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "node_modules/minipass": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.5.tgz", + "integrity": "sha512-+8NzxD82XQoNKNrl1d/FSi+X8wAEWR+sbYAfIvub4Nz0d22plFG72CEVVaufV8PNf4qSslFTD8VMOxNVhHCjTw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mocha": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.1.3.tgz", + "integrity": "sha512-Xcpl9FqXOAYqI3j79pEtHBBnQgVXIhpULjGQa7DVb0Po+VzmSIK9kanAiWLHoRR/dbZ2qpdPshuXr8l1VaHCzw==", + "dev": true, + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.2", + "debug": "4.3.2", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.7", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "nanoid": "3.1.25", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "workerpool": "6.1.5", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/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/mocha/node_modules/debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/mocha/node_modules/debug/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/mocha/node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/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/mocha/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/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "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/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/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.13", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.13.tgz", + "integrity": "sha512-M55tpCr/p5i6vdJ54nm4MG6/7SKV4JqlWnqbx6yCRuAuW05CZ7u+gNuHVPQVF9dZ59ALXjOtPEUl+OXklAa7ng==", + "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/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/mongoose/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/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/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/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/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "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.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/multer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.3.tgz", + "integrity": "sha512-np0YLKncuZoTzufbkM6wEKp68EhWJXcU6fq6QqrSwkckd2LlMgd1UqhUJLj6NS/5sZ8dE8LYDWslsltJznnXlg==", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^0.2.11", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "on-finished": "^2.3.0", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.1.25", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz", + "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==", + "dev": true, + "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": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "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/node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==" + }, + "node_modules/node-fetch": { + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz", + "integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + } + }, + "node_modules/node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/nodemon": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.15.tgz", + "integrity": "sha512-gdHMNx47Gw7b3kWxJV64NI+Q5nfl0y5DgDbiVtShiwa7Z0IZ07Ll4RLFo6AjrhzMtoEZn5PDE3/c2AbVsiCkpA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5", + "update-notifier": "^5.1.0" + }, + "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/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/nodemon/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/nodemon/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==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "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/normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/npmlog": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.0.tgz", + "integrity": "sha512-03ppFRGlsyUaQFbGC2C8QWJN/C/K7PsfyD9aQdhVKAQIH4sQBc8WASqFBP7O+Ut4d2oo5LoeoboB3cGdBZSp6Q==", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.0", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", + "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/object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "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": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, + "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-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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==", + "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/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, + "dependencies": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/package-json/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, + "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/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, + "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/passport": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.1.tgz", + "integrity": "sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg==", + "dependencies": { + "passport-strategy": "1.x.x", + "pause": "0.0.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/passport-local": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz", + "integrity": "sha1-H+YyaMkudWBmJkN+O5BmYsFbpu4=", + "dependencies": { + "passport-strategy": "1.x.x" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=", + "engines": { + "node": ">= 0.4.0" + } + }, + "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==", + "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": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "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": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" + }, + "node_modules/pg": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.7.1.tgz", + "integrity": "sha512-7bdYcv7V6U3KAtWjpQJJBww0UEsWuh4yQ/EjNf2HeO/NnvKjpvhEIe/A/TleP6wtmSKnUnghs5A9jUoK6iDdkA==", + "dependencies": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.5.0", + "pg-pool": "^3.4.1", + "pg-protocol": "^1.5.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "pg-native": ">=2.0.0" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-connection-string": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", + "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.4.1.tgz", + "integrity": "sha512-TVHxR/gf3MeJRvchgNHxsYsTCHQ+4wm3VIHSS19z8NC0+gioEhq1okDY1sm/TYbfoP6JLFx01s0ShvZ3puP/iQ==", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", + "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.4.tgz", + "integrity": "sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w==", + "dependencies": { + "split2": "^3.1.1" + } + }, + "node_modules/picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pngjs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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/prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/prettier": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.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/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/promise.allsettled": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.5.tgz", + "integrity": "sha512-tVDqeZPoBC0SlzJHzWGZ2NKAguVq2oiYj7gbggbiTvH2itHohijTp7njOUA0aQ/nl+0lr/r6egmhoYu63UZ/pQ==", + "dependencies": { + "array.prototype.map": "^1.0.4", + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "iterate-value": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/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/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pumpify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-2.0.1.tgz", + "integrity": "sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==", + "dependencies": { + "duplexify": "^4.1.1", + "inherits": "^2.0.3", + "pump": "^3.0.0" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "dev": true, + "dependencies": { + "escape-goat": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/qrcode": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.0.tgz", + "integrity": "sha512-9MgRpgVc+/+47dFvQeD6U2s0Z92EsKzcHogtum4QB+UNd025WOJSHvn/hjk9xmzj7Stj95CyUAs31mrjxliEsQ==", + "dependencies": { + "dijkstrajs": "^1.0.1", + "encode-utf8": "^1.0.3", + "pngjs": "^5.0.0", + "yargs": "^15.3.1" + }, + "bin": { + "qrcode": "bin/qrcode" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/qrcode/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qrcode/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/qrcode/node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/qrcode/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/qrcode/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + }, + "node_modules/qrcode/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", + "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "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/raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dependencies": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/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/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "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/reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" + }, + "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/registry-auth-token": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "dev": true, + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dev": true, + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=8" + } + }, + "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/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "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/responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "dependencies": { + "lowercase-keys": "^1.0.0" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/retry-request": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-4.2.2.tgz", + "integrity": "sha512-xA93uxUD/rogV7BV59agW/JHPGXeREMWiZc9jhcwY4YdZ7QOtC7qbomYg0n4wyk2lJhggjvKvhNX8wln/Aldhg==", + "dependencies": { + "debug": "^4.1.1", + "extend": "^3.0.2" + }, + "engines": { + "node": ">=8.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==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + }, + "node_modules/safe-stable-stringify": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-1.1.1.tgz", + "integrity": "sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw==" + }, + "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/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": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dev": true, + "dependencies": { + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semver-diff/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/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/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/send/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/send/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/send/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "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/signal-exit": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", + "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==" + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/sliced": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", + "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" + }, + "node_modules/snakeize": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/snakeize/-/snakeize-0.1.0.tgz", + "integrity": "sha1-EMCI2LWOsHazIpu1oE4jLOEmQi0=" + }, + "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/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", + "optional": true, + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "node_modules/split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dependencies": { + "readable-stream": "^3.0.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "engines": { + "node": "*" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/stream-events": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", + "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", + "dependencies": { + "stubs": "^3.0.0" + } + }, + "node_modules/stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, + "node_modules/streamsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "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/stubs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", + "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=" + }, + "node_modules/superagent": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", + "integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==", + "dev": true, + "dependencies": { + "component-emitter": "^1.2.0", + "cookiejar": "^2.1.0", + "debug": "^3.1.0", + "extend": "^3.0.0", + "form-data": "^2.3.1", + "formidable": "^1.2.0", + "methods": "^1.1.1", + "mime": "^1.4.1", + "qs": "^6.5.1", + "readable-stream": "^2.3.5" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/superagent/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/superagent/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/superagent/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/superagent/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==", + "dev": true, + "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/superagent/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==", + "dev": true + }, + "node_modules/superagent/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==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "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==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/table": { + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.3.tgz", + "integrity": "sha512-5DkIxeA7XERBqMwJq0aHZOdMadBx4e6eDoFRuyT5VR82J0Ycg2DwM6GfA/EQAhJ+toRTaS1lIdSQCqgrmhPnlw==", + "dev": true, + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.8.2.tgz", + "integrity": "sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/tar": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/teeny-request": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-7.1.3.tgz", + "integrity": "sha512-Ew3aoFzgQEatLA5OBIjdr1DWJUaC1xardG+qbPPo5k/y/3fMwXLxpjh5UB5dVfElktLaQbbMs80chkz53ByvSg==", + "dependencies": { + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "stream-events": "^1.0.5", + "uuid": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "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/touch/node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "node_modules/triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, + "node_modules/ts-node": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.4.0.tgz", + "integrity": "sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "0.7.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/acorn": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz", + "integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + }, + "node_modules/tsscmp": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", + "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==", + "engines": { + "node": ">=0.6.x" + } + }, + "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-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typeorm": { + "version": "0.2.41", + "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.2.41.tgz", + "integrity": "sha512-/d8CLJJxKPgsnrZWiMyPI0rz2MFZnBQrnQ5XP3Vu3mswv2WPexb58QM6BEtmRmlTMYN5KFWUz8SKluze+wS9xw==", + "dependencies": { + "@sqltools/formatter": "^1.2.2", + "app-root-path": "^3.0.0", + "buffer": "^6.0.3", + "chalk": "^4.1.0", + "cli-highlight": "^2.1.11", + "debug": "^4.3.1", + "dotenv": "^8.2.0", + "glob": "^7.1.6", + "js-yaml": "^4.0.0", + "mkdirp": "^1.0.4", + "reflect-metadata": "^0.1.13", + "sha.js": "^2.4.11", + "tslib": "^2.1.0", + "xml2js": "^0.4.23", + "yargs": "^17.0.1", + "zen-observable-ts": "^1.0.0" + }, + "bin": { + "typeorm": "cli.js" + }, + "funding": { + "url": "https://opencollective.com/typeorm" + }, + "peerDependencies": { + "@sap/hana-client": "*", + "better-sqlite3": "*", + "hdb-pool": "*", + "ioredis": "*", + "mongodb": "^3.6.0", + "mssql": "*", + "mysql2": "*", + "oracledb": "*", + "pg": "*", + "pg-native": "*", + "pg-query-stream": "*", + "redis": "*", + "sql.js": "*", + "sqlite3": "*", + "typeorm-aurora-data-api-driver": "*" + }, + "peerDependenciesMeta": { + "@sap/hana-client": { + "optional": true + }, + "better-sqlite3": { + "optional": true + }, + "hdb-pool": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "mongodb": { + "optional": true + }, + "mssql": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "oracledb": { + "optional": true + }, + "pg": { + "optional": true + }, + "pg-native": { + "optional": true + }, + "pg-query-stream": { + "optional": true + }, + "redis": { + "optional": true + }, + "sql.js": { + "optional": true + }, + "sqlite3": { + "optional": true + }, + "typeorm-aurora-data-api-driver": { + "optional": true + } + } + }, + "node_modules/typeorm/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==" + }, + "node_modules/typeorm/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "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.2.1" + } + }, + "node_modules/typeorm/node_modules/dotenv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "engines": { + "node": ">=10" + } + }, + "node_modules/typeorm/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==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/typeorm/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/typeorm/node_modules/yargs": { + "version": "17.2.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.2.1.tgz", + "integrity": "sha512-XfR8du6ua4K6uLGm5S6fA+FIJom/MdJcFNVY8geLlp2v8GYbOXD4EB1tPNZsRn4vBzKGMgb5DRZMeWuFc2GO8Q==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/typescript": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz", + "integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true + }, + "node_modules/uglify-js": { + "version": "3.14.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.3.tgz", + "integrity": "sha512-mic3aOdiq01DuSVx0TseaEzMIVqebMZ0Z3vaeDhFEh9bsc24hV1TFvN74reA2vs08D0ZWfNjAcJ3UbVLaBss+g==", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dependencies": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-notifier": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", + "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", + "dev": true, + "dependencies": { + "boxen": "^5.0.0", + "chalk": "^4.1.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.4.0", + "is-npm": "^5.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.1.0", + "pupa": "^2.1.1", + "semver": "^7.3.4", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "dependencies": { + "prepend-http": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "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": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "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/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/winston": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", + "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==", + "dependencies": { + "@dabh/diagnostics": "^2.0.2", + "async": "^3.1.0", + "is-stream": "^2.0.0", + "logform": "^2.2.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.4.0" + }, + "engines": { + "node": ">= 6.4.0" + } + }, + "node_modules/winston-transport": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", + "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==", + "dependencies": { + "readable-stream": "^2.3.7", + "triple-beam": "^1.2.0" + }, + "engines": { + "node": ">= 6.4.0" + } + }, + "node_modules/winston-transport/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/winston-transport/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/winston-transport/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/winston-transport/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/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": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" + }, + "node_modules/workerpool": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.5.tgz", + "integrity": "sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "engines": { + "node": ">=8" + } + }, + "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/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "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/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zen-observable": { + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz", + "integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==" + }, + "node_modules/zen-observable-ts": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.1.0.tgz", + "integrity": "sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA==", + "dependencies": { + "@types/zen-observable": "0.8.3", + "zen-observable": "0.8.15" + } } - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" - }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, - "deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", - "dev": true, - "requires": { - "type-detect": "^4.0.0" - } - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" - }, - "defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "requires": { - "object-keys": "^1.0.12" - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" - }, - "denque": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.0.tgz", - "integrity": "sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ==" - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" - }, - "dicer": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", - "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", - "requires": { - "readable-stream": "1.1.x", - "streamsearch": "0.1.2" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "dev": true + }, + "@babel/highlight": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.0.tgz", + "integrity": "sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.15.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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==", + "dev": true, + "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": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@cspotcode/source-map-consumer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", + "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", + "dev": true + }, + "@cspotcode/source-map-support": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", + "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", + "dev": true, + "requires": { + "@cspotcode/source-map-consumer": "0.8.0" + } + }, + "@dabh/diagnostics": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", + "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==", + "requires": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + } + }, + "@google-cloud/common": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-3.8.1.tgz", + "integrity": "sha512-FOs3NFU6bDt5mXE7IFpwIeqzLwRZNu9lJYl+bHVNkwmxX/w4VyDZAiGjQHhpV1Ek+muNKlX8HPchxaIxNTuOhw==", + "requires": { + "@google-cloud/projectify": "^2.0.0", + "@google-cloud/promisify": "^2.0.0", + "arrify": "^2.0.1", + "duplexify": "^4.1.1", + "ent": "^2.2.0", + "extend": "^3.0.2", + "google-auth-library": "^7.9.2", + "retry-request": "^4.2.2", + "teeny-request": "^7.0.0" + } + }, + "@google-cloud/paginator": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-3.0.6.tgz", + "integrity": "sha512-XCTm/GfQIlc1ZxpNtTSs/mnZxC2cePNhxU3X8EzHXKIJ2JFncmJj2Fcd2IP+gbmZaSZnY0juFxbUCkIeuu/2eQ==", + "requires": { + "arrify": "^2.0.0", + "extend": "^3.0.2" + } + }, + "@google-cloud/projectify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-2.1.1.tgz", + "integrity": "sha512-+rssMZHnlh0twl122gXY4/aCrk0G1acBqkHFfYddtsqpYXGxA29nj9V5V9SfC+GyOG00l650f6lG9KL+EpFEWQ==" + }, + "@google-cloud/promisify": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-2.0.4.tgz", + "integrity": "sha512-j8yRSSqswWi1QqUGKVEKOG03Q7qOoZP6/h2zN2YO+F5h2+DHU0bSrHCK9Y7lo2DI9fBd8qGAw795sf+3Jva4yA==" + }, + "@google-cloud/storage": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-5.16.0.tgz", + "integrity": "sha512-I/1lA78v9c5EbOM/KfcYsjzA7YlHQmhpzHYdKLKdYC8X5fFaQrw5nK+FU8GbEwdPxmREAF2qPbN7Ccq+A/ndWA==", + "requires": { + "@google-cloud/common": "^3.8.1", + "@google-cloud/paginator": "^3.0.0", + "@google-cloud/promisify": "^2.0.0", + "arrify": "^2.0.0", + "async-retry": "^1.3.1", + "compressible": "^2.0.12", + "date-and-time": "^2.0.0", + "duplexify": "^4.0.0", + "extend": "^3.0.2", + "gcs-resumable-upload": "^3.5.1", + "get-stream": "^6.0.0", + "hash-stream-validation": "^0.2.2", + "mime": "^3.0.0", + "mime-types": "^2.0.8", + "p-limit": "^3.0.1", + "pumpify": "^2.0.0", + "snakeize": "^0.1.0", + "stream-events": "^1.0.1", + "xdg-basedir": "^4.0.0" + } + }, + "@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@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 + }, + "@mapbox/node-pre-gyp": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.7.tgz", + "integrity": "sha512-PplSvl4pJ5N3BkVjAdDzpPhVUPdC73JgttkR+LnBx2OORC1GCQsBjUeEuipf9uOaAM1SbxcdZFfR3KDTKm2S0A==", + "requires": { + "detect-libc": "^1.0.3", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.5", + "nopt": "^5.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + } + }, + "@sendgrid/client": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@sendgrid/client/-/client-7.6.0.tgz", + "integrity": "sha512-cpBVZKLlMTO+vpE18krTixubYmZa98oTbLkqBDuTiA3zRkW+urrxg7pDR24TkI35Mid0Zru8jDHwnOiqrXu0TA==", + "requires": { + "@sendgrid/helpers": "^7.6.0", + "axios": "^0.21.4" + } + }, + "@sendgrid/helpers": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@sendgrid/helpers/-/helpers-7.6.0.tgz", + "integrity": "sha512-0uWD+HSXLl4Z/X3cN+UMQC20RE7xwAACgppnfjDyvKG0KvJcUgDGz7HDdQkiMUdcVWfmyk6zKSg7XKfKzBjTwA==", + "requires": { + "deepmerge": "^4.2.2" + } + }, + "@sendgrid/mail": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@sendgrid/mail/-/mail-7.6.0.tgz", + "integrity": "sha512-0KdaSZzflJD/vUAZjB3ALBIuaVGoLq22hrb2fvQXZHRepU/yhRNlEOqrr05MfKBnKskzq1blnD1J0fHxiwaolw==", + "requires": { + "@sendgrid/client": "^7.6.0", + "@sendgrid/helpers": "^7.6.0" + } + }, + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true + }, + "@sqltools/formatter": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.3.tgz", + "integrity": "sha512-O3uyB/JbkAEMZaP3YqyHH7TMnex7tWyCbCI4EfJdOCoN6HIhqdJBWTM6aCCiWQ/5f5wxjgU735QAIpJbjDvmzg==" + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==" + }, + "@tsconfig/node10": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", + "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", + "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", + "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", + "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", + "dev": true + }, + "@types/bcrypt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.0.tgz", + "integrity": "sha512-agtcFKaruL8TmcvqbndlqHPSJgsolhf/qPWchFlgnW1gECTN/nKbFcoFnvKAQRFfKbh+BO6A3SWdJu9t+xF3Lw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/bson": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.2.0.tgz", + "integrity": "sha512-ELCPqAdroMdcuxqwMgUpifQyRoTpyYCNr1V9xKyF40VsBobsj+BbWNRvwGchMgBPGqkw655ypkjj2MEF5ywVwg==", + "requires": { + "bson": "*" + } + }, + "@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==", + "dev": true + }, + "@types/chai": { + "version": "4.2.22", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.22.tgz", + "integrity": "sha512-tFfcE+DSTzWAgifkjik9AySNqIyNoYwmR+uecPwwD/XRNfvOjmC/FjCxpiUGDkDVDphPfCUecSQVFw+lN3M3kQ==", + "dev": true + }, + "@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==", + "dev": true + }, + "@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.25", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.25.tgz", + "integrity": "sha512-OUJIVfRMFijZukGGwTpKNFprqCCXk5WjNGvUgB/CxxBR40QWSjsNK86+yvGKlCOGc7sbwfHLaXhkG+NsytwBaQ==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/express-winston": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/express-winston/-/express-winston-4.0.0.tgz", + "integrity": "sha512-CCNvkHIRKIJGgt64naW7XvsXvw4NkVHHa3EDy63uZzruXaFhZb2+AE0HRZx90ph528D1gm+fx9dA1gmZZ2uzLw==", + "dev": true, + "requires": { + "express-winston": "*" + } + }, + "@types/google-cloud__storage": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@types/google-cloud__storage/-/google-cloud__storage-1.7.2.tgz", + "integrity": "sha512-RaQJ7+Ht20MRYJu7mgKBpbVNZIPneztKIl/DUKacRC6A8mXRsJfgDdPA7indHmJGIgm+hzUTj44+A3RyuuYZhg==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/request": "*" + } + }, + "@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "dev": true + }, + "@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/mongoose": { + "version": "5.11.97", + "resolved": "https://registry.npmjs.org/@types/mongoose/-/mongoose-5.11.97.tgz", + "integrity": "sha512-cqwOVYT3qXyLiGw7ueU2kX9noE8DPGRY6z8eUxudhXY8NZ7DMKYAxyZkLSevGfhCX3dO/AoX5/SO9lAzfjon0Q==", + "dev": true, + "requires": { + "mongoose": "*" + } + }, + "@types/multer": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.7.tgz", + "integrity": "sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, + "@types/node": { + "version": "16.11.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.10.tgz", + "integrity": "sha512-3aRnHa1KlOEEhJ6+CvyHKK5vE9BcLGjtUpwvqYLRvYNQKMfabu3BwfJaA/SLW8dxe28LsNDjtHwePTuzn3gmOA==" + }, + "@types/passport": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.7.tgz", + "integrity": "sha512-JtswU8N3kxBYgo+n9of7C97YQBT+AYPP2aBfNGTzABqPAZnK/WOAaKfh3XesUYMZRrXFuoPc2Hv0/G/nQFveHw==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, + "@types/passport-local": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/@types/passport-local/-/passport-local-1.0.34.tgz", + "integrity": "sha512-PSc07UdYx+jhadySxxIYWuv6sAnY5e+gesn/5lkPKfBeGuIYn9OPR+AAEDq73VRUh6NBTpvE/iPE62rzZUslog==", + "dev": true, + "requires": { + "@types/express": "*", + "@types/passport": "*", + "@types/passport-strategy": "*" + } + }, + "@types/passport-strategy": { + "version": "0.2.35", + "resolved": "https://registry.npmjs.org/@types/passport-strategy/-/passport-strategy-0.2.35.tgz", + "integrity": "sha512-o5D19Jy2XPFoX2rKApykY15et3Apgax00RRLf0RUotPDUsYrQa7x4howLYr9El2mlUApHmCMv5CZ1IXqKFQ2+g==", + "dev": true, + "requires": { + "@types/express": "*", + "@types/passport": "*" + } + }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "@types/request": { + "version": "2.48.7", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.7.tgz", + "integrity": "sha512-GWP9AZW7foLd4YQxyFZDBepl0lPsWLMEXDZUjQ/c1gqVPDPECrRZyEzuhJdnPWioFCq3Tv0qoGpMD6U+ygd4ZA==", + "dev": true, + "requires": { + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" + } + }, + "@types/serve-static": { + "version": "1.13.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", + "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "dev": true, + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "@types/superagent": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-4.1.13.tgz", + "integrity": "sha512-YIGelp3ZyMiH0/A09PMAORO0EBGlF5xIKfDpK74wdYvWUs2o96b5CItJcWPdH409b7SAXIIG6p8NdU/4U2Maww==", + "dev": true, + "requires": { + "@types/cookiejar": "*", + "@types/node": "*" + } + }, + "@types/tough-cookie": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.1.tgz", + "integrity": "sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg==", + "dev": true + }, + "@types/validator": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.0.tgz", + "integrity": "sha512-+jBxVvXVuggZOrm04NR8z+5+bgoW4VZyLzUO+hmPPW1mVFL/HaitLAkizfv4yg9TbG8lkfHWVMQ11yDqrVVCzA==", + "dev": true + }, + "@types/zen-observable": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.3.tgz", + "integrity": "sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw==" + }, + "@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "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": {} + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "requires": { + "string-width": "^4.1.0" + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "apidoc": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/apidoc/-/apidoc-0.28.1.tgz", + "integrity": "sha512-vJbRtNnxWqUUfbY4NJwq9vRB8+Fh43nccckhG9nC4nQBxrMDaBYHhwMbls3OZ9Nv36jWN4KexpLrZ5Ivph8GYg==", + "dev": true, + "requires": { + "apidoc-core": "^0.15.0", + "commander": "^2.20.0", + "fs-extra": "^9.0.1", + "handlebars": "^4.7.7", + "lodash": "^4.17.20", + "markdown-it": "^11.0.0", + "nodemon": "^2.0.4", + "winston": "^3.3.3" + } + }, + "apidoc-core": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/apidoc-core/-/apidoc-core-0.15.0.tgz", + "integrity": "sha512-CJNjRs6R8nc774vUtbv9Uakos5/JbEFpBXgE6oiWUX7OpjI1s04xPuULEoQQJyQM427r5hr55GSHAm5/LRc5TQ==", + "dev": true, + "requires": { + "fs-extra": "^9.0.1", + "glob": "^7.1.6", + "iconv-lite": "^0.6.2", + "klaw-sync": "^6.0.0", + "lodash": "^4.17.20", + "semver": "~7.3.2" + } + }, + "app-root-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.0.0.tgz", + "integrity": "sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw==" + }, + "append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=" + }, + "aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + }, + "are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "array.prototype.map": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.4.tgz", + "integrity": "sha512-Qds9QnX7A0qISY7JT5WuJO0NJPE9CMlC6JzHQfhpqAAQQzufVRoeH7EzUY5GcPTx72voG8LV/5eo+b8Qi8hmhA==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + } + }, + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "async": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.2.tgz", + "integrity": "sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g==" + }, + "async-retry": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", + "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", + "requires": { + "retry": "0.13.1" + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true + }, + "axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "requires": { + "follow-redirects": "^1.14.0" + } + }, + "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": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.0.1.tgz", + "integrity": "sha512-9BTgmrhZM2t1bNuDtrtIMVSmmxZBrJ71n8Wg+YgdjHuIWYF7SjjmCPZFB+/5i/o/PIeRpwVJR3P+NrpIItUjqw==", + "requires": { + "@mapbox/node-pre-gyp": "^1.0.0", + "node-addon-api": "^3.1.0" + } + }, + "bignumber.js": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", + "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==" + }, + "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 + }, + "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" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "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" + } + }, + "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==" + }, + "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" + } + } + } + }, + "bluebird": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "dependencies": { + "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" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "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" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + } + } + }, + "boom": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-7.3.0.tgz", + "integrity": "sha512-Swpoyi2t5+GhOEGw8rEsKvTxFLIDiiKoUc2gsoV6Lyr43LHBIzch3k2MvYUs8RTROrIkVJ3Al0TkaOGjnb+B6A==", + "requires": { + "hoek": "6.x.x" + } + }, + "boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "dev": true, + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.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==", + "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" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "bson": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.0.tgz", + "integrity": "sha512-8jw1NU1hglS+Da1jDOUYuNcBJ4cNHCFIqzlwoFNnsTOg2R/ox0aTYcTiBN4dzRa9q7Cvy6XErh3L8ReTEb9AQQ==", + "requires": { + "buffer": "^5.6.0" + } + }, + "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-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "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==" + }, + "buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" + }, + "busboy": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", + "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", + "requires": { + "dicer": "0.2.5", + "readable-stream": "1.1.x" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } + } + }, + "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 + }, + "camelcase": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.1.tgz", + "integrity": "sha512-tVI4q5jjFV5CavAU8DXfza/TJcZutVKo/5Foskmsqcm0MsL91moHvwiGNnqaa2o6PF/7yT5ikDRcVcl8Rj6LCA==", + "dev": true + }, + "chai": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.4.tgz", + "integrity": "sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + } + }, + "chai-http": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/chai-http/-/chai-http-4.3.0.tgz", + "integrity": "sha512-zFTxlN7HLMv+7+SPXZdkd5wUlK+KxH6Q7bIEMiEx0FK3zuuMqL7cwICAQ0V1+yYRozBburYuxN1qZstgHpFZQg==", + "dev": true, + "requires": { + "@types/chai": "4", + "@types/superagent": "^3.8.3", + "cookiejar": "^2.1.1", + "is-ip": "^2.0.0", + "methods": "^1.1.2", + "qs": "^6.5.1", + "superagent": "^3.7.0" + }, + "dependencies": { + "@types/superagent": { + "version": "3.8.7", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-3.8.7.tgz", + "integrity": "sha512-9KhCkyXv268A2nZ1Wvu7rQWM+BmdYUVkycFeNnYrUL5Zwu7o8wPQ3wBfW59dDP+wuoxw0ww8YKgTNv8j/cgscA==", + "dev": true, + "requires": { + "@types/cookiejar": "*", + "@types/node": "*" + } + } + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, + "chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "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" + } + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "class-validator": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.13.2.tgz", + "integrity": "sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw==", + "requires": { + "libphonenumber-js": "^1.9.43", + "validator": "^13.7.0" + } + }, + "cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true + }, + "cli-highlight": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", + "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==", + "requires": { + "chalk": "^4.0.0", + "highlight.js": "^10.7.1", + "mz": "^2.4.0", + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "requires": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + }, + "dependencies": { + "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": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + } + } + }, + "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==", + "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==" + }, + "color-string": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.7.4.tgz", + "integrity": "sha512-nVdUvPVgZMpRQad5dcsCMOSB5BXLljklTiaxS6ehhKxDsAI5sD7k5VmFuBt1y3Rlym8uulc/ANUN/bMWtBu6Sg==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" + }, + "colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "requires": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "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" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "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" + } + }, + "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==" + }, + "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" + } + } + } + }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "requires": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + } + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + }, + "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==" + } + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + }, + "cookie-parser": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", + "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", + "requires": { + "cookie": "0.4.1", + "cookie-signature": "1.0.6" + } + }, + "cookie-session": { + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/cookie-session/-/cookie-session-2.0.0-rc.1.tgz", + "integrity": "sha512-zg80EsLe7S1J4y0XxV7SZ8Fbi90ZZoampuX2bfYDOvJfc//98sSlZC41YDzTTjtVbeU1VlVdBbldXOOyi5xzEw==", + "requires": { + "cookies": "0.8.0", + "debug": "3.2.6", + "on-headers": "~1.0.2", + "safe-buffer": "5.2.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "cookiejar": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.3.tgz", + "integrity": "sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ==", + "dev": true + }, + "cookies": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.8.0.tgz", + "integrity": "sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==", + "requires": { + "depd": "~2.0.0", + "keygrip": "~1.1.0" + } + }, + "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" + } + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "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" + } + }, + "cryptiles": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-4.1.3.tgz", + "integrity": "sha512-gT9nyTMSUC1JnziQpPbxKGBbUg8VL7Zn2NB4E1cJYvuXdElHrwxrV9bmltZGDzet45zSDGyYceueke1TjynGzw==", + "requires": { + "boom": "7.x.x" + } + }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" + }, + "date-and-time": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-2.0.1.tgz", + "integrity": "sha512-O7Xe5dLaqvY/aF/MFWArsAM1J4j7w1CSZlPCX9uHgmb+6SbkPd8Q4YOvfvH/cZGvFlJFfHOZKxQtmMUOoZhc/w==" + }, + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "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.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" + }, + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "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.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" + }, + "dicer": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", + "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", + "requires": { + "readable-stream": "1.1.x", + "streamsearch": "0.1.2" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, + "dijkstrajs": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.2.tgz", + "integrity": "sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg==" + }, + "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" + } + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "requires": { + "is-obj": "^2.0.0" + } + }, + "dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "duplexify": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", + "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", + "requires": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.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" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, + "encode-utf8": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz", + "integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=" + }, + "entities": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", + "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", + "dev": true + }, + "es-abstract": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", + "object-inspect": "^1.11.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" + }, + "es-get-iterator": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", + "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.0", + "has-symbols": "^1.0.1", + "is-arguments": "^1.1.0", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.5", + "isarray": "^2.0.5" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "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 + }, + "eslint": { + "version": "7.31.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.31.0.tgz", + "integrity": "sha512-vafgJpSh2ia8tnTkNUkwxGmnumgckLh5aAbLa1xRmIn9+owi8qBNGKL+B881kNKNTy7FFqTEkpNkUvmw0n6PkA==", + "dev": true, + "requires": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-config-prettier": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", + "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", + "dev": true, + "requires": {} + }, + "eslint-plugin-prettier": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz", + "integrity": "sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "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 + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "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" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "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" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "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": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "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" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "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==" + } + } + }, + "express-validator": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-6.13.0.tgz", + "integrity": "sha512-gvLqMFPwEm+C1CQlF3l695ubY1Shd3AtfI5JDYXM0Ju0A2GsGX+VjjQN7TcHXF6cO8wPgU8hSSFqWecBR0Gx1g==", + "requires": { + "lodash": "^4.17.21", + "validator": "^13.6.0" + } + }, + "express-winston": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/express-winston/-/express-winston-4.2.0.tgz", + "integrity": "sha512-EMD74g63nVHi7pFleQw7KHCxiA1pjF5uCwbCfzGqmFxs9KvlDPIVS3cMGpULm6MshExMT9TjC3SqmRGB9kb7yw==", + "requires": { + "chalk": "^2.4.2", + "lodash": "^4.17.21" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "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" + } + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "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==", + "dev": true + }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "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==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fast-text-encoding": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", + "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig==" + }, + "fecha": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz", + "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==" + }, + "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" + } + }, + "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.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "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" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "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": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "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.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz", + "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==", + "dev": true + }, + "fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, + "follow-redirects": { + "version": "1.14.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz", + "integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==" + }, + "form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "formidable": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.6.tgz", + "integrity": "sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==", + "dev": true + }, + "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": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "requires": { + "minipass": "^3.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "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==" + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "gauge": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.0.tgz", + "integrity": "sha512-F8sU45yQpjQjxKkm1UOAhf0U/O0aFt//Fl7hsrNVto+patMHjs7dPI9mFOGUKbhrgKm0S3EjW3scMFuQmWSROw==", + "requires": { + "ansi-regex": "^5.0.1", + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + } + }, + "gaxios": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.3.2.tgz", + "integrity": "sha512-T+ap6GM6UZ0c4E6yb1y/hy2UB6hTrqhglp3XfmU9qbLCGRYhLVV5aRPpC4EmoG8N8zOnkYCgoBz+ScvGAARY6Q==", + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.1" + } + }, + "gcp-metadata": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.3.1.tgz", + "integrity": "sha512-x850LS5N7V1F3UcV7PoupzGsyD6iVwTVvsh3tbXfkctZnBnjW5yu5z1/3k3SehF7TyoTIe78rJs02GMMy+LF+A==", + "requires": { + "gaxios": "^4.0.0", + "json-bigint": "^1.0.0" + } + }, + "gcs-resumable-upload": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/gcs-resumable-upload/-/gcs-resumable-upload-3.6.0.tgz", + "integrity": "sha512-IyaNs4tx3Mp2UKn0CltRUiW/ZXYFlBNuK/V+ixs80chzVD+BJq3+8bfiganATFfCoMluAjokF9EswNJdVuOs8A==", + "requires": { + "abort-controller": "^3.0.0", + "async-retry": "^1.3.3", + "configstore": "^5.0.0", + "extend": "^3.0.2", + "gaxios": "^4.0.0", + "google-auth-library": "^7.0.0", + "pumpify": "^2.0.0", + "stream-events": "^1.0.4" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "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" + } + }, + "global-dirs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", + "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", + "dev": true, + "requires": { + "ini": "2.0.0" + } + }, + "globals": { + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", + "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "google-auth-library": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.10.2.tgz", + "integrity": "sha512-M37o9Kxa/TLvOLgF71SXvLeVEP5sbSTmKl1zlIgl72SFy5PtsU3pOdu8G8MIHHpQ3/NZabDI8rQkA9DvQVKkPA==", + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^4.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + } + }, + "google-p12-pem": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.1.2.tgz", + "integrity": "sha512-tjf3IQIt7tWCDsa0ofDQ1qqSCNzahXDxdAGJDbruWqu3eCg5CKLYKN+hi0s6lfvzYZ1GDVr+oDF9OOWlDSdf0A==", + "requires": { + "node-forge": "^0.10.0" + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "dependencies": { + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + } + } + }, + "graceful-fs": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "gtoken": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.3.1.tgz", + "integrity": "sha512-yqOREjzLHcbzz1UrQoxhBtpk8KjrVhuqPE7od1K2uhyxG2BHjKZetlbLw/SPZak/QqTIQW+addS+EcjqQsZbwQ==", + "requires": { + "gaxios": "^4.0.0", + "google-p12-pem": "^3.0.3", + "jws": "^4.0.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" + } + }, + "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-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "requires": { + "has-symbols": "^1.0.2" + } + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true + }, + "hash-stream-validation": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/hash-stream-validation/-/hash-stream-validation-0.2.4.tgz", + "integrity": "sha512-Gjzu0Xn7IagXVkSu9cSFuK1fqzwtLwFhNhVL8IFJijRNMgUttFbBSIAzKuSIrsFMO1+g1RlsoN49zPIbwPDMGQ==" + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==" + }, + "hoek": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz", + "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==" + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "dependencies": { + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } + } + }, + "http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "requires": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "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": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", + "dev": true + }, + "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" + } }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - } - } - }, - "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true - }, - "dijkstrajs": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.1.tgz", - "integrity": "sha1-082BIh4+pAdCz83lVtTpnpjdxxs=" - }, - "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" - } - }, - "dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "requires": { - "is-obj": "^2.0.0" - } - }, - "dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true - }, - "duplexify": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", - "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", - "requires": { - "end-of-stream": "^1.4.1", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1", - "stream-shift": "^1.0.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "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" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - }, - "enabled": { - "version": "2.0.0", - "resolved": "http://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", - "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", - "dev": true - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "requires": { - "once": "^1.4.0" - } - }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1" - } - }, - "ent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=" - }, - "entities": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", - "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", - "dev": true - }, - "es-array-method-boxes-properly": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", - "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" - }, - "es-get-iterator": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", - "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.0", - "has-symbols": "^1.0.1", - "is-arguments": "^1.1.0", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.5", - "isarray": "^2.0.5" - }, - "dependencies": { - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - } - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", - "dev": true - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "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 - }, - "eslint": { - "version": "7.31.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.31.0.tgz", - "integrity": "sha512-vafgJpSh2ia8tnTkNUkwxGmnumgckLh5aAbLa1xRmIn9+owi8qBNGKL+B881kNKNTy7FFqTEkpNkUvmw0n6PkA==", - "dev": true, - "requires": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } }, - "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" - } + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true + }, + "internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "requires": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.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" - } + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "requires": { + "has-bigints": "^1.0.1" + } }, - "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 + "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" + } }, - "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 + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "requires": { + "has-tostringtag": "^1.0.0" + } }, - "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 + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true }, - "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-config-prettier": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", - "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", - "dev": true - }, - "eslint-plugin-prettier": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz", - "integrity": "sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw==", - "dev": true, - "requires": { - "prettier-linter-helpers": "^1.0.0" - } - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "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 - }, - "espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", - "dev": true, - "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "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" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "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" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "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": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" - }, - "event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" - }, - "express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", - "requires": { - "accepts": "~1.3.7", - "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", - "content-type": "~1.0.4", - "cookie": "0.4.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "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" + } }, - "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" - } + "is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "dev": true, + "requires": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + } }, - "mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" + "is-ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ip/-/is-ip-2.0.0.tgz", + "integrity": "sha1-aO6gfooKCpTC0IDdZ0xzGrKkYas=", + "dev": true, + "requires": { + "ip-regex": "^2.0.0" + } }, - "mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", - "requires": { - "mime-db": "1.40.0" - } + "is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==" + }, + "is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==" + }, + "is-npm": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", + "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", + "dev": true + }, + "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-number-object": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", + "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "requires": { + "has-tostringtag": "^1.0.0" + } }, - "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" }, - "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==" + "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-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==" + }, + "is-shared-array-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", + "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==" + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "is-weakref": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", + "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", + "requires": { + "call-bind": "^1.0.0" + } + }, + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true + }, + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "iterate-iterator": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.2.tgz", + "integrity": "sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw==" + }, + "iterate-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz", + "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==", + "requires": { + "es-get-iterator": "^1.0.2", + "iterate-iterator": "^1.0.1" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "requires": { + "bignumber.js": "^9.0.0" + } + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "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": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "dependencies": { + "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" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } }, - "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" - } - } - } - }, - "express-validator": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-6.12.0.tgz", - "integrity": "sha512-lcQAdVeAO+pBbHD33nIsDsd+QPakLX08tJ82iEsXj6ezyWCfYjE9RY/g9SVq5z4G0NaIkH8039Oe4r0G92DRyA==", - "requires": { - "lodash": "^4.17.21", - "validator": "^13.5.2" - }, - "dependencies": { - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - } - } - }, - "express-winston": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/express-winston/-/express-winston-2.6.0.tgz", - "integrity": "sha512-m4qvQrrIErAZFMQman8CKnQB8sgVG0dSp/wRFv1ZyoWPpP/6waDZywteAdjMF57uJ5+9O7tkwZb5k9w80ZyvAA==", - "requires": { - "chalk": "~0.4.0", - "lodash": "~4.17.5" - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "eyes": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", - "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" - }, - "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==", - "dev": true - }, - "fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true - }, - "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==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fast-safe-stringify": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.8.tgz", - "integrity": "sha512-lXatBjf3WPjmWD6DpIZxkeSsCOwqI0maYMpgDlx8g4U2qi4lbjA9oH/HD2a87G+KfsUmo5WbJFmqBZlPxtptag==", - "dev": true - }, - "fast-text-encoding": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", - "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig==" - }, - "fecha": { - "version": "4.2.1", - "resolved": "http://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz", - "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==", - "dev": true - }, - "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" - } - }, - "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.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - }, - "dependencies": { - "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" - } - } - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.0.0" - } - }, - "flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true - }, - "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.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.1.tgz", - "integrity": "sha512-OMQjaErSFHmHqZe+PSidH5n8j3O0F2DdnVh8JB4j4eUQ2k6KvB0qGfrKIhapvez5JerBbmWkaLYUYWISaESoXg==", - "dev": true - }, - "fn.name": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", - "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", - "dev": true - }, - "follow-redirects": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", - "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==" - }, - "form-data": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", - "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "1.0.6", - "mime-types": "^2.1.12" - } - }, - "formidable": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.1.tgz", - "integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg==", - "dev": true - }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" - }, - "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - } - } - }, - "fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "requires": { - "minipass": "^3.0.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "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==" - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "gaxios": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.3.0.tgz", - "integrity": "sha512-pHplNbslpwCLMyII/lHPWFQbJWOX0B3R1hwBEOvzYi1GmdKZruuEHK4N9V6f7tf1EaPYyF80mui1+344p6SmLg==", - "requires": { - "abort-controller": "^3.0.0", - "extend": "^3.0.2", - "https-proxy-agent": "^5.0.0", - "is-stream": "^2.0.0", - "node-fetch": "^2.3.0" - } - }, - "gcp-metadata": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.3.0.tgz", - "integrity": "sha512-L9XQUpvKJCM76YRSmcxrR4mFPzPGsgZUH+GgHMxAET8qc6+BhRJq63RLhWakgEO2KKVgeSDVfyiNjkGSADwNTA==", - "requires": { - "gaxios": "^4.0.0", - "json-bigint": "^1.0.0" - } - }, - "gcs-resumable-upload": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/gcs-resumable-upload/-/gcs-resumable-upload-3.3.0.tgz", - "integrity": "sha512-MQKWi+9hOSTyg5/SI1NBW4gAjL1wlkoevHefvr1PCBBXH4uKYLsug5qRrcotWKolDPLfWS51cWaHRN0CTtQNZw==", - "requires": { - "abort-controller": "^3.0.0", - "configstore": "^5.0.0", - "extend": "^3.0.2", - "gaxios": "^4.0.0", - "google-auth-library": "^7.0.0", - "pumpify": "^2.0.0", - "stream-events": "^1.0.4" - } - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" - }, - "get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", - "dev": true - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" - }, - "glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "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" - } - }, - "global-dirs": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz", - "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", - "dev": true, - "requires": { - "ini": "1.3.7" - } - }, - "globals": { - "version": "13.10.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.10.0.tgz", - "integrity": "sha512-piHC3blgLGFjvOuMmWZX60f+na1lXFDhQXBf1UYp2fXPXqvEUbOhNwi6BsQ0bQishwedgnjkwv1d9zKf+MWw3g==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - }, - "dependencies": { - "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 - } - } - }, - "google-auth-library": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.3.0.tgz", - "integrity": "sha512-MPeeMlnsYnoiiVFMwX3hgaS684aiXrSqKoDP+xL4Ejg4Z0qLvIeg4XsaChemyFI8ZUO7ApwDAzNtgmhWSDNh5w==", - "requires": { - "arrify": "^2.0.0", - "base64-js": "^1.3.0", - "ecdsa-sig-formatter": "^1.0.11", - "fast-text-encoding": "^1.0.0", - "gaxios": "^4.0.0", - "gcp-metadata": "^4.2.0", - "gtoken": "^5.0.4", - "jws": "^4.0.0", - "lru-cache": "^6.0.0" - } - }, - "google-p12-pem": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.1.1.tgz", - "integrity": "sha512-e9CwdD2QYkpvJsktki3Bm8P8FSGIneF+/42a9F9QHcQvJ73C2RoYZdrwRl6BhwksWtzl65gT4OnBROhUIFw95Q==", - "requires": { - "node-forge": "^0.10.0" - } - }, - "got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "dev": true, - "requires": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - }, - "dependencies": { - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - } - } - }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" - }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true - }, - "gtoken": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.3.0.tgz", - "integrity": "sha512-mCcISYiaRZrJpfqOs0QWa6lfEM/C1V9ASkzFmuz43XBb5s1Vynh+CZy1ECeeJXVGx2PRByjYzb4Y4/zr1byr0w==", - "requires": { - "gaxios": "^4.0.0", - "google-p12-pem": "^3.0.3", - "jws": "^4.0.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" - } - }, - "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-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" - }, - "has-color": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", - "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" - }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" - }, - "has-yarn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", - "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", - "dev": true - }, - "hash-stream-validation": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/hash-stream-validation/-/hash-stream-validation-0.2.4.tgz", - "integrity": "sha512-Gjzu0Xn7IagXVkSu9cSFuK1fqzwtLwFhNhVL8IFJijRNMgUttFbBSIAzKuSIrsFMO1+g1RlsoN49zPIbwPDMGQ==" - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "dev": true - }, - "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - }, - "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - } - }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - }, - "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "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": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", - "dev": true - }, - "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" - } - }, - "import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", - "dev": true - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "ini": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", - "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==", - "dev": true - }, - "ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", - "dev": true - }, - "ipaddr.js": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", - "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==" - }, - "is-arguments": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz", - "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==", - "requires": { - "call-bind": "^1.0.0" - } - }, - "is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", - "dev": true - }, - "is-bigint": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", - "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==" - }, - "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-boolean-object": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", - "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", - "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==" - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } - }, - "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-installed-globally": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", - "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", - "dev": true, - "requires": { - "global-dirs": "^2.0.1", - "is-path-inside": "^3.0.1" - } - }, - "is-ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ip/-/is-ip-2.0.0.tgz", - "integrity": "sha1-aO6gfooKCpTC0IDdZ0xzGrKkYas=", - "dev": true, - "requires": { - "ip-regex": "^2.0.0" - } - }, - "is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==" - }, - "is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==" - }, - "is-npm": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", - "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==", - "dev": true - }, - "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-number-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", - "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==" - }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" - }, - "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-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true - }, - "is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==" - }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" - }, - "is-string": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", - "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==" - }, - "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "requires": { - "has-symbols": "^1.0.1" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true - }, - "is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "iterate-iterator": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.1.tgz", - "integrity": "sha512-3Q6tudGN05kbkDQDI4CqjaBf4qf85w6W6GnuZDtUVYwKgtC1q8yxYX7CZed7N+tLzQqS6roujWvszf13T+n9aw==" - }, - "iterate-value": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz", - "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==", - "requires": { - "es-get-iterator": "^1.0.2", - "iterate-iterator": "^1.0.1" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "json-bigint": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", - "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", - "requires": { - "bignumber.js": "^9.0.0" - } - }, - "json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "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": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", - "requires": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^5.6.0" - }, - "dependencies": { "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" - } + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "requires": { + "jwa": "^2.0.0", + "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==" + }, + "keygrip": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", + "integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==", + "requires": { + "tsscmp": "1.0.6" + } + }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, + "klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11" + } + }, + "kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, + "latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dev": true, + "requires": { + "package-json": "^6.3.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" + } + }, + "libphonenumber-js": { + "version": "1.9.43", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.43.tgz", + "integrity": "sha512-tNB87ZutAiAkl3DE/Bo0Mxqn/XZbNxhPg4v9bYBwQQW4dlhBGqXl1vtmPxeDWbrijzwOA9vRjOOFm5V9SK/W3w==" + }, + "linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "dev": true, + "requires": { + "uc.micro": "^1.0.1" + } + }, + "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" + } }, - "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" - } + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, + "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 + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + } }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + "logform": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.3.0.tgz", + "integrity": "sha512-graeoWUH2knKbGthMtuG1EfaSPMZFZBIrhuJHhkS5ZseFBrc7DupCzihOQAzsK/qIKPQaPJ/lFQFctILUY5ARQ==", + "requires": { + "colors": "^1.2.1", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^1.1.0", + "triple-beam": "^1.3.0" + }, + "dependencies": { + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" + } + } }, - "semver": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" - } - } - }, - "jwa": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", - "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "jws": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", - "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", - "requires": { - "jwa": "^2.0.0", - "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==" - }, - "keygrip": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", - "integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==", - "requires": { - "tsscmp": "1.0.6" - } - }, - "keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "dev": true, - "requires": { - "json-buffer": "3.0.0" - } - }, - "klaw-sync": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", - "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11" - } - }, - "kuler": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", - "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", - "dev": true - }, - "latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", - "dev": true, - "requires": { - "package-json": "^6.3.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" - } - }, - "linkify-it": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.2.tgz", - "integrity": "sha512-gDBO4aHNZS6coiZCKVhSNh43F9ioIL4JwRjLZPkoLIY4yZFwg264Y5lu2x6rb1Js42Gh6Yqm2f6L2AJcnkzinQ==", - "dev": true, - "requires": { - "uc.micro": "^1.0.1" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, - "lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" - }, - "lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" - }, - "lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" - }, - "lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" - }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" - }, - "lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" - }, - "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 - }, - "lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" - }, - "lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, - "log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.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" - } + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, + "lru-cache": { + "version": "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" + } }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } }, - "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" - } + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "markdown-it": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-11.0.1.tgz", + "integrity": "sha512-aU1TzmBKcWNNYvH9pjq6u92BML+Hz3h5S/QpfTFwiQF852pLT+9qHsrhM9JYipkOXZxGn+sGH8oyJE9FD9WezQ==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "entities": "~2.0.0", + "linkify-it": "^3.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + } }, - "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 + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", + "dev": true + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "memory-cache": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/memory-cache/-/memory-cache-0.2.0.tgz", + "integrity": "sha1-eJCwHVLADI68nVM+H46xfjA0hxo=" + }, + "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": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" }, - "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 + "mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==" }, - "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" - } - } - } - }, - "logform": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.2.0.tgz", - "integrity": "sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg==", - "dev": true, - "requires": { - "colors": "^1.2.1", - "fast-safe-stringify": "^2.0.4", - "fecha": "^4.2.0", - "ms": "^2.1.1", - "triple-beam": "^1.3.0" - }, - "dependencies": { - "colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true + "mime-db": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==" + }, + "mime-types": { + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "requires": { + "mime-db": "1.51.0" + } + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } }, - "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 - } - } - }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true - }, - "lru-cache": { - "version": "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" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "requires": { - "semver": "^6.0.0" - } - }, - "markdown-it": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-11.0.1.tgz", - "integrity": "sha512-aU1TzmBKcWNNYvH9pjq6u92BML+Hz3h5S/QpfTFwiQF852pLT+9qHsrhM9JYipkOXZxGn+sGH8oyJE9FD9WezQ==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "entities": "~2.0.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - } - }, - "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", - "dev": true - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" - }, - "memory-cache": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/memory-cache/-/memory-cache-0.2.0.tgz", - "integrity": "sha1-eJCwHVLADI68nVM+H46xfjA0hxo=" - }, - "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": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, - "mime": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", - "dev": true - }, - "mime-db": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" - }, - "mime-types": { - "version": "2.1.18", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", - "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", - "requires": { - "mime-db": "~1.33.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" - }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - }, - "minipass": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", - "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", - "requires": { - "yallist": "^4.0.0" - } - }, - "minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "requires": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - } - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "requires": { - "minimist": "^1.2.5" - }, - "dependencies": { "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - } - } - }, - "mocha": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.0.3.tgz", - "integrity": "sha512-hnYFrSefHxYS2XFGtN01x8un0EwNu2bzKvhpRFhgoybIvMaOkkL60IVPmkb5h6XDmUl4IMSB+rT5cIO4/4bJgg==", - "dev": true, - "requires": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.2", - "debug": "4.3.1", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.1.7", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "3.0.4", - "ms": "2.1.3", - "nanoid": "3.1.23", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "which": "2.0.2", - "wide-align": "1.1.3", - "workerpool": "6.1.5", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "dependencies": { - "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 + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "minipass": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.5.tgz", + "integrity": "sha512-+8NzxD82XQoNKNrl1d/FSi+X8wAEWR+sbYAfIvub4Nz0d22plFG72CEVVaufV8PNf4qSslFTD8VMOxNVhHCjTw==", + "requires": { + "yallist": "^4.0.0" + } }, - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - }, - "dependencies": { - "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 - } - } + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.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" - } + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } }, - "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 + "mocha": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.1.3.tgz", + "integrity": "sha512-Xcpl9FqXOAYqI3j79pEtHBBnQgVXIhpULjGQa7DVb0Po+VzmSIK9kanAiWLHoRR/dbZ2qpdPshuXr8l1VaHCzw==", + "dev": true, + "requires": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.2", + "debug": "4.3.2", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.7", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "nanoid": "3.1.25", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "workerpool": "6.1.5", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "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 + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "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 + } + } + }, + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "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" + } + }, + "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 + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } }, - "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" - } + "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": { + "bson": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", + "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==" + }, + "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" + } + } + } }, - "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" - } + "mongoose": { + "version": "5.13.13", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.13.tgz", + "integrity": "sha512-M55tpCr/p5i6vdJ54nm4MG6/7SKV4JqlWnqbx6yCRuAuW05CZ7u+gNuHVPQVF9dZ59ALXjOtPEUl+OXklAa7ng==", + "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": { + "@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": "*" + } + }, + "bson": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", + "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==" + }, + "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": {} + }, + "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==" + } + } + }, + "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" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "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.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "multer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.3.tgz", + "integrity": "sha512-np0YLKncuZoTzufbkM6wEKp68EhWJXcU6fq6QqrSwkckd2LlMgd1UqhUJLj6NS/5sZ8dE8LYDWslsltJznnXlg==", + "requires": { + "append-field": "^1.0.0", + "busboy": "^0.2.11", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "on-finished": "^2.3.0", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + } + }, + "mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "requires": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "nanoid": { + "version": "3.1.25", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz", + "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "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-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==" + }, + "node-fetch": { + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz", + "integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" + }, + "nodemon": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.15.tgz", + "integrity": "sha512-gdHMNx47Gw7b3kWxJV64NI+Q5nfl0y5DgDbiVtShiwa7Z0IZ07Ll4RLFo6AjrhzMtoEZn5PDE3/c2AbVsiCkpA==", + "dev": true, + "requires": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5", + "update-notifier": "^5.1.0" + }, + "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" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "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 + }, + "normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "dev": true + }, + "npmlog": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.0.tgz", + "integrity": "sha512-03ppFRGlsyUaQFbGC2C8QWJN/C/K7PsfyD9aQdhVKAQIH4sQBc8WASqFBP7O+Ut4d2oo5LoeoboB3cGdBZSp6Q==", + "requires": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.0", + "set-blocking": "^2.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-inspect": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==" + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "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": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "requires": { + "fn.name": "1.x.x" + } + }, + "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-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true }, "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" - } + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "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" - } + "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" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, + "requires": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, + "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" + } + }, + "parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" + }, + "parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "requires": { + "parse5": "^6.0.1" + }, + "dependencies": { + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + } + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "passport": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.1.tgz", + "integrity": "sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg==", + "requires": { + "passport-strategy": "1.x.x", + "pause": "0.0.1" + } + }, + "passport-local": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz", + "integrity": "sha1-H+YyaMkudWBmJkN+O5BmYsFbpu4=", + "requires": { + "passport-strategy": "1.x.x" + } + }, + "passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=" }, "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 + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "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": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true + }, + "pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" + }, + "pg": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.7.1.tgz", + "integrity": "sha512-7bdYcv7V6U3KAtWjpQJJBww0UEsWuh4yQ/EjNf2HeO/NnvKjpvhEIe/A/TleP6wtmSKnUnghs5A9jUoK6iDdkA==", + "requires": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.5.0", + "pg-pool": "^3.4.1", + "pg-protocol": "^1.5.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + } }, - "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 + "pg-connection-string": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", + "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" + }, + "pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" + }, + "pg-pool": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.4.1.tgz", + "integrity": "sha512-TVHxR/gf3MeJRvchgNHxsYsTCHQ+4wm3VIHSS19z8NC0+gioEhq1okDY1sm/TYbfoP6JLFx01s0ShvZ3puP/iQ==", + "requires": {} + }, + "pg-protocol": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", + "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==" + }, + "pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "requires": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + } }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } + "pgpass": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.4.tgz", + "integrity": "sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w==", + "requires": { + "split2": "^3.1.1" + } }, - "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true - } - } - }, - "mongodb": { - "version": "3.6.10", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.10.tgz", - "integrity": "sha512-fvIBQBF7KwCJnDZUnFFy4WqEFP8ibdXeFANnylW19+vOwdjOAvqIzPdsNCEMT6VKTHnYu4K64AWRih0mkFms6Q==", - "requires": { - "bl": "^2.2.1", - "bson": "^1.1.4", - "denque": "^1.4.1", - "optional-require": "^1.0.3", - "safe-buffer": "^5.1.2", - "saslprep": "^1.0.0" - }, - "dependencies": { - "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==" - } - } - }, - "mongoose": { - "version": "5.13.3", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.3.tgz", - "integrity": "sha512-q+zX6kqHAvwxf5speMWhq6qF4vdj+x6/kfD5RSKdZKNm52yGmaUygN+zgrtQjBZPFEzG0B3vF6GP0PoAGadE+w==", - "requires": { - "@types/mongodb": "^3.5.27", - "@types/node": "14.x || 15.x", - "bson": "^1.1.4", - "kareem": "2.3.2", - "mongodb": "3.6.10", - "mongoose-legacy-pluralize": "1.0.2", - "mpath": "0.8.3", - "mquery": "3.2.5", - "ms": "2.1.2", - "regexp-clone": "1.0.0", - "safe-buffer": "5.2.1", - "sift": "13.5.2", - "sliced": "1.0.1" - }, - "dependencies": { - "@types/node": { - "version": "15.14.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.14.2.tgz", - "integrity": "sha512-dvMUE/m2LbXPwlvVuzCyslTEtQ2ZwuuFClDrOQ6mp2CenCg971719PTILZ4I6bTP27xfFFc+o7x2TkLuun/MPw==" + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, + "pngjs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==" + }, + "postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" + }, + "postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=" + }, + "postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" + }, + "postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "requires": { + "xtend": "^4.0.0" + } }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "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 + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + }, + "prettier": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.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==" - } - } - }, - "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==" - }, - "mpath": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.8.3.tgz", - "integrity": "sha512-eb9rRvhDltXVNL6Fxd2zM9D4vKBxjVVQNLNijlj7uoXUy19zNDsIif5zR+pWmPCWNKwAtqyo4JveQm4nfD5+eA==" - }, - "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" - } + "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==" + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "promise.allsettled": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.5.tgz", + "integrity": "sha512-tVDqeZPoBC0SlzJHzWGZ2NKAguVq2oiYj7gbggbiTvH2itHohijTp7njOUA0aQ/nl+0lr/r6egmhoYu63UZ/pQ==", + "requires": { + "array.prototype.map": "^1.0.4", + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "iterate-value": "^1.0.2" + } + }, + "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" + } + }, + "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 + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-2.0.1.tgz", + "integrity": "sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==", + "requires": { + "duplexify": "^4.1.1", + "inherits": "^2.0.3", + "pump": "^3.0.0" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "dev": true, + "requires": { + "escape-goat": "^2.0.0" + } + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" + }, + "qrcode": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.0.tgz", + "integrity": "sha512-9MgRpgVc+/+47dFvQeD6U2s0Z92EsKzcHogtum4QB+UNd025WOJSHvn/hjk9xmzj7Stj95CyUAs31mrjxliEsQ==", + "requires": { + "dijkstrajs": "^1.0.1", + "encode-utf8": "^1.0.3", + "pngjs": "^5.0.0", + "yargs": "^15.3.1" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "qs": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", + "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "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==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "dependencies": { + "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" + } + } + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + } + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "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" + } + }, + "reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" + }, + "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 + }, + "registry-auth-token": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "require-at": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/require-at/-/require-at-1.0.6.tgz", + "integrity": "sha512-7i1auJbMUrXEAZCOQ0VNJgmcT2VOKPRl2YGJwgpHpC9CE91Mv4/4UYIUm4chGJaI381ZDq1JUicFii64Hapd8g==" + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "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 + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==" + }, + "retry-request": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-4.2.2.tgz", + "integrity": "sha512-xA93uxUD/rogV7BV59agW/JHPGXeREMWiZc9jhcwY4YdZ7QOtC7qbomYg0n4wyk2lJhggjvKvhNX8wln/Aldhg==", + "requires": { + "debug": "^4.1.1", + "extend": "^3.0.2" + } + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } }, "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": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "multer": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.2.tgz", - "integrity": "sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg==", - "requires": { - "append-field": "^1.0.0", - "busboy": "^0.2.11", - "concat-stream": "^1.5.2", - "mkdirp": "^0.5.1", - "object-assign": "^4.1.1", - "on-finished": "^2.3.0", - "type-is": "^1.6.4", - "xtend": "^4.0.0" - } - }, - "nanoid": { - "version": "3.1.23", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz", - "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" - }, - "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-addon-api": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", - "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==" - }, - "node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" - }, - "node-forge": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", - "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" - }, - "nodemon": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.12.tgz", - "integrity": "sha512-egCTmNZdObdBxUBw6ZNwvZ/xzk24CKRs5K6d+5zbmrMr7rOpPmfPeF6OxM3DDpaRx331CQRFEktn+wrFFfBSOA==", - "dev": true, - "requires": { - "chokidar": "^3.2.2", - "debug": "^3.2.6", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", - "pstree.remy": "^1.1.7", - "semver": "^5.7.1", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.3", - "update-notifier": "^4.1.0" - }, - "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" - } + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + }, + "safe-stable-stringify": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-1.1.1.tgz", + "integrity": "sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "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" + } }, - "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 + "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 + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "requires": { + "lru-cache": "^6.0.0" + } }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "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 - }, - "normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", - "dev": true - }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "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": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "one-time": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", - "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", - "dev": true, - "requires": { - "fn.name": "1.x.x" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "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-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", - "dev": true - }, - "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", - "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==" - }, - "package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", - "dev": true, - "requires": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.0" - } - }, - "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" - } - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, - "passport": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.1.tgz", - "integrity": "sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg==", - "requires": { - "passport-strategy": "1.x.x", - "pause": "0.0.1" - } - }, - "passport-local": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz", - "integrity": "sha1-H+YyaMkudWBmJkN+O5BmYsFbpu4=", - "requires": { - "passport-strategy": "1.x.x" - } - }, - "passport-strategy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", - "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=" - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "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": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" - }, - "pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true - }, - "pause": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", - "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" - }, - "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true - }, - "pngjs": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", - "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==" - }, - "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 - }, - "prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", - "dev": true - }, - "prettier": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", - "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", - "dev": true - }, - "prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "requires": { - "fast-diff": "^1.1.2" - } - }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "promise.allsettled": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.4.tgz", - "integrity": "sha512-o73CbvQh/OnPFShxHcHxk0baXR2a1m4ozb85ha0H14VEoi/EJJLa9mnPfEWJx9RjA9MLfhdjZ8I6HhWtBa64Ag==", - "requires": { - "array.prototype.map": "^1.0.3", - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "get-intrinsic": "^1.0.2", - "iterate-value": "^1.0.2" - }, - "dependencies": { - "es-abstract": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", - "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.10.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - } + "semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dev": true, + "requires": { + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "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" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } }, - "is-callable": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==" + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } }, - "is-regex": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", - "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", - "requires": { - "call-bind": "^1.0.2", - "has-symbols": "^1.0.2" - } + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "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" + } }, - "object-inspect": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", - "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==" + "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" + } }, - "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - } + "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==" + }, + "signal-exit": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", + "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==" + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "requires": { + "is-arrayish": "^0.3.1" + } }, - "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } }, - "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - } - } - }, - "proxy-addr": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", - "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", - "requires": { - "forwarded": "~0.1.2", - "ipaddr.js": "1.9.0" - } - }, - "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 - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "pumpify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-2.0.1.tgz", - "integrity": "sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==", - "requires": { - "duplexify": "^4.1.1", - "inherits": "^2.0.3", - "pump": "^3.0.0" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "pupa": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", - "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", - "dev": true, - "requires": { - "escape-goat": "^2.0.0" - } - }, - "q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" - }, - "qrcode": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.4.4.tgz", - "integrity": "sha512-oLzEC5+NKFou9P0bMj5+v6Z40evexeE29Z9cummZXZ9QXyMr3lphkURzxjXgPJC5azpxcshoDWV1xE46z+/c3Q==", - "requires": { - "buffer": "^5.4.3", - "buffer-alloc": "^1.2.0", - "buffer-from": "^1.1.1", - "dijkstrajs": "^1.0.1", - "isarray": "^2.0.1", - "pngjs": "^3.3.0", - "yargs": "^13.2.4" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + "sliced": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", + "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" + }, + "snakeize": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/snakeize/-/snakeize-0.1.0.tgz", + "integrity": "sha1-EMCI2LWOsHazIpu1oE4jLOEmQi0=" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", + "optional": true, + "requires": { + "memory-pager": "^1.0.2" + } }, - "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" - } + "split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "requires": { + "readable-stream": "^3.0.0" + } }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "stream-events": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", + "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", + "requires": { + "stubs": "^3.0.0" + } }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "streamsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" }, - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } }, "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } }, "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" - } + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - } + "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 + }, + "stubs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", + "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=" + }, + "superagent": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", + "integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==", + "dev": true, + "requires": { + "component-emitter": "^1.2.0", + "cookiejar": "^2.1.0", + "debug": "^3.1.0", + "extend": "^3.0.0", + "form-data": "^2.3.1", + "formidable": "^1.2.0", + "methods": "^1.1.1", + "mime": "^1.4.1", + "qs": "^6.5.1", + "readable-stream": "^2.3.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" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "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==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } }, - "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.1" - } - } - } - }, - "qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", - "dev": true - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "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==" - }, - "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "dependencies": { - "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" - } - } - } - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - } - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "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" - } - }, - "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" - } - }, - "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 - }, - "registry-auth-token": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", - "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", - "dev": true, - "requires": { - "rc": "^1.2.8" - } - }, - "registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", - "dev": true, - "requires": { - "rc": "^1.2.8" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" - }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" - }, - "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 - }, - "responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", - "dev": true, - "requires": { - "lowercase-keys": "^1.0.0" - } - }, - "retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" - }, - "retry-request": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-4.2.2.tgz", - "integrity": "sha512-xA93uxUD/rogV7BV59agW/JHPGXeREMWiZc9jhcwY4YdZ7QOtC7qbomYg0n4wyk2lJhggjvKvhNX8wln/Aldhg==", - "requires": { - "debug": "^4.1.1", - "extend": "^3.0.2" - } - }, - "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" - } - }, - "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "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" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - }, - "semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", - "dev": true, - "requires": { - "semver": "^6.3.0" - } - }, - "send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", - "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.7.2", - "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "dependencies": { - "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" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } + "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==", + "requires": { + "has-flag": "^4.0.0" + } }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + "table": { + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.3.tgz", + "integrity": "sha512-5DkIxeA7XERBqMwJq0aHZOdMadBx4e6eDoFRuyT5VR82J0Ycg2DwM6GfA/EQAhJ+toRTaS1lIdSQCqgrmhPnlw==", + "dev": true, + "requires": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "ajv": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.8.2.tgz", + "integrity": "sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - } - } - }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.1" - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - }, - "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 - }, - "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==" - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" - }, - "simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", - "dev": true, - "requires": { - "is-arrayish": "^0.3.1" - } - }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.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" - } + "tar": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + } + } }, - "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" - } + "teeny-request": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-7.1.3.tgz", + "integrity": "sha512-Ew3aoFzgQEatLA5OBIjdr1DWJUaC1xardG+qbPPo5k/y/3fMwXLxpjh5UB5dVfElktLaQbbMs80chkz53ByvSg==", + "requires": { + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "stream-events": "^1.0.5", + "uuid": "^8.0.0" + } }, - "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 + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "requires": { + "any-promise": "^1.0.0" + } }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - } - } - }, - "sliced": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", - "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" - }, - "snakeize": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/snakeize/-/snakeize-0.1.0.tgz", - "integrity": "sha1-EMCI2LWOsHazIpu1oE4jLOEmQi0=" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "sparse-bitfield": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", - "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", - "optional": true, - "requires": { - "memory-pager": "^1.0.2" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" - }, - "stream-events": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", - "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", - "requires": { - "stubs": "^3.0.0" - } - }, - "stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" - }, - "streamsearch": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", - "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "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" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - }, - "stubs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", - "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=" - }, - "superagent": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", - "integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==", - "dev": true, - "requires": { - "component-emitter": "^1.2.0", - "cookiejar": "^2.1.0", - "debug": "^3.1.0", - "extend": "^3.0.0", - "form-data": "^2.3.1", - "formidable": "^1.2.0", - "methods": "^1.1.1", - "mime": "^1.4.1", - "qs": "^6.5.1", - "readable-stream": "^2.3.5" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } + "thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", + "requires": { + "thenify": ">= 3.1.0 < 4" + } }, - "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": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "table": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", - "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", - "dev": true, - "requires": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.6.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.2.tgz", - "integrity": "sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true + }, + "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" + } }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "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" + }, + "dependencies": { + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "dev": true, + "requires": { + "abbrev": "1" + } + } + } }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, + "ts-node": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.4.0.tgz", + "integrity": "sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "0.7.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "yn": "3.1.1" + }, + "dependencies": { + "acorn": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz", + "integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==", + "dev": true + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + } + } }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true + "tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + }, + "tsscmp": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", + "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==" + }, + "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" + } }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } + "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 }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } - } - }, - "tar": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", - "integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==", - "requires": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "dependencies": { - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" - } - } - }, - "teeny-request": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-7.1.1.tgz", - "integrity": "sha512-iwY6rkW5DDGq8hE2YgNQlKbptYpY5Nn2xecjQiNjOXWbKzPGUfmeUBCSQbbr306d7Z7U2N0TPl+/SwYRfua1Dg==", - "requires": { - "http-proxy-agent": "^4.0.0", - "https-proxy-agent": "^5.0.0", - "node-fetch": "^2.6.1", - "stream-events": "^1.0.5", - "uuid": "^8.0.0" - } - }, - "term-size": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", - "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", - "dev": true - }, - "text-hex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", - "dev": true - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", - "dev": true - }, - "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.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" - }, - "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" - }, - "dependencies": { - "nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", - "dev": true, - "requires": { - "abbrev": "1" - } - } - } - }, - "triple-beam": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", - "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==", - "dev": true - }, - "tsscmp": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", - "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==" - }, - "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-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "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" - }, - "dependencies": { - "mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" + "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" + } }, - "mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", - "requires": { - "mime-db": "1.40.0" - } - } - } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "dev": true - }, - "uglify-js": { - "version": "3.13.9", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.9.tgz", - "integrity": "sha512-wZbyTQ1w6Y7fHdt8sJnHfSIuWeDgk6B5rCb4E/AM6QNNPbOMIZph21PW5dRB3h7Df0GszN+t7RuUH6sWK5bF0g==", - "optional": true - }, - "unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - }, - "dependencies": { - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" - } - } - }, - "undefsafe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", - "integrity": "sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==", - "dev": true, - "requires": { - "debug": "^2.2.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "requires": { - "crypto-random-string": "^2.0.0" - } - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, - "update-notifier": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz", - "integrity": "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==", - "dev": true, - "requires": { - "boxen": "^4.2.0", - "chalk": "^3.0.0", - "configstore": "^5.0.1", - "has-yarn": "^2.1.0", - "import-lazy": "^2.1.0", - "is-ci": "^2.0.0", - "is-installed-globally": "^0.3.1", - "is-npm": "^4.0.0", - "is-yarn-global": "^0.3.0", - "latest-version": "^5.0.0", - "pupa": "^2.0.1", - "semver-diff": "^3.1.1", - "xdg-basedir": "^4.0.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" - } + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } + "typeorm": { + "version": "0.2.41", + "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.2.41.tgz", + "integrity": "sha512-/d8CLJJxKPgsnrZWiMyPI0rz2MFZnBQrnQ5XP3Vu3mswv2WPexb58QM6BEtmRmlTMYN5KFWUz8SKluze+wS9xw==", + "requires": { + "@sqltools/formatter": "^1.2.2", + "app-root-path": "^3.0.0", + "buffer": "^6.0.3", + "chalk": "^4.1.0", + "cli-highlight": "^2.1.11", + "debug": "^4.3.1", + "dotenv": "^8.2.0", + "glob": "^7.1.6", + "js-yaml": "^4.0.0", + "mkdirp": "^1.0.4", + "reflect-metadata": "^0.1.13", + "sha.js": "^2.4.11", + "tslib": "^2.1.0", + "xml2js": "^0.4.23", + "yargs": "^17.0.1", + "zen-observable-ts": "^1.0.0" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "dotenv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==" + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, + "yargs": { + "version": "17.2.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.2.1.tgz", + "integrity": "sha512-XfR8du6ua4K6uLGm5S6fA+FIJom/MdJcFNVY8geLlp2v8GYbOXD4EB1tPNZsRn4vBzKGMgb5DRZMeWuFc2GO8Q==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + } + } }, - "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" - } + "typescript": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz", + "integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==" + }, + "uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true + }, + "uglify-js": { + "version": "3.14.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.3.tgz", + "integrity": "sha512-mic3aOdiq01DuSVx0TseaEzMIVqebMZ0Z3vaeDhFEh9bsc24hV1TFvN74reA2vs08D0ZWfNjAcJ3UbVLaBss+g==", + "optional": true + }, + "unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } }, - "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 + "undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "requires": { + "crypto-random-string": "^2.0.0" + } }, - "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 + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "update-notifier": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", + "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", + "dev": true, + "requires": { + "boxen": "^5.0.0", + "chalk": "^4.1.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.4.0", + "is-npm": "^5.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.1.0", + "pupa": "^2.1.1", + "semver": "^7.3.4", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + } }, - "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" - } - } - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", - "dev": true, - "requires": { - "prepend-http": "^2.0.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" - }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "validator": { - "version": "13.6.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.6.0.tgz", - "integrity": "sha512-gVgKbdbHgtxpRyR8K0O6oFZPhhB5tT1jeEHZR0Znr9Svg03U0+r9DXWMrnRAB+HtCStDQKlaIZm42tVsVjqtjg==" - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" - }, - "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" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" - }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "dev": true, - "requires": { - "string-width": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "requires": { + "prepend-http": "^2.0.0" + } }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "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": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } + "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" + } }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } - } - }, - "winston": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.5.tgz", - "integrity": "sha512-TWoamHt5yYvsMarGlGEQE59SbJHqGsZV8/lwC+iCcGeAe0vUaOh+Lv6SYM17ouzC/a/LB1/hz/7sxFBtlu1l4A==", - "requires": { - "async": "~1.0.0", - "colors": "1.0.x", - "cycle": "1.0.x", - "eyes": "0.1.x", - "isstream": "0.1.x", - "stack-trace": "0.0.x" - }, - "dependencies": { - "async": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", - "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=" - } - } - }, - "winston-transport": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", - "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==", - "dev": true, - "requires": { - "readable-stream": "^2.3.7", - "triple-beam": "^1.2.0" - }, - "dependencies": { - "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==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - } - } - }, - "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": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" - }, - "workerpool": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.5.tgz", - "integrity": "sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw==", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } }, - "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" - } + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } }, - "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" - } + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "requires": { + "string-width": "^4.0.0" + } }, - "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 + "winston": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", + "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==", + "requires": { + "@dabh/diagnostics": "^2.0.2", + "async": "^3.1.0", + "is-stream": "^2.0.0", + "logform": "^2.2.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.4.0" + } }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "winston-transport": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", + "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==", + "requires": { + "readable-stream": "^2.3.7", + "triple-beam": "^1.2.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "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" + } + }, + "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==" + }, + "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" + } + } + } }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true + "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 }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==" - }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" - }, - "y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true + "workerpool": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.5.tgz", + "integrity": "sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw==", + "dev": true }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==" + }, + "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" + } }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.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==" }, "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } }, "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true - } - } - }, - "yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" - } - } - }, - "yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "requires": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "dependencies": { - "camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "dev": true + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==" + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + } }, - "decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + }, + "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==" + }, + "zen-observable": { + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz", + "integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==" + }, + "zen-observable-ts": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.1.0.tgz", + "integrity": "sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA==", + "requires": { + "@types/zen-observable": "0.8.3", + "zen-observable": "0.8.15" + } } - } - }, - "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==" } - } } diff --git a/package.json b/package.json index 5f854b30..c2f697e7 100644 --- a/package.json +++ b/package.json @@ -3,23 +3,22 @@ "version": "3.1.3", "private": true, "scripts": { - "start": "DEBUG=hackboard:* NODE_ENV=test nodemon --ignore gcp_creds.json ./bin/www.js", + "build": "tsc", + "start": "DEBUG=hackboard:* NODE_ENV=test rimraf dist/ && tsc && cp .env ./dist/.env && nodemon --ignore gcp_creds.json ./dist/bin/www.js", "start-windows": "set DEBUG=hackboard:* && set NODE_ENV=test && nodemon --ignore gcp_creds.json ./bin/www.js", "deploy": "NODE_ENV=deployment node ./bin/www.js", "debug": "DEBUG=hackboard:* NODE_ENV=test nodemon --ignore gcp_creds.json ./bin/www.js", - "test": "DEBUG=hackboard:* NODE_ENV=test mocha --reporter spec tests/**.js --exit", + "test": "DEBUG=hackboard:* NODE_ENV=test mocha --parallel --reporter spec tests/**.js --exit", "seed": "NODE_ENV=test node ./seed/index.js", "docs": "apidoc -i ./routes -o ./docs/api/", "format": "prettier --write '**/*.js'", "lint": "eslint --fix '**/*.js'" }, - "engines": { - "node": "14.x" - }, "dependencies": { "@google-cloud/storage": "^5.10.0", "@sendgrid/mail": "^7.4.5", "bcrypt": "^5.0.1", + "class-validator": "^0.13.2", "cookie-parser": "^1.4.5", "cookie-session": "^2.0.0-rc.1", "cors": "^2.8.5", @@ -28,7 +27,7 @@ "dotenv": "^10.0.0", "express": "~4.17.1", "express-validator": "^6.12.0", - "express-winston": "^2.6.0", + "express-winston": "^4.2.0", "handlebars": "^4.7.7", "jsonwebtoken": "^8.5.1", "memory-cache": "^0.2.0", @@ -36,17 +35,27 @@ "multer": "^1.4.2", "passport": "^0.4.1", "passport-local": "^1.0.0", + "pg": "^8.7.1", "promise.allsettled": "^1.0.4", "q": "^1.5.1", "qrcode": "^1.4.4", - "winston": "^2.4.5" + "reflect-metadata": "^0.1.13", + "typeorm": "^0.2.41", + "typescript": "^4.5.2", + "winston": "^3.3.3" }, "devDependencies": { + "@types/bcrypt": "^5.0.0", "@types/express": "^4.17.13", + "@types/express-winston": "^4.0.0", "@types/google-cloud__storage": "^1.7.2", "@types/mongodb": "^3.6.20", "@types/mongoose": "^5.11.97", "@types/multer": "^1.4.7", + "@types/passport": "^1.0.7", + "@types/passport-local": "^1.0.34", + "@types/superagent": "^4.1.13", + "@types/validator": "^13.7.0", "apidoc": "^0.28.1", "chai": "^4.3.4", "chai-http": "^4.3.0", @@ -55,6 +64,7 @@ "eslint-plugin-prettier": "3.4.0", "mocha": "^9.0.3", "nodemon": "^2.0.12", - "prettier": "1.19.1" + "prettier": "1.19.1", + "rimraf": "^3.0.2" } } diff --git a/services/account.service.js b/services/account.service.js deleted file mode 100644 index 8c7a74b3..00000000 --- a/services/account.service.js +++ /dev/null @@ -1,158 +0,0 @@ -"use strict"; -const Hacker = require("../models/hacker.model"); -const Account = require("../models/account.model"); -const logger = require("./logger.service"); -const bcrypt = require("bcrypt"); - -/** - * @function findById - * @param {ObjectId} id - * @return {DocumentQuery} The document query will resolve to either account or null. - * @description Finds an account by mongoID. - */ -function findById(id) { - const TAG = `[Account Service # findById]:`; - const query = { - _id: id - }; - return Account.findById( - query, - logger.queryCallbackFactory(TAG, "account", query) - ); -} - -/** - * @function findByHackerId - * @param {ObjectId} id the Hacker's ID - * @returns {Promise} The account of the hacker, minus the password. Returns null if the hacker does not exist, or if the hacker is not associated with an account. - * Get the account by using the hacker's ID. - */ -async function findByHackerId(id) { - const TAG = `[Account Service # findByHackerId]:`; - const query = { - _id: id - }; - const hacker = await Hacker.findById( - query, - logger.queryCallbackFactory(TAG, "account", query) - ).populate({ - path: "accountId", - select: " -password" - }); - if (!hacker || !hacker.accountId) { - return null; - } - return hacker.accountId; -} - -/** - * @function findByEmail - * @param {String} email - * @return {DocumentQuery} The document query will resolve to either account or null. - * @description Find an account by email. - */ -function findByEmail(email) { - const query = { - email: email - }; - - return findOne(query); -} - -/** - * @param {String} email - * @param {String} password - * @return {Account | null} either account or null - */ -async function getAccountIfValid(email, password) { - const account = await findByEmail(email); - - if (!!account && account.comparePassword(password)) { - return account; - } - return null; -} - -/** - * @function hashPassword - * @param {String} password - * @return {string} hashed password - * @description Hashes password with bcrypt. - */ -function hashPassword(password) { - return bcrypt.hashSync(password, 10); -} - -/** - * @function findOne - * @param {*} query - * @return {DocumentQuery} The document query will resolve to either account or null. - * @description Finds an account by some query. - */ -function findOne(query) { - const TAG = `[Account Service # findOne ]:`; - - return Account.findOne( - query, - logger.queryCallbackFactory(TAG, "account", query) - ); -} - -/** - * @function addOneAccount - * @param {{_id: ObjectId, firstName: string, lastName: string, email: string, password: string}} accountDetails - * @return {Promise} The promise will resolve to the account object if save is successful. - * @description Adds a new account to database. - */ -function addOneAccount(accountDetails) { - const TAG = `[Account Service # addOneAccount ]:`; - - const account = new Account(accountDetails); - - return account.save(); -} - -/** - * @function updateOne - * @param {ObjectId} id - * @param {{_id?: ObjectId, firstName?: string, lastName?: string, email?: string, password?: string}} accountDetails - * @return {DocumentQuery} The document query will resolve to either account or null. - * @description Changes account information to the specified information in accountDetails. - */ -function updateOne(id, accountDetails) { - const TAG = `[Account Service # updateOne ]:`; - - const query = { - _id: id - }; - - return Account.findOneAndUpdate( - query, - accountDetails, - logger.updateCallbackFactory(TAG, "account") - ); -} - -/** - * Updates the password for an account. This function also hashes the password. - * @param {ObjectId} id String representing the ObjectId of the account - * @param {string} newPassword the new password for the account (in plain-text). - */ -function updatePassword(id, newPassword) { - const hashed = hashPassword(newPassword); - return updateOne(id, { - password: hashed - }); -} - -module.exports = { - findOne: findOne, - findById: findById, - findByHackerId: findByHackerId, - findByEmail: findByEmail, - addOneAccount: addOneAccount, - getAccountIfValid: getAccountIfValid, - hashPassword: hashPassword, - updateOne: updateOne, - updatePassword: updatePassword -}; diff --git a/services/account.service.ts b/services/account.service.ts new file mode 100644 index 00000000..7e60f4c2 --- /dev/null +++ b/services/account.service.ts @@ -0,0 +1,146 @@ +const Hacker = require("../models/hacker.model"); +import Account from "../models/account.model"; +import * as logger from "./logger.service"; +import { hashSync } from "bcrypt"; + +/** + * @function findById + * @param {Number} id + * @return {Account} Will resolve to either account or null. + * @description Finds an account by identifier. + */ +async function findById(id: number): Promise { + const TAG = `[Account Service # findById]:`; + return await Account.findOne(id).then((account) => { + logger.queryCallbackFactory(TAG, "account", id); + return account; + }); +} + +/** + * @function findByHackerId + * @param {number} identifier the Hacker's ID + * @returns {Promise} The account of the hacker, minus the password. Returns null if the hacker does not exist, or if the hacker is not associated with an account. + * Get the account by using the hacker's ID. + */ +//TODO: Complete this message. +async function findByHackerId(identifier: number) { + const TAG = `[Account Service # findByHackerId]:`; + const query = { + _id: identifier + }; + const hacker = await Hacker.findById( + query, + logger.queryCallbackFactory(TAG, "account", query) + ).populate({ + path: "accountId", + select: " -password" + }); + if (!hacker || !hacker.accountId) { + return null; + } + return hacker.accountId; +} + +/** + * @function findByEmail + * @param {String} email + * @return {Account} Will resolve to either account or null. + * @description Find an account by email. + */ +function findByEmail(email: string) { + const query = { email: email }; + + return findOne(query); +} + +/** + * @param {String} email + * @param {String} password + * @return {Account | null} either account or null + */ +async function getAccountIfValid(email: string, password: string) { + const account = await findByEmail(email); + + return !!account && account.comparePassword(password) ? account : null; +} + +/** + * @function hashPassword + * @param {String} password + * @return {string} hashed password + * @description Hashes password with bcrypt. + */ +function hashPassword(password: string) { + return hashSync(password, 10); +} + +/** + * @function findOne + * @param {*} query + * @return {Account} Will resolve to either account or null. + * @description Finds an account by some query. + */ +function findOne(query: Object): Promise { + const TAG = `[Account Service # findOne ]:`; + + return Account.findOne(query).then((account) => { + logger.queryCallbackFactory(TAG, "account", query); + return account; + }); +} + +/** + * @function addOneAccount + * @param {{identifier: number, firstName: string, lastName: string, email: string, password: string}} accountDetails + * @return {Promise} The promise will resolve to the account object if save is successful. + * @description Adds a new account to database. + */ +//TODO: Make all functions that call this async. +async function addOneAccount(accountDetails: Object): Promise { + const TAG = `[Account Service # addOneAccount ]:`; + + const account = Account.create(accountDetails); + + return await account.save(); +} + +/** + * @function updateOne + * @param {number} identifier + * @param {{identifier?: number, firstName?: string, lastName?: string, email?: string, password?: string}} accountDetails + * @return {DocumentQuery} The document query will resolve to either account or null. + * @description Changes account information to the specified information in accountDetails. + */ +function updateOne(identifier: number, accountDetails: Object) { + const TAG = `[Account Service # updateOne ]:`; + + return Account.update(identifier, accountDetails).then((account) => { + logger.updateCallbackFactory(TAG, "account"); + return account; + }); +} + +/** + * Updates the password for an account. This function also hashes the password. + * @param {number} identifier String representing the ObjectId of the account + * @param {string} newPassword the new password for the account (in plain-text). + */ +async function updatePassword(identifier: number, newPassword: string) { + const hashed = hashPassword(newPassword); + return await updateOne(identifier, { + password: hashed + }); +} + +export { + findOne, + findById, + findByHackerId, + findByEmail, + addOneAccount, + getAccountIfValid, + hashPassword, + updateOne, + updatePassword +}; diff --git a/services/accountConfirmation.service.js b/services/accountConfirmation.service.ts similarity index 67% rename from services/accountConfirmation.service.js rename to services/accountConfirmation.service.ts index 25e92604..7700c315 100644 --- a/services/accountConfirmation.service.js +++ b/services/accountConfirmation.service.ts @@ -1,6 +1,6 @@ -"use strict"; const logger = require("./logger.service"); -const AccountConfirmation = require("../models/accountConfirmationToken.model"); +import AccountConfirmation from "../models/accountConfirmationToken.model"; +import { findById as findByIdAccountService } from "./account.service"; const Constants = require("../constants/general.constant"); const jwt = require("jsonwebtoken"); const path = require("path"); @@ -10,46 +10,54 @@ const Services = { /** * @function findByAccountId - * @param {ObjectId} accountId - * @return {DocumentQuery} The document query will resolve to either account confirmation or null. + * @param {number} identifier + * @return {Promise} The document query will resolve to either account confirmation or null. * @description Finds an account confirmation document by accountId. */ -function findByAccountId(accountId) { +async function findByAccountId( + identifier: number +): Promise { const TAG = `[ AccountConfirmation Reset Service # findByAccountId ]`; - return AccountConfirmation.findOne( - { - accountId: accountId - }, - logger.queryCallbackFactory(TAG, "AccountConfirmation", "accountId") - ); + + return await AccountConfirmation.findOne({ + where: { account: identifier } + }).then((accountConfirmation) => { + logger.queryCallbackFactory(TAG, "AccountConfirmation", "accountId"); + return accountConfirmation; + }); } /** * @function findById - * @param {ObjectId} id - * @return {DocumentQuery} The document query will resolve to either account confirmation or null. + * @param {number} identifier + * @return {Promise} The document query will resolve to either account confirmation or null. * @description Finds an account by mongoID. */ -function findById(id) { +async function findById( + identifier: number +): Promise { const TAG = `[ AccountConfirmation Service # findById ]`; - return AccountConfirmation.findById( - id, - logger.queryCallbackFactory(TAG, "AccountConfirmation", "mongoId") - ); + return await AccountConfirmation.findOne({ + where: { identifier: identifier } + }).then((accountConfirmation) => { + logger.queryCallbackFactory(TAG, "AccountConfirmation", "identifier"); + return accountConfirmation; + }); } /** * @function find * @param {*} query the query to search the database by. - * @return {DocumentQuery} The document query will resolve to either account confirmations or null. + * @return {Promise} The document query will resolve to either account confirmations or null. * @description Finds an account by query. */ -function find(query) { +async function find(query: Object): Promise { const TAG = `[ AccountConfirmation Service # find ]`; - return AccountConfirmation.find( - query, - logger.queryCallbackFactory(TAG, "AccountConfirmation", query) - ); + + return await AccountConfirmation.find(query).then((accountConfirmation) => { + logger.queryCallbackFactory(TAG, "AccountConfirmation", query); + return accountConfirmation; + }); } /** @@ -57,29 +65,31 @@ function find(query) { * @param {String} type the type of user which to create the token for * @param {String} email * @param {"Invite"|"Organic"} confirmationType whether this confirmation token is for an organic acct creation, or an invited account - * @param {ObjectId} accountId optional accountId parameter to link to account, optional when token is being made for not a hacker + * @param {number} accountId optional accountId parameter to link to account, optional when token is being made for not a hacker * @returns {Promise.<*>} */ -async function create(type, email, confirmationType, accountId) { - //Create new instance of account confirmation - const newAccountToken = AccountConfirmation({ +async function create( + type: string, + email: string, + confirmationType: string, + accountId: number +): Promise { + const newAccountToken = await AccountConfirmation.create({ accountType: type, email: email, - confirmationType: confirmationType + confirmationType: confirmationType, + account: await findByIdAccountService(accountId) }); - if (accountId !== undefined) { - newAccountToken.accountId = accountId; - } return newAccountToken.save(); } /** * Generates JWT for Confirming account - * @param {ObjectId} accountConfirmationId - * @param {ObjectId} accountId + * @param {number} accountConfirmationId + * @param {number} accountId * @returns {string} JWT Token containing accountId and accountConfirmationId */ -function generateToken(accountConfirmationId, accountId = null) { +function generateToken(accountConfirmationId: number, accountId = null) { const token = jwt.sign( { accountConfirmationId: accountConfirmationId, @@ -101,7 +111,12 @@ function generateToken(accountConfirmationId, accountId = null) { * @param {string} token the reset token * @returns {string} the string, of form: [http|https]://{domain}/{model}/create?token={token} */ -function generateCreateAccountTokenLink(httpOrHttps, domain, type, token) { +function generateCreateAccountTokenLink( + httpOrHttps: string, + domain: string, + type: string, + token: string +): string { const link = `${httpOrHttps}://${domain}/account/create?token=${token}&accountType=${type}`; return link; } @@ -114,7 +129,11 @@ function generateCreateAccountTokenLink(httpOrHttps, domain, type, token) { * @param {string} token the reset token * @returns {string} the string, of form: [http|https]://{domain}/{model}/create?token={token} */ -function generateConfirmTokenLink(httpOrHttps, domain, token) { +function generateConfirmTokenLink( + httpOrHttps: string, + domain: string, + token: string +): string { const link = `${httpOrHttps}://${domain}/account/confirm?token=${token}`; return link; } @@ -126,7 +145,12 @@ function generateConfirmTokenLink(httpOrHttps, domain, token) { * @param {string} type the user type * @param {string} token The account confirmation token */ -function generateAccountConfirmationEmail(address, receiverEmail, type, token) { +function generateAccountConfirmationEmail( + address: string, + receiverEmail: string, + type: string, + token: string +): Object | undefined { const httpOrHttps = address.includes("localhost") ? "http" : "https"; const tokenLink = generateConfirmTokenLink(httpOrHttps, address, token); var emailSubject = ""; @@ -159,7 +183,12 @@ function generateAccountConfirmationEmail(address, receiverEmail, type, token) { * @param {string} type The user type * @param {string} token The account confirmation token */ -function generateAccountInvitationEmail(address, receiverEmail, type, token) { +function generateAccountInvitationEmail( + address: string, + receiverEmail: string, + type: string, + token: string +) { const httpOrHttps = address.includes("localhost") ? "http" : "https"; const tokenLink = generateCreateAccountTokenLink( httpOrHttps, @@ -194,12 +223,13 @@ function generateAccountInvitationEmail(address, receiverEmail, type, token) { }; return mailData; } -module.exports = { - find: find, - findById: findById, - findByAccountId: findByAccountId, - create: create, - generateToken: generateToken, - generateAccountConfirmationEmail: generateAccountConfirmationEmail, - generateAccountInvitationEmail: generateAccountInvitationEmail + +export { + find, + findById, + findByAccountId, + create, + generateToken, + generateAccountConfirmationEmail, + generateAccountInvitationEmail }; diff --git a/services/auth.service.js b/services/auth.service.ts similarity index 68% rename from services/auth.service.js rename to services/auth.service.ts index 5b4799d9..0be8b9ff 100644 --- a/services/auth.service.js +++ b/services/auth.service.ts @@ -1,51 +1,55 @@ -"use strict"; -const LocalStrategy = require("passport-local").Strategy; -const Account = require("../services/account.service"); +import { Request } from "express"; +import Account from "../models/account.model"; +import Role, { RouteSchema } from "../models/role.model"; + +import { Strategy as LocalStrategy } from "passport-local"; +const { getAccountIfValid, findById } = require("../services/account.service"); const RoleBinding = require("../services/roleBinding.service"); -const logger = require("./logger.service"); +import * as logger from "./logger.service"; -module.exports = { - emailAndPassStrategy: new LocalStrategy( - { - usernameField: "email", - passwordField: "password" - }, - function(email, password, done) { - email = email.toLowerCase(); - Account.getAccountIfValid(email, password).then( - (account) => { - if (account) { - done(null, account); - } else { - done(null, false); - } - }, - (reason) => { - done(reason, false); +const emailAndPassStrategy = new LocalStrategy( + { + usernameField: "email", + passwordField: "password" + }, + (email: string, password: string, done: any) => { + email = email.toLowerCase(); + getAccountIfValid(email, password).then( + (account: Account) => { + if (account) { + done(null, account); + } else { + done(null, false); } - ); - } - ), - /** - * Takes as input the id of the user. If the user id exists, it passes the user object to the callback - * (done). The two arguments of the callback must be (failureReason, userObject). If there is no user, - * then the userObject will be undefined. - */ - deserializeUser: function(id, done) { - Account.findById(id).then( - (user) => { - done(null, user); }, - (reason) => { - done(reason); + (reason: Object) => { + done(reason, false); } ); - }, - serializeUser: function(user, done) { - done(null, user.id); - }, - ensureAuthorized: ensureAuthorized -}; + } +); + +function deserializeUser(identifier: number, done: any) { + findById(identifier).then( + (user: Account) => { + done(null, user); + }, + (reason: Object) => { + done(reason); + } + ); +} + +/** + * Takes as input the id of the user. If the user id exists, it passes the user object to the callback + * (done). The two arguments of the callback must be (failureReason, userObject). If there is no user, + * then the userObject will be undefined. + */ +function serializeUser(user: Account, done: any) { + done(null, user.identifier); +} + +export { emailAndPassStrategy, deserializeUser, serializeUser }; /** * @param {{params: string[], baseUrl: string, path: string, user: {id: string}}} req request object passed in by Express.js @@ -59,8 +63,10 @@ module.exports = { // size of findByIdFns needs to match the number of route parameters // to check for :all, just replace :all with the paramID (AKA resource ID) -async function ensureAuthorized(req, findByIdFns) { +export async function ensureAuthorized(req: Request, findByIdFns: any) { // if number of params doesn't match number of findById functions, fail + //TODO - req.params is a ParamDictionary not string[] + //@ts-ignore if (!verifyParamsFunctions(req.params, findByIdFns)) { return false; } @@ -75,16 +81,19 @@ async function ensureAuthorized(req, findByIdFns) { const splitPath = path.split("/"); // if account doesn't have a role binding, then not authenticated - const roleBinding = await RoleBinding.getRoleBindingForAcct(req.user.id); + const roleBinding = await RoleBinding.getRoleBindingForAcct( + //@ts-ignore TODO - User has no identifier field in express.User + req.user?.identifier + ); if (!roleBinding) { return false; } // get the route ids - const twoDRoutes = roleBinding.roles.map((role) => { + const twoDRoutes = roleBinding.roles.map((role: Role) => { return role.routes; }); - const routes = [].concat(...twoDRoutes); + const routes: RouteSchema[] = [].concat(...twoDRoutes); // each route is an object with an uri and a request type // for each uri, separate by '/', check each section to see if it's the same as requested uri @@ -125,7 +134,8 @@ async function ensureAuthorized(req, findByIdFns) { currentlyValid = await verifySelfCase( findByIdFns[findByParamCount], splitPath[i], - req.user.id + //@ts-ignore TODO - User has no identifier field in express.User + req.user?.identifier ); findByParamCount += 1; break; @@ -154,7 +164,10 @@ async function ensureAuthorized(req, findByIdFns) { * @param {string[]} params List of route parameters * @return {boolean} Whether the number of route parameters matches with the number of idFns */ -function verifyParamsFunctions(params, idFns) { +function verifyParamsFunctions( + params: string[], + idFns: ((param: string) => object)[] +) { let numParams = Object.values(params).length; let validRoute = true; @@ -171,21 +184,26 @@ function verifyParamsFunctions(params, idFns) { * Uses param with idFunction to check whether the returned object is the user account, or is linked to the user's account * @param {(string) => object} idFunction A function that will take a string and return an object * @param {string} param The route parameter - * @param {ObjectId} userId The id of the user + * @param {number} userId The id of the user * @return {boolean} Whether the object found by the idFunction is the user's account or linked to the user's account */ -async function verifySelfCase(idFunction, param, userId) { - const object = await idFunction(param); +async function verifySelfCase( + idFunction: (value: string) => object, + param: string, + userId: number +) { + const object: any = await idFunction(param); if (!object) { return false; } // if the accountId exists (all cases except when object is an account) if (object.accountId) { - return object.accountId.toString() === userId; + //TODO - Check if this code is correct, we changed to identifier from accountId. + return object.identifier.toString() === userId; } // no accountId so object is an account else { - return object._id.toString() === userId; + return object.identifier.toString() === userId; } } diff --git a/services/database.service.js b/services/database.service.js deleted file mode 100644 index 2fa575d9..00000000 --- a/services/database.service.js +++ /dev/null @@ -1,78 +0,0 @@ -"use strict"; -const mongoose = require("mongoose"); -const logger = require("./logger.service"); -const Q = require("q"); - -const TAG = "[ DATABASE SERVICE ]"; -const env = require("./env.service"); - -// if DB is defined as an env var, it will go there, elsewise, try local -// you ideally set DB to your database uri that the provider gives you -// it should be easily findable - -// DATABASE SERVICE -function getAddressFromEnvironment() { - return env.isDevelopment() - ? process.env.DB_ADDRESS_DEV - : env.isProduction() - ? process.env.DB_ADDRESS_DEPLOY - : process.env.DB_ADDRESS_TEST; -} - -function getUserFromEnvironment() { - return env.isDevelopment() - ? process.env.DB_USER_DEV - : env.isProduction() - ? process.env.DB_USER_DEPLOY - : process.env.DB_USER_TEST; -} - -function getPassFromEnvironment() { - return process.env.NODE_ENV === "development" - ? process.env.DB_PASS_DEV - : process.env.NODE_ENV === "deployment" - ? process.env.DB_PASS_DEPLOY - : process.env.DB_PASS_TEST; -} - -module.exports = { - connect: function(app, callback) { - mongoose.Promise = Q.promise; - const user = getUserFromEnvironment(); - const pass = getPassFromEnvironment(); - const address = getAddressFromEnvironment(); - const url = - !!user && !!pass - ? `mongodb://${user}:${pass}@${address}` - : `mongodb://${address}`; - logger.info(`${TAG} Connecting to db on ${url}`); - mongoose - .connect(url, { - useNewUrlParser: true, - useCreateIndex: true, - useFindAndModify: false, - useUnifiedTopology: true - }) - .then( - function() { - logger.info(`${TAG} Connected to database on ${url}`); - if (app) { - app.emit("event:connected to db"); - } - if (callback) { - callback(); - } - }, - function(error) { - logger.error( - `${TAG} Failed to connect to database at ${url}. Error: ${error}` - ); - throw `Failed to connect to database at ${url}`; - } - ); - }, - address: getAddressFromEnvironment(), - readyState: function() { - return mongoose.connection.readyState; - } -}; diff --git a/services/database.service.ts b/services/database.service.ts new file mode 100644 index 00000000..8ed18592 --- /dev/null +++ b/services/database.service.ts @@ -0,0 +1,118 @@ +import { Connection, createConnection } from "typeorm"; +const logger = require("./logger.service"); + +const TAG = "[ DATABASE SERVICE ]"; +import * as env from "./env.service"; +import Account from "../models/account.model"; +import AccountConfirmation from "../models/accountConfirmationToken.model"; +import Application from "../models/application.model"; +import Bus from "../models/bus.model"; +import EmailTemplate from "../models/emailTemplate.model"; +import Hacker from "../models/hacker.model"; +import PasswordReset from "../models/passwordResetToken.model"; +import Role from "../models/role.model"; +import RoleBinding from "../models/roleBinding.model"; +import Settings from "../models/settings.model"; +import Sponsor from "../models/sponsor.model"; +import Staff from "../models/staff.model"; +import Team from "../models/team.model"; +import Travel from "../models/travel.model"; +import Volunteer from "../models/volunteer.model"; + +// if DB is defined as an env var, it will go there, elsewise, try local +// you ideally set DB to your database uri that the provider gives you +// it should be easily findable + +// DATABASE SERVICE +function getHostFromEnvironment() { + return process.env.NODE_ENV == "development" + ? process.env.DB_HOST_DEV + : process.env.NODE_ENV == "deployment" + ? process.env.DB_HOST_DEPLOY + : process.env.DB_HOST_TEST; +} + +function getPortFromEnvironment() { + return process.env.NODE_ENV == "development" + ? process.env.DB_PORT_DEV + : process.env.NODE_ENV == "deployment" + ? process.env.DB_PORT_DEPLOY + : process.env.DB_PORT_TEST; +} + +function getNameFromEnvironment() { + return process.env.NODE_ENV == "development" + ? process.env.DB_NAME_DEV + : process.env.NODE_ENV == "deployment" + ? process.env.DB_NAME_DEPLOY + : process.env.DB_NAME_TEST; +} + +function getUserFromEnvironment() { + return process.env.NODE_ENV == "development" + ? process.env.DB_USER_DEV + : process.env.NODE_ENV == "deployment" + ? process.env.DB_USER_DEPLOY + : process.env.DB_USER_TEST; +} + +function getPassFromEnvironment() { + return process.env.NODE_ENV == "development" + ? process.env.DB_PASS_DEV + : process.env.NODE_ENV == "deployment" + ? process.env.DB_PASS_DEPLOY + : process.env.DB_PASS_TEST; +} + +async function connect(app: any, callback: any) { + const host = getHostFromEnvironment(); + // TODO - Fix this hack. + const port = parseInt(getPortFromEnvironment()!); + const user = getUserFromEnvironment(); + const password = getPassFromEnvironment(); + const database = getNameFromEnvironment(); + logger.info(`${TAG} Connecting to db on ${host}`); + await createConnection({ + type: "postgres", + host: host, + port: port, + username: user, + password: password, + database: database, + entities: [ + Account, + AccountConfirmation, + Application, + Bus, + EmailTemplate, + Hacker, + PasswordReset, + Role, + RoleBinding, + Settings, + Sponsor, + Staff, + Team, + Travel, + Volunteer + ] + }) + .then((connection: Connection) => { + connection.synchronize(); + logger.info(`${TAG} Connected to database on ${host}`); + if (app) { + app.emit("event:connected to db"); + } + if (callback) { + callback(); + } + }) + .catch((error) => { + logger.error( + `${TAG} Failed to connect to database at ${host}. Error: ${error}` + ); + throw `Failed to connect to database at ${host}`; + }); +} + +export { connect }; diff --git a/services/email.service.js b/services/email.service.ts similarity index 76% rename from services/email.service.js rename to services/email.service.ts index af9abde1..7ae6fa79 100644 --- a/services/email.service.js +++ b/services/email.service.ts @@ -1,15 +1,15 @@ "use strict"; const logger = require("./logger.service"); -const client = require("@sendgrid/mail"); -const fs = require("fs"); -const path = require("path"); +import client from "@sendgrid/mail"; +import * as fs from "fs"; +import * as path from "path"; const TAG = `[ EMAIL.SERVICE ]`; const env = require("../services/env.service"); const Constants = require("../constants/general.constant"); -const Handlebars = require("handlebars"); +import * as Handlebars from "handlebars"; class EmailService { - constructor(apiKey) { + constructor(apiKey: string = "") { client.setApiKey(apiKey); } @@ -18,7 +18,7 @@ class EmailService { * @param {*} mailData * @param {(err?)=>void} callback */ - send(mailData, callback = () => {}) { + send(mailData: any, callback = (error?: Object) => {}) { if (env.isTest()) { //Silence all actual emails if we're testing mailData.mailSettings = { @@ -27,29 +27,31 @@ class EmailService { } }; } - return client.send(mailData, false) - .then(response => { - callback() - return response - }) - .catch(error => { - callback(error) + return client + .send(mailData, false) + .then((response) => { + callback(); + return response; }) + .catch((error) => { + callback(error); + }); } /** * Send separate emails to the list of users in mailData * @param {*} mailData * @param {(err?)=>void} callback */ - sendMultiple(mailData, callback = () => {}) { - return client.sendMultiple(mailData) - .then(response => { - callback() + sendMultiple(mailData: any, callback = (error?: Object) => {}) { + return client + .sendMultiple(mailData) + .then((response) => { + callback(); return response; }) - .catch(error => { - callback(error) - }) + .catch((error) => { + callback(error); + }); } /** * Send email with ticket. @@ -58,7 +60,12 @@ class EmailService { * @param {string} ticket the ticket image (must be base-64 string) * @param {(err?)=>void} callback */ - sendWeekOfEmail(firstName, recipient, ticket, callback) { + sendWeekOfEmail( + firstName: string, + recipient: string, + ticket: string, + callback = (error?: Object) => {} + ) { const handlebarsPath = path.join( __dirname, `../assets/email/Ticket.hbs` @@ -90,7 +97,11 @@ class EmailService { * @param {string} recipient the recipient's email address * @param {(err?)=>void} callback */ - sendDayOfEmail(firstName, recipient, callback) { + sendDayOfEmail( + firstName: string, + recipient: string, + callback = (error?: Object) => {} + ) { const handlebarsPath = path.join( __dirname, `../assets/email/Welcome.hbs` @@ -116,7 +127,12 @@ class EmailService { }, callback); } - sendStatusUpdate(firstName, recipient, status, callback) { + sendStatusUpdate( + firstName: string, + recipient: string, + status: string, + callback = (error?: Object) => {} + ) { const handlebarsPath = path.join( __dirname, `../assets/email/statusEmail/${status}.hbs` @@ -145,7 +161,7 @@ class EmailService { * @param {string} path the absolute path to the handlebars template file * @param {*} context any variables that need to be replaced in the template file */ - renderEmail(path, context) { + renderEmail(path: string, context: Object) { const templateStr = fs.readFileSync(path).toString(); const template = Handlebars.compile(templateStr); return template(context); diff --git a/services/env.service.js b/services/env.service.ts similarity index 66% rename from services/env.service.js rename to services/env.service.ts index 9b3d2091..e163128f 100644 --- a/services/env.service.js +++ b/services/env.service.ts @@ -1,26 +1,23 @@ -"use strict"; -const dotenv = require("dotenv"); -const fs = require("fs"); -const path = require("path"); +import { config } from "dotenv"; +import * as fs from "fs"; +import * as path from "path"; const Logger = require("./logger.service"); -module.exports = { - load: function(path) { - const result = dotenv.config({ - path: path - }); - createGCPFile(); - return result; - }, - isDevelopment: function() { - return process.env.NODE_ENV === "development"; - }, - isProduction: function() { - return process.env.NODE_ENV === "deployment"; - }, - isTest: function() { - return process.env.NODE_ENV === "test"; - } -}; + +function load(path: string) { + const result = config({ + path: path + }); + createGCPFile(); + return result; +} + +const isDevelopment = (): boolean => process.env.NODE_ENV === "test"; + +const isProduction = (): boolean => process.env.NODE_ENV === "deployment"; + +const isTest = (): boolean => process.env.NODE_ENV === "test"; + +export { load, isDevelopment, isProduction, isTest }; function createGCPFile() { const creds = { diff --git a/services/hacker.service.js b/services/hacker.service.ts similarity index 74% rename from services/hacker.service.js rename to services/hacker.service.ts index 3ebfd289..839be428 100644 --- a/services/hacker.service.js +++ b/services/hacker.service.ts @@ -1,5 +1,5 @@ -"use strict"; -const Hacker = require("../models/hacker.model"); +import { UpdateResult } from "typeorm"; +import Hacker from "../models/hacker.model"; const logger = require("./logger.service"); const cache = require("memory-cache"); @@ -14,14 +14,12 @@ const QRCode = require("qrcode"); * @return {Promise} The promise will resolve to a hacker object if save is successful. * @description Adds a new hacker to database. */ -function createHacker(hackerDetails) { +async function createHacker(hackerDetails: Object): Promise { const TAG = `[Hacker Service # createHacker]:`; - let hacker; - //if (Date.now() < Constants.APPLICATION_CLOSE_TIME) { - hacker = new Hacker(hackerDetails); - return hacker.save(); + let hacker = Hacker.create(hackerDetails); + return await hacker.save(); //} //throw new Error("Sorry, the application deadline has passed!"); } @@ -33,18 +31,16 @@ function createHacker(hackerDetails) { * @return {DocumentQuery} The document query will resolve to hacker or null. * @description Update an account specified by its mongoId with information specified by hackerDetails. */ -function updateOne(id, hackerDetails) { +async function updateOne( + identifier: number, + hackerDetails: Object +): Promise { const TAG = `[Hacker Service # update ]:`; - const query = { - _id: id - }; - - return Hacker.findOneAndUpdate( - query, - hackerDetails, - logger.updateCallbackFactory(TAG, "hacker") - ); + return await Hacker.update(identifier, hackerDetails).then((hacker) => { + logger.updateCallbackFactory(TAG, "hacker"); + return hacker; + }); } /** @@ -53,46 +49,54 @@ function updateOne(id, hackerDetails) { * @return {DocumentQuery} The document query will resolve to hacker or null. * @description Finds an hacker by the id, which is the mongoId. */ -function findById(id) { +async function findById(identifier: number): Promise { const TAG = `[Hacker Service # findById ]:`; - return Hacker.findById(id, logger.queryCallbackFactory(TAG, "hacker", id)); + return await Hacker.findOne(identifier).then((hacker) => { + logger.queryCallbackFactory(TAG, "hacker", identifier); + return hacker; + }); } /** * @async * @function findOne - * @param {JSON} query + * @param {ObjectID} query * @return {Hacker | null} either hacker or null * @description Finds an hacker by some query. */ -async function findIds(queries) { +async function findIds(queries: Object[]): Promise<(Hacker | undefined)[]> { const TAG = `[Hacker Service # findIds ]:`; let ids = []; for (const query of queries) { - let currId = await Hacker.findOne( - query, - "_id", - logger.queryCallbackFactory(TAG, "hacker", query) + let current = await Hacker.findOne({ where: query }).then( + (hacker: Hacker) => { + logger.queryCallbackFactory(TAG, "hacker", query); + return hacker; + } ); - ids.push(currId); + ids.push(current); } return ids; } +//TODO - Remove this function, it is redundant. /** * @function findByAccountId - * @param {ObjectId} accountId - * @return {DocumentQuery} A hacker document queried by accountId + * @param {number} accountId + * @return {Promise} A hacker document queried by accountId */ -function findByAccountId(accountId) { +function findByAccountId(accountId: number): Promise { const TAG = `[ Hacker Service # findByAccountId ]:`; const query = { - accountId: accountId + identifier: accountId }; - return Hacker.findOne(query, logger.updateCallbackFactory(TAG, "hacker")); + return Hacker.findOne({ where: query }).then((hacker: Hacker) => { + logger.updateCallbackFactory(TAG, "hacker"); + return hacker; + }); } async function getStatsAllHackersCached() { @@ -101,21 +105,21 @@ async function getStatsAllHackersCached() { logger.info(`${TAG} Getting cached stats`); return cache.get(Constants.CACHE_KEY_STATS); } - const allHackers = await Hacker.find( - {}, - logger.updateCallbackFactory(TAG, "hacker") - ).populate({ - path: "accountId" + + const allHackers = await Hacker.find().then((hackers) => { + logger.updateCallbackFactory(TAG, "hacker"); + return hackers; }); + const stats = getStats(allHackers); cache.put(Constants.CACHE_KEY_STATS, stats, Constants.CACHE_TIMEOUT_STATS); //set a time-out of 5 minutes - return getStats(allHackers); + return stats; } /** * Generate a QR code for the hacker. * @param {string} str The string to be encoded in the QR code. */ -async function generateQRCode(str) { +async function generateQRCode(str: string) { const response = await QRCode.toDataURL(str, { scale: 4 }); @@ -128,12 +132,16 @@ async function generateQRCode(str) { * @param {string} domain The domain of the frontend site * @param {string} id The ID of the hacker to view */ -function generateHackerViewLink(httpOrHttps, domain, id) { +function generateHackerViewLink( + httpOrHttps: string, + domain: string, + id: number +) { const link = `${httpOrHttps}://${domain}/application/view/${id}`; return link; } -function getStats(hackers) { +function getStats(hackers: Hacker[]): Object { const TAG = `[ hacker Service # getStats ]`; const stats = { total: 0, @@ -153,11 +161,13 @@ function getStats(hackers) { }; hackers.forEach((hacker) => { - if (!hacker.accountId) { + if (!hacker.identifier) { // user is no longer with us for some reason :( return; } stats.total += 1; + //TODO - Fix this functionality. + /* stats.status[hacker.status] = stats.status[hacker.status] ? stats.status[hacker.status] + 1 : 1; @@ -225,18 +235,19 @@ function getStats(hackers) { ] ? stats.applicationDate[applicationDate] + 1 : 1; + */ }); return stats; } -module.exports = { - createHacker: createHacker, - findById: findById, - updateOne: updateOne, - findIds: findIds, - findByAccountId: findByAccountId, - getStats: getStats, - getStatsAllHackersCached: getStatsAllHackersCached, - generateQRCode: generateQRCode, - generateHackerViewLink: generateHackerViewLink +export { + createHacker, + findById, + updateOne, + findIds, + findByAccountId, + getStats, + getStatsAllHackersCached, + generateQRCode, + generateHackerViewLink }; diff --git a/services/logger.service.js b/services/logger.service.ts similarity index 54% rename from services/logger.service.js rename to services/logger.service.ts index 1faf7818..5d81b21d 100755 --- a/services/logger.service.js +++ b/services/logger.service.ts @@ -1,34 +1,40 @@ -"use strict"; -const winston = require("winston"); -const expressWinston = require("express-winston"); +import winston, { + error, + warn, + info, + log, + verbose, + debug, + silly +} from "winston"; +import expressWinston from "express-winston"; const colorize = process.env.NODE_ENV !== "deployment"; const errorLogger = expressWinston.errorLogger({ - transports: [ - new winston.transports.Console({ - json: true, - colorize: colorize, - timestamp: true - }) - ] + transports: [new winston.transports.Console()], + format: winston.format.combine( + winston.format.json(), + winston.format.colorize(), + winston.format.timestamp() + ) }); const requestLogger = expressWinston.logger({ - transports: [ - new winston.transports.Console({ - json: false, - colorize: colorize, - timestamp: true - }) - ], + transports: [new winston.transports.Console()], + format: winston.format.combine( + winston.format.json(), + winston.format.colorize(), + winston.format.timestamp() + ), + colorize: colorize, expressFormat: true, meta: false }); -function queryCallbackFactory(TAG, model, query) { +function queryCallbackFactory(TAG: string, model: string, query: Object) { // err is error, res is result - return (err, res) => { + return (err: Error, res: Object) => { if (err) { winston.error( `${TAG} Failed to verify if ${model} exist or not using ${JSON.stringify( @@ -52,8 +58,8 @@ function queryCallbackFactory(TAG, model, query) { }; } -function updateCallbackFactory(TAG, model) { - return (err, res) => { +function updateCallbackFactory(TAG: string, model: string) { + return (err: Error, res: Object) => { if (err) { winston.error(`${TAG} failed to change ${model}`); } else if (!res) { @@ -64,16 +70,15 @@ function updateCallbackFactory(TAG, model) { }; } -module.exports = { - updateCallbackFactory: updateCallbackFactory, - queryCallbackFactory: queryCallbackFactory, - requestLogger: requestLogger, - errorLogger: errorLogger, - error: winston.error, - warn: winston.warn, - info: winston.info, - log: winston.log, - verbose: winston.verbose, - debug: winston.debug, - silly: winston.silly +export { + updateCallbackFactory, + queryCallbackFactory, + requestLogger, + errorLogger, + error, + warn, + info, + verbose, + debug, + silly }; diff --git a/services/parsePatch.service.js b/services/parsePatch.service.js deleted file mode 100644 index b4ae1bc5..00000000 --- a/services/parsePatch.service.js +++ /dev/null @@ -1,21 +0,0 @@ -"use strict"; -const mongoose = require("mongoose"); - -module.exports = { - parsePatch: function(req, model, done) { - setMatchingAttributes(model).then(() => { - done(); - }); - } -}; - -async function setMatchingAttributes(model) { - let modelDetails = {}; - for (const val in req.body) { - if (model.schema.paths.hasOwnProperty(val)) { - modelDetails[val] = req.body[val]; - delete req.body[val]; - } - } - req.body.modelDetails = modelDetails; -} diff --git a/services/parsePatch.service.ts b/services/parsePatch.service.ts new file mode 100644 index 00000000..0a5e3ce1 --- /dev/null +++ b/services/parsePatch.service.ts @@ -0,0 +1,20 @@ +import { Request } from "express"; + +function parsePatch(req: Request, model: Object, done: () => {}) { + setMatchingAttributes(req, model).then(() => { + done(); + }); +} + +async function setMatchingAttributes(req: Request, model: Object) { + let modelDetails: any = {}; + for (const val in req.body) { + if (model.hasOwnProperty(val)) { + modelDetails[val] = req.body[val]; + delete req.body[val]; + } + } + req.body.modelDetails = modelDetails; +} + +export { parsePatch }; diff --git a/services/resetPassword.service.js b/services/resetPassword.service.ts similarity index 56% rename from services/resetPassword.service.js rename to services/resetPassword.service.ts index b8a43b7c..33330bb0 100644 --- a/services/resetPassword.service.js +++ b/services/resetPassword.service.ts @@ -1,84 +1,74 @@ -"use strict"; const logger = require("./logger.service"); -const PasswordReset = require("../models/passwordResetToken.model"); +import PasswordReset from "../models/passwordResetToken.model"; const jwt = require("jsonwebtoken"); const path = require("path"); const Services = { - Email: require("./email.service") + Email: require("./email.service"), + Account: require("./account.service") }; -function findByAccountId(accountId) { +async function findByAccountId( + identifier: number +): Promise { const TAG = `[ PasswordReset Service # findByAccountId ]`; - return PasswordReset.findOne( - { - accountId: accountId - }, - logger.queryCallbackFactory(TAG, "passwordReset", "accountId") + return await PasswordReset.findOne({ where: { account: identifier } }).then( + (account) => { + logger.queryCallbackFactory(TAG, "passwordReset", "accountId"); + return account; + } ); } -function findById(id) { +function findById(identifier: number): Promise { const TAG = `[ PasswordReset Service # findById ]`; - return PasswordReset.findById( - id, - logger.queryCallbackFactory(TAG, "passwordReset", "mongoId") + + return PasswordReset.findOne(identifier).then( + (passwordReset: PasswordReset) => { + logger.queryCallbackFactory(TAG, "passwordReset", "identifier"); + return passwordReset; + } ); } -async function create(accountId) { +async function create(accountId: number) { const TAG = `[ PasswordReset Service # create]:`; //Create new instance of password reset token - const newResetToken = PasswordReset({ - accountId: accountId, - created: new Date() + const newResetToken = PasswordReset.create({ + account: await Services.Account.findOne(accountId), + createdAt: new Date() }); + // TODO - Previous behaviour was to mark reset tokens as used in "wasUsed" field. + //invalidate all of the previous reset tokens such that they do not work anymore - await PasswordReset.update( - { - accountId: accountId - }, - { - $set: { - wasUsed: true - } - }, - { - multi: true - }, - (error) => { - if (error) { - logger.error( - `${TAG} could not invalidate all previous password reset tokens`, - error - ); - } else { - logger.info( - `${TAG} invalidated all previous password reset tokens ${accountId}` - ); - } - } - ); + await PasswordReset.delete({ + account: await Services.Account.findOne(accountId) + }) + .then(() => { + logger.info( + `${TAG} invalidated all previous password reset tokens ${accountId}` + ); + }) + .catch((error: Object) => { + logger.error( + `${TAG} could not invalidate all previous password reset tokens`, + error + ); + }); return newResetToken.save(); } -function deleteToken(id) { +function deleteToken(identifier: number) { const TAG = `[ PasswordReset Service # deleteToken]:`; + //Create new instance of password reset token - return PasswordReset.deleteOne( - { - _id: id - }, - (err) => { - if (err) { - logger.erro(`${TAG} could not delete token id: ${id}`); - } - } - ); + return PasswordReset.delete(identifier).catch((error: Object) => { + logger.error(`${TAG} could not delete token id: ${identifier}`); + }); } -function generateToken(resetId, accountId) { +function generateToken(resetId: number, accountId: number) { const token = jwt.sign( { resetId: resetId, @@ -99,7 +89,7 @@ function generateToken(resetId, accountId) { * @param {string} token the reset token * @returns {string} the string, of form: [http|https]://{domain}/password/reset?token={token} */ -function generateTokenLink(httpOrHttps, domain, token) { +function generateTokenLink(httpOrHttps: string, domain: string, token: string) { const link = `${httpOrHttps}://${domain}/password/reset?token=${token}`; return link; } @@ -110,7 +100,11 @@ function generateTokenLink(httpOrHttps, domain, token) { * @param {string} receiverEmail The receiver of the email * @param {string} token The resetPassword token */ -function generateResetPasswordEmail(address, receiverEmail, token) { +function generateResetPasswordEmail( + address: string, + receiverEmail: string, + token: string +) { const httpOrHttps = address.includes("localhost") ? "http" : "https"; const tokenLink = generateTokenLink(httpOrHttps, address, token); if (token === undefined || tokenLink === undefined) { diff --git a/services/role.service.js b/services/role.service.js deleted file mode 100644 index da8f7e07..00000000 --- a/services/role.service.js +++ /dev/null @@ -1,68 +0,0 @@ -"use strict"; -const Role = require("../models/role.model"); -const logger = require("./logger.service"); -const mongoose = require("mongoose"); - -/** - * @function createRole - * @param {{_id: ObjectId, name: String, routes: route[]}} roleDetails - * @return {Promise} The promise will resolve to a role object if save was successful. - * @description Adds a new role to database. - */ -function createRole(roleDetails) { - const role = new Role(roleDetails); - - return role.save(); -} - -/** - * @function getRole - * @param {string} roleName The name of the role that you're looking for. - * @description - * Returns the role defined by the role name - */ -function getRole(roleName) { - const TAG = "[Role Service # getRole]:"; - const query = { - name: roleName - }; - //get the roleBinding for account - //Populate roles for roleBinding - return Role.findOne(query, logger.queryCallbackFactory(TAG, "role", query)); -} - -/** - * @function getById - * @param {ObjectId} id The role id - * @description - * Returns the role specified by the id. - */ -function getById(id) { - const TAG = "[Role Service # getById]:"; - const query = { - _id: id - }; - //get the roleBinding for account - //Populate roles for roleBinding - return Role.findById( - query, - logger.queryCallbackFactory(TAG, "role", query) - ); -} - -/** - * @function getAll - * @description - * Returns all the roles in the database - */ -function getAll() { - const TAG = "[Role Service # getAll]:"; - return Role.find({}, logger.queryCallbackFactory(TAG, "role", {})); -} - -module.exports = { - getRole: getRole, - getById: getById, - getAll: getAll, - createRole: createRole -}; diff --git a/services/role.service.ts b/services/role.service.ts new file mode 100644 index 00000000..dc8af54a --- /dev/null +++ b/services/role.service.ts @@ -0,0 +1,66 @@ +import { BaseEntity } from "typeorm"; +import Role from "../models/role.model"; +import * as logger from "./logger.service"; + +/** + * @function createRole + * @param {{_id: ObjectId, name: String, routes: route[]}} roleDetails + * @return {Promise} The promise will resolve to a role object if save was successful. + * @description Adds a new role to database. + */ +async function createRole(roleDetails: Object): Promise { + const role = Role.create(roleDetails); + + return await role.save(); +} + +/** + * @function getRole + * @param {string} roleName The name of the role that you're looking for. + * @description + * Returns the role defined by the role name + */ +async function getRole(roleName: string): Promise { + const TAG = "[Role Service # getRole]:"; + + const query = { name: roleName }; + + //get the roleBinding for account + //Populate roles for roleBinding + return await Role.findOne({ where: query }).then((role: Role) => { + logger.queryCallbackFactory(TAG, "role", query); + return role; + }); +} + +/** + * @function getById + * @param {number} identifier The role id + * @description + * Returns the role specified by the id. + */ +async function getById(identifier: number): Promise { + const TAG = "[Role Service # getById]:"; + + //get the roleBinding for account + //Populate roles for roleBinding + return await Role.findOne(identifier).then((role: Role) => { + logger.queryCallbackFactory(TAG, "role", identifier); + return role; + }); +} + +/** + * @function getAll + * @description + * Returns all the roles in the database + */ +async function getAll(): Promise { + const TAG = "[Role Service # getAll]:"; + return Role.find().then((roles) => { + logger.queryCallbackFactory(TAG, "role", {}); + return roles; + }); +} + +export { createRole, getRole, getById, getAll }; diff --git a/services/roleBinding.service.js b/services/roleBinding.service.js deleted file mode 100644 index fc00dab9..00000000 --- a/services/roleBinding.service.js +++ /dev/null @@ -1,119 +0,0 @@ -"use strict"; -const RoleBinding = require("../models/roleBinding.model"); -const RoleService = require("./role.service"); -const logger = require("./logger.service"); - -/** - * Creates a rolebinding between an account and a role. Appends to an existing rolebinding if one already exists - * @param {ObjectId} accountId the id of the account that you want to add a rolebinding to - * @param {ObjectId} roleId the id of the role that you want to add - */ -async function createRoleBinding(accountId, roleId = undefined) { - const TAG = "[RoleBinding Service # createRoleBinding]:"; - const query = { - accountId: accountId - }; - const roleBindingModel = await getRoleBindingForAcct(accountId); - if (!roleBindingModel) { - const roleArray = roleId ? [roleId] : []; - const newRb = new RoleBinding({ - name: accountId + "_rolebinding", - accountId: accountId, - roles: roleArray - }); - return newRb.save(); - } else { - return RoleBinding.findByIdAndUpdate( - roleBindingModel._id, - { - $addToSet: { - roles: roleId - } - }, - logger.queryCallbackFactory(TAG, "roleBinding", query) - ); - } -} - -/** - * Attempts to find a rolebinding given the role name and adds it to the account - * @param {ObjectId} accountId the id of the account that you want to add a rolebinding to - * @param {String} roleName the name of the role that you want to add - */ -async function createRoleBindingByRoleName(accountId, roleName) { - const role = await RoleService.getRole(roleName); - if (role) { - await createRoleBinding(accountId, role.id); - } -} - -/** - * Removes a role from a rolebinding for a given account. - * @param {ObjectId} accountId the id of the account that you want to remove a rolebinding from - * @param {ObjectId} roleId the id of the role that you want to remove - */ -async function removeRoleBinding(accountId, roleId) { - const TAG = "[RoleBinding Service # removeRoleBinding]:"; - const roleBindingModel = await getRoleBindingForAcct(accountId); - return RoleBinding.findByIdAndUpdate( - roleBindingModel._id, - { - $pop: { - roles: roleId - } - }, - logger.queryCallbackFactory(TAG, "roleBinding", roleBindingModel._id) - ); -} - -/** - * @async - * @function getRoleBindingForAcct - * @param {string} accountId The id of the account that you want the role bindings for. - * @returns {Promise} - * @description - * Gets the roleBinding for a given account. Populates the role array as well with the Roles. - */ -async function getRoleBindingForAcct(accountId) { - const TAG = "[RoleBinding Service # getRoleBindings]:"; - const query = { - accountId: accountId - }; - //get the roleBinding for account - //Populate roles for roleBinding - - return RoleBinding.findOne( - query, - logger.queryCallbackFactory(TAG, "roleBinding", query) - ).populate({ - path: "roles" - }); -} - -/** - * @async - * @function getById - * @param {ObjectId} id The rolebinding id - * @description - * Returns the roleBinding specified by the id. - */ -async function getById(id) { - const TAG = "[RoleBinding Service # getById]:"; - const query = { - _id: id - }; - //get the roleBinding for account - //Populate roles for roleBinding - return await RoleBinding.findById( - query, - logger.queryCallbackFactory(TAG, "roleBinding", query) - ); -} - -module.exports = { - getRoleBindingForAcct: getRoleBindingForAcct, - getById: getById, - createRoleBinding: createRoleBinding, - createRoleBindingByRoleName: createRoleBindingByRoleName, - removeRoleBinding: removeRoleBinding -}; diff --git a/services/roleBinding.service.ts b/services/roleBinding.service.ts new file mode 100644 index 00000000..d6c767c0 --- /dev/null +++ b/services/roleBinding.service.ts @@ -0,0 +1,130 @@ +import RoleBinding from "../models/roleBinding.model"; +import { getById as getRoleById, getRole } from "./role.service"; +import { findById as findAccountById } from "./account.service"; +import { UpdateResult } from "typeorm"; +import Role from "../models/role.model"; +const logger = require("./logger.service"); + +/** + * Creates a rolebinding between an account and a role. Appends to an existing rolebinding if one already exists + * @param {number} accountId the id of the account that you want to add a rolebinding to + * @param {number} roleId the id of the role that you want to add + */ +async function createRoleBinding(accountId: number, roleId?: any) { + const TAG = "[RoleBinding Service # createRoleBinding]:"; + const query = { + accountId: accountId + }; + const roleBindingModel = await getRoleBindingForAcct(accountId); + if (!roleBindingModel) { + const roleArray = roleId ? [roleId] : []; + const newRb = RoleBinding.create({ + account: await findAccountById(accountId), + roles: roleArray + }); + return newRb.save(); + } else { + // This code is terrible. + if (roleId == undefined) return undefined; + const role = await getRoleById(roleId); + if (role == undefined) return undefined; + roleBindingModel.roles.push(); + return RoleBinding.update( + roleBindingModel.identifier, + roleBindingModel + ).then((value: UpdateResult) => { + logger.queryCallbackFactory(TAG, "roleBinding", query); + return value; + }); + } +} + +/** + * Attempts to find a rolebinding given the role name and adds it to the account + * @param {ObjectId} accountId the id of the account that you want to add a rolebinding to + * @param {String} roleName the name of the role that you want to add + */ +async function createRoleBindingByRoleName( + accountId: number, + roleName: string +) { + const role = await getRole(roleName); + if (role === undefined) return undefined; + await createRoleBinding(accountId, role.identifier); +} + +/** + * Removes a role from a rolebinding for a given account. + * @param {ObjectId} accountId the id of the account that you want to remove a rolebinding from + * @param {ObjectId} roleId the id of the role that you want to remove + */ +async function removeRoleBinding(accountId: number, roleId: number) { + const TAG = "[RoleBinding Service # removeRoleBinding]:"; + const roleBindingModel = await getRoleBindingForAcct(accountId); + const role = await getRoleById(roleId); + if ( + roleBindingModel === undefined || + role === undefined || + roleId == undefined + ) + return undefined; + delete roleBindingModel.roles[roleBindingModel.roles.indexOf(role)]; + return RoleBinding.update( + roleBindingModel.identifier, + roleBindingModel + ).then((value: UpdateResult) => { + logger.queryCallbackFactory( + TAG, + "roleBinding", + roleBindingModel.identifier + ); + return value; + }); +} + +/** + * @async + * @function getRoleBindingForAcct + * @param {string} accountId The id of the account that you want the role bindings for. + * @returns {Promise} + * @description + * Gets the roleBinding for a given account. Populates the role array as well with the Roles. + */ +async function getRoleBindingForAcct(accountId: number) { + const TAG = "[RoleBinding Service # getRoleBindings]:"; + const query = {}; + //get the roleBinding for account + //Populate roles for roleBinding + + return RoleBinding.findOne({ + where: { account: await findAccountById(accountId) } + }).then((roleBinding) => { + logger.queryCallbackFactory(TAG, "roleBinding", "accountId"); + return roleBinding; + }); +} + +/** + * @async + * @function getById + * @param {ObjectId} id The rolebinding id + * @description + * Returns the roleBinding specified by the id. + */ +async function getById(identifier: number) { + const TAG = "[RoleBinding Service # getById]:"; + //get the roleBinding for account + //Populate roles for roleBinding + return await RoleBinding.findOne(identifier).then((roleBinding) => { + logger.queryCallbackFactory(TAG, "roleBinding", identifier); + return roleBinding; + }); +} + +module.exports = { + getRoleBindingForAcct: getRoleBindingForAcct, + getById: getById, + createRoleBinding: createRoleBinding, + createRoleBindingByRoleName: createRoleBindingByRoleName, + removeRoleBinding: removeRoleBinding +}; diff --git a/services/search.service.js b/services/search.service.ts similarity index 90% rename from services/search.service.js rename to services/search.service.ts index 5b887f75..78f0b987 100644 --- a/services/search.service.js +++ b/services/search.service.ts @@ -14,16 +14,17 @@ const logger = require("./logger.service"); * @description Builds and executes a search query based on a subset of mongodb */ function executeQuery( - model, - queryArray, - page, - limit, - sort, - sort_by, + model: Object, + queryArray: Array, + page: number, + limit: number, + sort: string, + sort_by: string, shouldExpand = false ) { - var query; - switch (model.toLowerCase()) { + //TODO: Fix this / update for TypeOrm. + var query = {}; + /*switch (model.toLowerCase()) { case "hacker": query = shouldExpand ? Hacker.find().populate([ @@ -83,7 +84,8 @@ function executeQuery( return query .limit(limit) .skip(limit * page) - .exec(); + .exec();*/ + return query; } module.exports = { diff --git a/services/settings.service.js b/services/settings.service.ts similarity index 67% rename from services/settings.service.js rename to services/settings.service.ts index 240d7271..45c4a62b 100644 --- a/services/settings.service.js +++ b/services/settings.service.ts @@ -1,5 +1,5 @@ -"use strict"; -const Settings = require("../models/settings.model"); +import { UpdateResult } from "typeorm"; +import Settings from "../models/settings.model"; const logger = require("./logger.service"); /** @@ -8,18 +8,19 @@ const logger = require("./logger.service"); * @return {Promise} The promise will resolve to a Settings object if save was successful. * @description Adds a new setting to database. */ -async function updateSettings(settingsDetails) { +async function updateSettings(settingsDetails: Object) { const TAG = "[Setting service # updateSettings]:"; const existingSetting = await getSettings(); if (existingSetting) { - return Settings.findOneAndUpdate( - {}, - settingsDetails, - logger.queryCallbackFactory(TAG, "settings", {}) + return Settings.update({}, settingsDetails).then( + (value: UpdateResult) => { + logger.queryCallbackFactory(TAG, "settings", {}); + return value; + } ); } else { - const setting = new Settings(settingsDetails); - return setting.save(); + const setting = Settings.create(settingsDetails); + return await setting.save(); } } diff --git a/services/sponsor.service.js b/services/sponsor.service.js deleted file mode 100644 index d0480ffd..00000000 --- a/services/sponsor.service.js +++ /dev/null @@ -1,76 +0,0 @@ -"use strict"; -const Sponsor = require("../models/sponsor.model"); -const logger = require("./logger.service"); - -/** - * @function findById - * @param {ObjectId} id - * @return {DocumentQuery} The document query will resolve to a sponsor or null. - * @description Find a sponsor by id - */ -function findById(id) { - const TAG = `[Sponsor Service # findById]:`; - const query = { - _id: id - }; - - return Sponsor.findById( - query, - logger.queryCallbackFactory(TAG, "sponsor", JSON.stringify(query)) - ); -} - -/** - * @function createSponsor - * @param {{_id: ObjectId, accountId: ObjectId, tier: number, company: string, contractURL: string, nominees: ObjectId[]}} sponsorDetails - * @return {Promise} The promise will resolve to a sponsor object if save was successful. - * @description Adds a new sponsor to database. - */ -function createSponsor(sponsorDetails) { - const TAG = `[Sponsor Service # createSponsor]:`; - - const sponsor = new Sponsor(sponsorDetails); - - return sponsor.save(); -} - -/** - * @function updateOne - * @param {ObjectId} id - * @param {{company?: string, contractURL?: string, nominees?: ObjectId[]}} sponsorDetails - * @return {Promise} The promise will resolve to a sponsor object if update was successful. - * @description Updates a sponsor by id with information in sponsorDetails. Return the updated sponsor - */ -function updateOne(id, sponsorDetails) { - const TAG = `[Sponsor Service # updateOne]:`; - - const query = { - _id: id - }; - - return Sponsor.findOneAndUpdate(query, sponsorDetails, { - new: true - }); -} - -/** - * @function findByAccountId - * @param {ObjectId} accountId - * @return {DocumentQuery} A sponsor document queried by accountId - */ -function findByAccountId(accountId) { - const TAG = `[ Sponsor Service # findByAccountId ]:`; - - const query = { - accountId: accountId - }; - - return Sponsor.findOne(query, logger.updateCallbackFactory(TAG, "sponsor")); -} - -module.exports = { - findByAccountId: findByAccountId, - findById: findById, - createSponsor: createSponsor, - updateOne: updateOne -}; diff --git a/services/sponsor.service.ts b/services/sponsor.service.ts new file mode 100644 index 00000000..00e448b8 --- /dev/null +++ b/services/sponsor.service.ts @@ -0,0 +1,73 @@ +"use strict"; +import { UpdateResult } from "typeorm"; +import Sponsor from "../models/sponsor.model"; +import * as logger from "./logger.service"; + +/** + * @function findById + * @param {number} identifier + * @return {Promise} The document query will resolve to a sponsor or null. + * @description Find a sponsor by id + */ +function findById(identifier: number): Promise { + const TAG = `[Sponsor Service # findById]:`; + + return Sponsor.findOne(identifier).then((sponsor) => { + logger.queryCallbackFactory(TAG, "sponsor", identifier); + return sponsor; + }); +} + +/** + * @function createSponsor + * @param {{_id: ObjectId, accountId: ObjectId, tier: number, company: string, contractURL: string, nominees: ObjectId[]}} sponsorDetails + * @return {Promise} The promise will resolve to a sponsor object if save was successful. + * @description Adds a new sponsor to database. + */ +async function createSponsor(sponsorDetails: Object): Promise { + const TAG = `[Sponsor Service # createSponsor]:`; + + const sponsor = Sponsor.create(sponsorDetails); + + return await sponsor.save(); +} + +/** + * @function updateOne + * @param {ObjectId} id + * @param {{company?: string, contractURL?: string, nominees?: ObjectId[]}} sponsorDetails + * @return {Promise} The promise will resolve to a sponsor object if update was successful. + * @description Updates a sponsor by id with information in sponsorDetails. Return the updated sponsor + */ +async function updateOne( + identifier: number, + sponsorDetails: Object +): Promise { + const TAG = `[Sponsor Service # updateOne]:`; + + return await Sponsor.update(identifier, sponsorDetails); +} + +// TODO - Remove this function, it's redundant. +/** + * @function findByAccountId + * @param {number} identifier + * @return {Promise} A sponsor document queried by accountId + */ +function findByAccountId(identifier: number): Promise { + const TAG = `[ Sponsor Service # findByAccountId ]:`; + + return Sponsor.findOne(identifier).then((sponsor) => { + logger.updateCallbackFactory(TAG, "sponsor"); + return sponsor; + }); +} + +module.exports = { + findByAccountId: findByAccountId, + findById: findById, + createSponsor: createSponsor, + updateOne: updateOne +}; + +export { findByAccountId, findById, createSponsor, updateOne }; diff --git a/services/storage.service.js b/services/storage.service.ts similarity index 76% rename from services/storage.service.js rename to services/storage.service.ts index 85cb9ce7..c573fe8d 100644 --- a/services/storage.service.js +++ b/services/storage.service.ts @@ -1,16 +1,22 @@ -"use strict"; // Imports the Google Cloud client library -const GStorage = require("@google-cloud/storage"); -const Logger = require("./logger.service"); +import * as GStorage from "@google-cloud/storage"; +import * as Logger from "./logger.service"; +import * as Env from "./env.service"; + class StorageService { + bucketName: string | undefined; + storage: any; + bucket: any; + constructor() { - this.bucketName = process.env.BUCKET_NAME; + this.bucketName = process.env.BUCKET_NAME || ""; try { this.storage = new GStorage.Storage(); } catch (error) { Logger.error(error); } - this.bucket = this.storage.bucket(this.bucketName); + if (Env.isProduction()) + this.bucket = this.storage.bucket(this.bucketName); } /** @@ -19,7 +25,7 @@ class StorageService { * @param {string} gcfilename the location in the bucket that you want the file stored. * @returns {Promise} the address of the file that was uploaded */ - upload(file, gcfilename) { + upload(file: { mimetype: string; buffer: Buffer }, gcfilename: string) { const blob = this.bucket.file(gcfilename); const blobStream = blob.createWriteStream({ metadata: { @@ -42,10 +48,10 @@ class StorageService { * @param {string} filename path to file in bucket * @returns {Promise<[Buffer]>} the file data that was returned */ - download(filename) { + download(filename: string): Promise { const file = this.bucket.file(filename); return new Promise((resolve, reject) => { - file.exists().then((doesExist) => { + file.exists().then((doesExist: boolean) => { if (doesExist) { file.download() .then(resolve) @@ -61,7 +67,7 @@ class StorageService { * @param {*} filename the file that you want to delete * @returns {Promise<[ApiResponse]>} */ - delete(filename) { + delete(filename: string) { const file = this.bucket.file(filename); return file.delete(); } @@ -71,7 +77,7 @@ class StorageService { * @param {*} filename the file that you want to check exists * @returns {Promise<[Boolean]>} */ - exists(filename) { + exists(filename: string): boolean { const file = this.bucket.file(filename); return file.exists(); } @@ -79,9 +85,9 @@ class StorageService { * Get the public URL of the file * @param {string} filename the path of the file */ - getPublicUrl(filename) { + getPublicUrl(filename: string): string { return `https://storage.googleapis.com/${this.bucket.name}/${filename}`; } } -module.exports = new StorageService(); +export default new StorageService(); diff --git a/services/team.service.js b/services/team.service.ts similarity index 64% rename from services/team.service.js rename to services/team.service.ts index aed5bd2d..8c67c740 100644 --- a/services/team.service.js +++ b/services/team.service.ts @@ -1,5 +1,7 @@ -"use strict"; -const Team = require("../models/team.model"); +import Team from "../models/team.model"; +import hacker from "../routes/api/hacker"; +import { BaseEntity, UpdateResult } from "typeorm"; + const logger = require("./logger.service"); const Services = { Hacker: require("../services/hacker.service") @@ -10,18 +12,19 @@ const Middleware = { /** * @function findTeamByHackerId - * @param {ObjectId} hackerId objectID of the hacker + * @param {number} hackerId objectID of the hacker * @return {DocumentQuery} The document query will resolve to a team or null. * @description Finds the team that the hacker belongs to, or undefined. */ -function findTeamByHackerId(hackerId) { +async function findTeamByHackerId(hackerId: number): Promise { const TAG = `[Team Service # findTeamByHackerId]:`; - const query = { - members: hackerId - }; + const query = { hackers: hackerId }; - return Team.findOne(query, logger.queryCallbackFactory(TAG, "team", query)); + return await Team.findOne({ where: query }).then((team) => { + logger.queryCallbackFactory(TAG, "team", query); + return team; + }); } /** @@ -30,12 +33,11 @@ function findTeamByHackerId(hackerId) { * @return {Promise} The promise will resolve to a team object if save was successful. * @description Adds a new team to database. */ -async function createTeam(teamDetails) { +async function createTeam(teamDetails: Object): Promise { const TAG = `[Team Service # createTeam]:`; - const team = new Team(teamDetails); - - return team.save(); + const team = Team.create(teamDetails); + return await team.save(); } /** @@ -46,35 +48,31 @@ async function createTeam(teamDetails) { * @description Update a team specified by its mongoId with information specified by teamDetails. */ -function updateOne(id, teamDetails) { +async function updateOne( + identifier: number, + teamDetails: Object +): Promise { const TAG = `[Team Service # updateOne]:`; - const query = { - _id: id - }; - - return Team.findOneAndUpdate( - query, - teamDetails, - logger.updateCallbackFactory(TAG, "team") - ); + return await Team.update(identifier, teamDetails).then((team) => { + logger.updateCallbackFactory(TAG, "team"); + return team; + }); } /** * @function findById - * @param {ObjectId} id + * @param {number} identifier * @return {DocumentQuery} The document query will either resolve to a team or null. * @description Finds a team by its mongoID. */ -function findById(id) { +async function findById(identifier: number): Promise { const TAG = `[Team Service # findById]:`; - const query = { - _id: id - }; - return Team.findById( - query, - logger.queryCallbackFactory(TAG, "team", query) - ); + + return await Team.findOne(identifier).then((team) => { + logger.queryCallbackFactory(TAG, "team", identifier); + return team; + }); } /** @@ -83,45 +81,50 @@ function findById(id) { * @return {DocumentQuery} The document query will either resolve to a team or null. * @description Finds a team by its team name. */ -function findByName(name) { +function findByName(name: string): Promise { const TAG = `[Team Services # findByName]:`; const query = { name: name }; - return Team.findOne(query, logger.queryCallbackFactory(TAG, "team", query)); + return Team.findOne({ where: query }).then((team: Team) => { + logger.queryCallbackFactory(TAG, "team", query); + return team; + }); } /** * @async * @function removeMember - * @param {ObjectId} teamId - * @param {ObjectId} hackerId + * @param {number} teamId + * @param {number} hackerId * @return {DocumentQuery} The document query will resolve to the number of objects removed, or null. * @description Removes the hacker specified by hackerId from a team specified by teamId. */ -async function removeMember(teamId, hackerId) { +async function removeMember(teamId: number, identifier: number) { const TAG = `[Team Services # removeMember]:`; - const hacker = await Services.Hacker.updateOne(hackerId, { - teamId: null + const hacker = await Services.Hacker.updateOne(identifier, { + team: null }); if (!hacker) { return null; } - return Team.findOneAndUpdate( + // TODO - Implement this functionality. + /* return Team.findOneAndUpdate( { - _id: teamId + ident: teamId }, { $pull: { members: hackerId } } - ); + );*/ + return null; } /** @@ -132,7 +135,7 @@ async function removeMember(teamId, hackerId) { * @return {DocumentQuery} Query evaluates to object that details the number of modified documents, or null. * @description Add the hacker specified by hackerId to the team specified by teamId */ -async function addMember(teamId, hackerId) { +async function addMember(teamId: number, hackerId: number) { const TAG = `[Team Services # addMember]:`; const hacker = await Services.Hacker.updateOne(hackerId, { @@ -145,6 +148,8 @@ async function addMember(teamId, hackerId) { return null; } + // TODO - Implement this functionality. + /* return Team.update( { _id: teamId @@ -154,25 +159,24 @@ async function addMember(teamId, hackerId) { members: [hackerId] } } - ); + );*/ + return null; } /** * @async * @function removeTeamIfEmpty * @param {ObjectId} teamId - * @return {DocumentQuery} Query evaluates to object that details the number of modified documents, or null. + * @return {Promise} Query evaluates to object that details the number of modified documents, or null. * @description Removes the team if the team contains no members. Returns null if the team has one or more members, or if the team doesn't exist. */ -async function removeTeamIfEmpty(teamId) { +async function removeTeamIfEmpty(teamId: number) { const TAG = `[Team Services # removeTeam]`; const team = await findById(teamId); - if (team.members.length === 0) { - return Team.deleteOne({ - _id: teamId - }); + if (team?.hackers.length === 0) { + return Team.delete(teamId); } return null; @@ -185,18 +189,18 @@ async function removeTeamIfEmpty(teamId) { * @return {DocumentQuery} The document query will resolve to the number of objects removed, or null. * @description Delete the team specified by teamId. */ -async function removeTeam(teamId) { +async function removeTeam(teamId: number) { const TAG = `[Team Services # removeTeam]`; const team = await findById(teamId); - for (const hackerId of team.members) { - await removeMember(teamId, hackerId); + if (team == null) return null; + + for (const hackerId of team.hackers) { + await removeMember(teamId, hackerId.identifier); } - return Team.deleteOne({ - _id: teamId - }); + return Team.delete(teamId); } /** @@ -206,25 +210,25 @@ async function removeTeam(teamId) { * @return {number} If the team exists, return the number of members in the team. Otherwise, returns -1. * @description Gets the number of current members of a team defined by name */ -async function getSize(name) { +async function getSize(name: string): Promise { const team = await findByName(name); if (!team) { return -1; } else { - return team.members.length; + return team.hackers.length; } } /** * @async * @function isTeamIdValid - * @param {ObjectId} id + * @param {number} id * @return {boolean} * @description Checks whether a Team with the specified mongoID exists. */ -async function isTeamIdValid(id) { - const team = await findById(id); +async function isTeamIdValid(identifier: number): Promise { + const team = await findById(identifier); return !!team; } diff --git a/services/travel.service.js b/services/travel.service.js deleted file mode 100644 index e9a18c6f..00000000 --- a/services/travel.service.js +++ /dev/null @@ -1,112 +0,0 @@ -"use strict"; -const Travel = require("../models/travel.model"); -const logger = require("./logger.service"); - -// const Constants = require("../constants/general.constant"); - - -/** - * @function createTravel - * @param {{_id: ObjectId, accountId: ObjectId, status: enum of Constants.TRAVEL_STATUSES, request: Number, offer?: number}} travelDetails - * @return {Promise} The promise will resolve to a travel object if save is successful. - * @description Adds a new travel to database. - */ -function createTravel(travelDetails) { - const TAG = `[Travel Service # createTravel]:`; - - const travel = new Travel(travelDetails); - - return travel.save(); -} - -/** - * @function updateOne - * @param {ObjectId} id - * @param {{_id?: ObjectId, accountId?: ObjectId, status?: enum of Constants.TRAVEL_STATUSES, request?: Number, offer?: number}} travelDetails - * @return {DocumentQuery} The document query will resolve to travel or null. - * @description Update an travel specified by its mongoId with information specified by travelDetails. - */ -function updateOne(id, travelDetails) { - const TAG = `[Travel Service # update ]:`; - - const query = { - _id: id - }; - - return Travel.findOneAndUpdate( - query, - travelDetails, - logger.updateCallbackFactory(TAG, "travel") - ); -} - -/** - * @function findById - * @param {ObjectId} id - * @return {DocumentQuery} The document query will resolve to travel or null. - * @description Finds an travel by the id, which is the mongoId. - */ -function findById(id) { - const TAG = `[Travel Service # findById ]:`; - - return Travel.findById(id, logger.queryCallbackFactory(TAG, "travel", id)); -} - -/** - * @async - * @function findOne - * @param {JSON} query - * @return {Travel | null} either travel or null - * @description Finds an travel by some query. - */ -async function findIds(queries) { - const TAG = `[Travel Service # findIds ]:`; - let ids = []; - - for (const query of queries) { - let currId = await Travel.findOne( - query, - "_id", - logger.queryCallbackFactory(TAG, "travel", query) - ); - ids.push(currId); - } - return ids; -} - -/** - * @function findByAccountId - * @param {ObjectId} accountId - * @return {DocumentQuery} A travel document queried by accountId - */ -function findByAccountId(accountId) { - const TAG = `[ Travel Service # findByAccountId ]:`; - const query = { - accountId: accountId - }; - - return Travel.findOne(query, logger.updateCallbackFactory(TAG, "travel")); -} - -/** - * @function findByHackerId - * @param {ObjectId} travelId - * @return {DocumentQuery} A travel document queried by hackerId - */ -function findByHackerId(hackerId) { - const TAG = `[ Travel Service # findByAccountId ]:`; - const query = { - hackerId: hackerId - }; - - return Travel.findOne(query, logger.updateCallbackFactory(TAG, "travel")); -} - -module.exports = { - createTravel: createTravel, - findById: findById, - updateOne: updateOne, - findIds: findIds, - findByAccountId: findByAccountId, - findByHackerId: findByHackerId -}; diff --git a/services/travel.service.ts b/services/travel.service.ts new file mode 100644 index 00000000..5d034e60 --- /dev/null +++ b/services/travel.service.ts @@ -0,0 +1,94 @@ +import Travel from "../models/travel.model"; +const logger = require("./logger.service"); +import { UpdateResult } from "typeorm"; + +// const Constants = require("../constants/general.constant"); + +/** + * @function createTravel + * @param {{_id: ObjectId, accountId: ObjectId, status: enum of Constants.TRAVEL_STATUSES, request: Number, offer?: number}} travelDetails + * @return {Promise} The promise will resolve to a travel object if save is successful. + * @description Adds a new travel to database. + */ +async function createTravel(travelDetails: Object): Promise { + const TAG = `[Travel Service # createTravel]:`; + + const travel = Travel.create(travelDetails); + return await travel.save(); +} + +/** + * @function updateOne + * @param {number} identifier + * @param {{_id?: ObjectId, accountId?: ObjectId, status?: enum of Constants.TRAVEL_STATUSES, request?: Number, offer?: number}} travelDetails + * @return {Promise} The document query will resolve to travel or null. + * @description Update an travel specified by its mongoId with information specified by travelDetails. + */ +async function updateOne( + identifier: number, + travelDetails: Object +): Promise { + const TAG = `[Travel Service # update ]:`; + + return await Travel.findOne(identifier, travelDetails).then((travel) => { + logger.updateCallbackFactory(TAG, "travel"); + return travel; + }); +} + +/** + * @function findById + * @param {number} identifier + * @return {Promise} The document query will resolve to travel or null. + * @description Finds an travel by the id, which is the mongoId. + */ +async function findById(identifier: number): Promise { + const TAG = `[Travel Service # findById ]:`; + + return await Travel.findOne(identifier).then((travel) => { + logger.queryCallbackFactory(TAG, "travel", identifier); + return travel; + }); +} + +/** + * @async + * @function findOne + * @param {Object} query + * @return {Promise<(Travel | undefined)[]>} either travel or null + * @description Finds an travel by some query. + */ +async function findIds(queries: Object[]): Promise<(Travel | undefined)[]> { + const TAG = `[Travel Service # findIds ]:`; + let ids = []; + + for (const query of queries) { + let current = await Travel.findOne({ where: query }).then( + (travel: Travel) => { + logger.queryCallbackFactory(TAG, "travel", query); + return travel; + } + ); + ids.push(current); + } + return ids; +} + +/** + * @function findByHackerId + * @param {number} identifier + * @return {Promise} A travel document queried by accountId + */ +async function findByHackerId(identifier: number): Promise { + const TAG = `[ Travel Service # findByHackerId ]:`; + const query = { + hacker: identifier + }; + + return await Travel.findOne({ where: query }).then((travel) => { + logger.updateCallbackFactory(TAG, "travel"); + return travel; + }); +} + +export { createTravel, findById, updateOne, findIds, findByHackerId }; diff --git a/services/version.service.js b/services/version.service.js deleted file mode 100644 index ae41666d..00000000 --- a/services/version.service.js +++ /dev/null @@ -1,10 +0,0 @@ -"use strict"; -const { version } = require("../package.json"); - -const get = function() { - return version; -}; - -module.exports = { - get: get -}; diff --git a/services/version.service.ts b/services/version.service.ts new file mode 100644 index 00000000..9809b867 --- /dev/null +++ b/services/version.service.ts @@ -0,0 +1,7 @@ +import { version } from "../package.json"; + +const get = function() { + return version; +}; + +export { get }; diff --git a/services/volunteer.service.js b/services/volunteer.service.js deleted file mode 100644 index d1156a9d..00000000 --- a/services/volunteer.service.js +++ /dev/null @@ -1,56 +0,0 @@ -"use strict"; -const Volunteer = require("../models/volunteer.model"); -const logger = require("./logger.service"); - -/** - * @function createVolunteer - * @param {{_id: ObjectId, accountId: ObjectId}} volunteerDetails - * @return {Promise} The promise will resolve to a volunteer object if save was successful. - * @description Adds a new volunteer to database. - */ -function createVolunteer(volunteerDetails) { - const TAG = `[Volunteer Service # createTeam]:`; - - const volunteer = new Volunteer(volunteerDetails); - - return volunteer.save(); -} - -/** - * @function findById - * @param {ObjectId} id - * @return {DocumentQuery} The document query will resolve to volunteer or null. - * @description Finds an volunteer by the id, which is the mongoId. - */ -function findById(id) { - const TAG = `[Volunteer Service # findById ]:`; - - return Volunteer.findById( - id, - logger.queryCallbackFactory(TAG, "volunteer", id) - ); -} - -/** - * @function findByAccountId - * @param {ObjectId} accountId - * @return {DocumentQuery} A volunteer document queried by accountId - */ -function findByAccountId(accountId) { - const TAG = `[ Volunteer Service # findByAccountId ]:`; - - const query = { - accountId: accountId - }; - - return Volunteer.findOne( - query, - logger.updateCallbackFactory(TAG, "volunteer") - ); -} - -module.exports = { - createVolunteer: createVolunteer, - findById: findById, - findByAccountId: findByAccountId -}; diff --git a/services/volunteer.service.ts b/services/volunteer.service.ts new file mode 100644 index 00000000..bab8e16c --- /dev/null +++ b/services/volunteer.service.ts @@ -0,0 +1,45 @@ +import Volunteer from "../models/volunteer.model"; +const logger = require("./logger.service"); + +/** + * @function createVolunteer + * @param {{_id: ObjectId, accountId: ObjectId}} volunteerDetails + * @return {Promise} The promise will resolve to a volunteer object if save was successful. + * @description Adds a new volunteer to database. + */ +async function createVolunteer(volunteerDetails: Object): Promise { + const TAG = `[Volunteer Service # createTeam]:`; + + const volunteer = Volunteer.create(volunteerDetails); + return await volunteer.save(); +} + +/** + * @function findById + * @param {number} identifier + * @return {Promise} The document query will resolve to volunteer or null. + * @description Finds an volunteer by the id, which is the mongoId. + */ +async function findById(identifier: number): Promise { + const TAG = `[Volunteer Service # findById ]:`; + + return await Volunteer.findOne(identifier).then((volunteer) => { + logger.queryCallbackFactory(TAG, "volunteer", identifier); + return volunteer; + }); +} + +// TODO: Deprecrate / remove this function. +/** + * @function findByAccountId + * @param {number} accountId + * @return {Promise} A volunteer document queried by accountId + */ +async function findByAccountId( + accountId: number +): Promise { + const TAG = `[ Volunteer Service # findByAccountId ]:`; + return this.findById(accountId); +} + +export { createVolunteer, findById, findByAccountId }; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..9bba37af --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "experimentalDecorators": true, + "target": "ES5", + "lib": ["ES6", "ES2017"], + "noImplicitAny": true, + "strictNullChecks": true, + "alwaysStrict": true, + "removeComments": true, + "preserveConstEnums": true, + "sourceMap": true, + "outDir": "dist/", + "allowJs": true, + //"checkJs": true, + "esModuleInterop": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "emitDecoratorMetadata": true + }, + "include": ["./**/*", ".env"], + "exclude": ["node_modules", "**/*.spec.ts", ".vscode", ".github", ".idea", "docs", "scripts", "tests"] +} From 72d48a4a395a178c206439e38d5199d49f2ecba3 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Sat, 11 Dec 2021 21:41:12 -0500 Subject: [PATCH 04/72] refactor: first push towards decorator based approach for middleware and controllers. - change main application launch point from bin/www.js to app.ts - wrap app.ts in an async call to allow database connection. (async/await for #connect()). - general code cleanup for app.ts - move the following services to the decorator/class-based model with dependency injection: - EnvService - DatabaseService - LoggerService - AccountService - move the following controllers to the decorator/class-based model with dependency injection: - ApplicationController - create class-based authentication and authorization. - EnsureAuthenticated - EnsureAuthorized - authorization no longer depends on the :self/:all pre-definition in a constants file and instead checks against the authorization level and the identifier provided by an authenticated user to verify permission to access resources. - move passport authentication strategy to it's own class and combine the user serialization/de-serialization with it. - refactor LoggerService to provide general purpose logger instead of exporting winston loggers. - fix EnvService GCP file creation (added a schema). - fix small bug where error would be thrown regardless of launch for EnvService as we were checking if a result was not null instead of result.error. - refactor DatabaseService: - genericize database information method (port, host, etc...). - remove application callbacks and logging - we should add this back in a later update. - add class-transformer to strip password from JSON response on account model. - add class-validator for fields on account model. - expand the use of this package to all models. - change the following constant files to typescript: - Error Constants - General Constants - Success Constants - todos: - various todo's have been left throughout the codebase, it would be fruitless to leave a list here, as you can simply query them by searching: - TODO --- app.js | 133 --------- app.ts | 82 ++++++ constants/authorization-level.constant.ts | 8 + .../{error.constant.js => error.constant.ts} | 92 +++---- ...eneral.constant.js => general.constant.ts} | 256 +++++++++--------- ...uccess.constant.js => success.constant.ts} | 103 +++---- controllers/account.controller.ts | 122 +++++++++ controllers/authentication.controller.ts | 50 ++++ middlewares/authenticated.middleware.ts | 27 ++ middlewares/authorization.middleware.ts | 84 ++++++ models/account.model.ts | 35 ++- package.json | 7 +- services/account.service.ts | 185 ++++--------- services/database.service.ts | 145 ++-------- services/email.service.ts | 41 ++- services/env.service.ts | 98 ++++--- services/logger.service.ts | 117 ++++---- strategy/emailAndPassword.strategy.ts | 59 ++++ 18 files changed, 874 insertions(+), 770 deletions(-) delete mode 100755 app.js create mode 100755 app.ts create mode 100644 constants/authorization-level.constant.ts rename constants/{error.constant.js => error.constant.ts} (50%) rename constants/{general.constant.js => general.constant.ts} (50%) rename constants/{success.constant.js => success.constant.ts} (59%) create mode 100644 controllers/account.controller.ts create mode 100644 controllers/authentication.controller.ts create mode 100644 middlewares/authenticated.middleware.ts create mode 100644 middlewares/authorization.middleware.ts create mode 100644 strategy/emailAndPassword.strategy.ts diff --git a/app.js b/app.js deleted file mode 100755 index 99e529a4..00000000 --- a/app.js +++ /dev/null @@ -1,133 +0,0 @@ -"use strict"; -const express = require("express"); -import path from "path"; -const cookieParser = require("cookie-parser"); -const cookieSession = require("cookie-session"); -const cors = require("cors"); -const Services = { - log: require("./services/logger.service"), - db: require("./services/database.service"), - auth: require("./services/auth.service"), - env: require("./services/env.service") -}; - -const envLoadResult = Services.env.load(path.resolve(__dirname, ".env")); -if (envLoadResult.error) { - Services.log.warn(envLoadResult.error); -} - -const passport = require("passport"); -passport.use("emailAndPass", Services.auth.emailAndPassStrategy); - -/* Routes here */ -const indexRouter = require("./routes/index"); -const accountRouter = require("./routes/api/account"); -const authRouter = require("./routes/api/auth"); -const hackerRouter = require("./routes/api/hacker"); -const teamRouter = require("./routes/api/team"); -const travelRouter = require("./routes/api/travel"); -const sponsorRouter = require("./routes/api/sponsor"); -const searchRouter = require("./routes/api/search"); -const settingsRouter = require("./routes/api/settings"); -const volunteerRouter = require("./routes/api/volunteer"); -const roleRouter = require("./routes/api/role"); - -const app = express(); -Services.db.connect(app); - -let corsOptions = {}; - -if (!Services.env.isProduction()) { - corsOptions = { - origin: [`http://${process.env.FRONTEND_ADDRESS_DEV}`], - credentials: true - }; -} else { - // TODO: change this when necessary - corsOptions = { - origin: [ - `https://${process.env.FRONTEND_ADDRESS_DEPLOY}`, - `https://${process.env.FRONTEND_ADDRESS_BETA}`, - `https://docs.mchacks.ca` - ], - credentials: true - }; -} - -app.use(cors(corsOptions)); -app.use(Services.log.requestLogger); -app.use(Services.log.errorLogger); -app.use(express.json()); -app.use( - express.urlencoded({ - extended: false - }) -); -app.use(cookieParser()); -//Cookie-based session tracking -app.use( - cookieSession({ - name: "session", - keys: [process.env.COOKIE_SECRET], - // Cookie Options - maxAge: 48 * 60 * 60 * 1000 //Logged in for 48 hours - }) -); -app.use(passport.initialize()); -app.use(passport.session()); //persistent login session - -app.use(express.static(path.join(__dirname, "public"))); - -var apiRouter = express.Router(); - -accountRouter.activate(apiRouter); -Services.log.info("Account router activated"); -authRouter.activate(apiRouter); -Services.log.info("Auth router activated"); -hackerRouter.activate(apiRouter); -Services.log.info("Hacker router activated"); -teamRouter.activate(apiRouter); -Services.log.info("Team router activated"); -travelRouter.activate(apiRouter); -Services.log.info("Travel router activated") -sponsorRouter.activate(apiRouter); -Services.log.info("Sponsor router activated"); -volunteerRouter.activate(apiRouter); -Services.log.info("Volunteer router activated"); -searchRouter.activate(apiRouter); -Services.log.info("Search router activated"); -settingsRouter.activate(apiRouter); -Services.log.info("Settings router activated"); -roleRouter.activate(apiRouter); -Services.log.info("Role router activated"); - -apiRouter.use("/", indexRouter); -app.use("/", indexRouter); - -app.use("/api", apiRouter); - -//Custom error handler -app.use((err, req, res, next) => { - // log the error... - const status = err.status ? err.status : 500; - const message = err.message ? err.message : "Internal Server Error"; - //Only show bad error when we're not in deployment - let errorContents; - if (status === 500 && Services.env.isProduction) { - errorContents = {}; - } else if (err.error) { - errorContents = err.error; - } else if (err.data) { - errorContents = err.data; - } else { - errorContents = err; - } - res.status(status).json({ - message: message, - data: errorContents - }); -}); - -module.exports = { - app: app -}; diff --git a/app.ts b/app.ts new file mode 100755 index 00000000..8e4df2ad --- /dev/null +++ b/app.ts @@ -0,0 +1,82 @@ +import { attachControllerInstances } from "@decorators/express"; +import express from "express"; +import passport from "passport"; +import { join } from "path"; +import { container } from "tsyringe"; +import { AccountController } from "./controllers/account.controller"; +import { AuthenticationController } from "./controllers/authentication.controller"; +import { DatabaseService } from "./services/database.service"; +import { EnvService } from "./services/env.service"; +import { LoggerService } from "./services/logger.service"; +const cookieParser = require("cookie-parser"); +const cookieSession = require("cookie-session"); +const cors = require("cors"); + +(async () => { + const application = express(); + + const envService: EnvService = container.resolve(EnvService); + const loggerService: LoggerService = container.resolve(LoggerService); + const databaseService: DatabaseService = container.resolve(DatabaseService); + await databaseService.connect(); + + let corsOptions = {}; + + if (!envService.isProduction()) { + corsOptions = { + origin: [`http://${process.env.FRONTEND_ADDRESS_DEV}`], + credentials: true + }; + } else { + // TODO: change this when necessary + corsOptions = { + origin: [ + `https://${process.env.FRONTEND_ADDRESS_DEPLOY}`, + `https://${process.env.FRONTEND_ADDRESS_BETA}`, + `https://docs.mchacks.ca` + ], + credentials: true + }; + } + + application.use(cors(corsOptions)); + + application.use( + loggerService.getRequestLogger(), + loggerService.getErrorLogger() + ); + + application.use( + express.json(), + express.urlencoded({ + extended: false + }) + ); + + //Cookie-based session tracking + application.use( + cookieParser(), + cookieSession({ + name: "session", + keys: [process.env.COOKIE_SECRET], + // Cookie Options + maxAge: 48 * 60 * 60 * 1000 //Logged in for 48 hours + }) + ); + + application.use(passport.initialize(), passport.session()); //persistent login session + + application.use(express.static(join(__dirname, "public"))); + + const router = express.Router(); + attachControllerInstances(router, [ + container.resolve(AccountController), + container.resolve(AuthenticationController) + ]); + application.use("/api", router); + + const port = process.env.PORT ?? 3000; + application.listen(port, () => { + loggerService.getLogger().info(`Listening on port ${port}...`); + }); +})(); diff --git a/constants/authorization-level.constant.ts b/constants/authorization-level.constant.ts new file mode 100644 index 00000000..791ed425 --- /dev/null +++ b/constants/authorization-level.constant.ts @@ -0,0 +1,8 @@ +export enum AuthorizationLevel { + Staff = "Staff", + Sponsor = "Sponsor", + Volunteer = "Volunteer", + Hacker = "Hacker", + Account = "Account", + None = "None", +} diff --git a/constants/error.constant.js b/constants/error.constant.ts similarity index 50% rename from constants/error.constant.js rename to constants/error.constant.ts index c86160e8..89a38941 100644 --- a/constants/error.constant.js +++ b/constants/error.constant.ts @@ -1,5 +1,3 @@ -"use strict"; - const ACCOUNT_404_MESSAGE = "Account not found"; const HACKER_404_MESSAGE = "Hacker not found"; const TEAM_404_MESSAGE = "Team not found"; @@ -15,7 +13,7 @@ const SPONSOR_ID_409_MESSAGE = "Conflict with sponsor accountId link"; const VOLUNTEER_ID_409_MESSAGE = "Conflict with volunteer accountId link"; const HACKER_ID_409_MESSAGE = "Conflict with hacker accountId link"; const TEAM_MEMBER_409_MESSAGE = - "Conflict with team member being in another team"; + "Conflict with team member being in another team"; const TEAM_NAME_409_MESSAGE = "Conflict with team name already in use"; const HACKER_STATUS_409_MESSAGE = "Conflict with hacker status"; const TEAM_SIZE_409_MESSAGE = "Team full"; @@ -26,7 +24,7 @@ const VALIDATION_422_MESSAGE = "Validation failed"; const ACCOUNT_DUPLICATE_422_MESSAGE = "Account already exists"; const ROLE_DUPLICATE_422_MESSAGE = "Role already exists"; const SETTINGS_422_MESSAGE = - "openTime must be before closeTime, and closeTime must be before confirmTime"; + "openTime must be before closeTime, and closeTime must be before confirmTime"; const ACCOUNT_TOKEN_401_MESSAGE = "Invalid token for account"; const AUTH_401_MESSAGE = "Invalid Authentication"; @@ -50,47 +48,47 @@ const LOGIN_500_MESSAGE = "Error while logging in"; const ROLE_CREATE_500_MESSAGE = "Error while creating role"; const TRAVEL_CREATE_500_MESSAGE = "Error while creating travel"; -module.exports = { - ACCOUNT_404_MESSAGE: ACCOUNT_404_MESSAGE, - HACKER_404_MESSAGE: HACKER_404_MESSAGE, - TEAM_404_MESSAGE: TEAM_404_MESSAGE, - RESUME_404_MESSAGE: RESUME_404_MESSAGE, - ACCOUNT_TYPE_409_MESSAGE: ACCOUNT_TYPE_409_MESSAGE, - ACCOUNT_EMAIL_409_MESSAGE: ACCOUNT_EMAIL_409_MESSAGE, - SPONSOR_ID_409_MESSAGE: SPONSOR_ID_409_MESSAGE, - VOLUNTEER_ID_409_MESSAGE: VOLUNTEER_ID_409_MESSAGE, - TEAM_MEMBER_409_MESSAGE: TEAM_MEMBER_409_MESSAGE, - TEAM_MEMBER_422_MESSAGE: TEAM_MEMBER_422_MESSAGE, - VALIDATION_422_MESSAGE: VALIDATION_422_MESSAGE, - ACCOUNT_TOKEN_401_MESSAGE: ACCOUNT_TOKEN_401_MESSAGE, - AUTH_401_MESSAGE: AUTH_401_MESSAGE, - AUTH_403_MESSAGE: AUTH_403_MESSAGE, - ACCOUNT_403_MESSAGE: ACCOUNT_403_MESSAGE, - TEAM_UPDATE_500_MESSAGE: TEAM_UPDATE_500_MESSAGE, - HACKER_UPDATE_500_MESSAGE: HACKER_UPDATE_500_MESSAGE, - HACKER_ID_409_MESSAGE: HACKER_ID_409_MESSAGE, - ACCOUNT_UPDATE_500_MESSAGE: ACCOUNT_UPDATE_500_MESSAGE, - HACKER_CREATE_500_MESSAGE: HACKER_CREATE_500_MESSAGE, - SPONSOR_404_MESSAGE: SPONSOR_404_MESSAGE, - SPONSOR_CREATE_500_MESSAGE: SPONSOR_CREATE_500_MESSAGE, - TEAM_CREATE_500_MESSAGE: TEAM_CREATE_500_MESSAGE, - VOLUNTEER_CREATE_500_MESSAGE: VOLUNTEER_CREATE_500_MESSAGE, - EMAIL_500_MESSAGE: EMAIL_500_MESSAGE, - GENERIC_500_MESSAGE: GENERIC_500_MESSAGE, - ACCOUNT_DUPLICATE_422_MESSAGE: ACCOUNT_DUPLICATE_422_MESSAGE, - LOGIN_500_MESSAGE: LOGIN_500_MESSAGE, - HACKER_STATUS_409_MESSAGE: HACKER_STATUS_409_MESSAGE, - TEAM_SIZE_409_MESSAGE: TEAM_SIZE_409_MESSAGE, - ROLE_DUPLICATE_422_MESSAGE: ROLE_DUPLICATE_422_MESSAGE, - SETTINGS_422_MESSAGE: SETTINGS_422_MESSAGE, - ROLE_CREATE_500_MESSAGE: ROLE_CREATE_500_MESSAGE, - TEAM_NAME_409_MESSAGE: TEAM_NAME_409_MESSAGE, - TEAM_JOIN_SAME_409_MESSAGE: TEAM_JOIN_SAME_409_MESSAGE, - TEAM_READ_500_MESSAGE: TEAM_READ_500_MESSAGE, - VOLUNTEER_404_MESSAGE: VOLUNTEER_404_MESSAGE, - SPONSOR_UPDATE_500_MESSAGE: SPONSOR_UPDATE_500_MESSAGE, - SETTINGS_404_MESSAGE: SETTINGS_404_MESSAGE, - SETTINGS_403_MESSAGE: SETTINGS_403_MESSAGE, - TRAVEL_404_MESSAGE: TRAVEL_404_MESSAGE, - TRAVEL_CREATE_500_MESSAGE: TRAVEL_CREATE_500_MESSAGE +export { + ACCOUNT_404_MESSAGE, + HACKER_404_MESSAGE, + TEAM_404_MESSAGE, + RESUME_404_MESSAGE, + ACCOUNT_TYPE_409_MESSAGE, + ACCOUNT_EMAIL_409_MESSAGE, + SPONSOR_ID_409_MESSAGE, + VOLUNTEER_ID_409_MESSAGE, + TEAM_MEMBER_409_MESSAGE, + TEAM_MEMBER_422_MESSAGE, + VALIDATION_422_MESSAGE, + ACCOUNT_TOKEN_401_MESSAGE, + AUTH_401_MESSAGE, + AUTH_403_MESSAGE, + ACCOUNT_403_MESSAGE, + TEAM_UPDATE_500_MESSAGE, + HACKER_UPDATE_500_MESSAGE, + HACKER_ID_409_MESSAGE, + ACCOUNT_UPDATE_500_MESSAGE, + HACKER_CREATE_500_MESSAGE, + SPONSOR_404_MESSAGE, + SPONSOR_CREATE_500_MESSAGE, + TEAM_CREATE_500_MESSAGE, + VOLUNTEER_CREATE_500_MESSAGE, + EMAIL_500_MESSAGE, + GENERIC_500_MESSAGE, + ACCOUNT_DUPLICATE_422_MESSAGE, + LOGIN_500_MESSAGE, + HACKER_STATUS_409_MESSAGE, + TEAM_SIZE_409_MESSAGE, + ROLE_DUPLICATE_422_MESSAGE, + SETTINGS_422_MESSAGE, + ROLE_CREATE_500_MESSAGE, + TEAM_NAME_409_MESSAGE, + TEAM_JOIN_SAME_409_MESSAGE, + TEAM_READ_500_MESSAGE, + VOLUNTEER_404_MESSAGE, + SPONSOR_UPDATE_500_MESSAGE, + SETTINGS_404_MESSAGE, + SETTINGS_403_MESSAGE, + TRAVEL_404_MESSAGE, + TRAVEL_CREATE_500_MESSAGE, }; diff --git a/constants/general.constant.js b/constants/general.constant.ts similarity index 50% rename from constants/general.constant.js rename to constants/general.constant.ts index 5e23d2fe..76a4c628 100644 --- a/constants/general.constant.js +++ b/constants/general.constant.ts @@ -1,12 +1,12 @@ -"use strict"; - const HACKATHON_NAME = "McHacks"; // constants kept in alphabetical order // matches optional http://, https://, http:, https:, and optional www., and then matches for devpost.com and further parameters -const DEVPOST_REGEX = /^(http(s)?:(\/\/)?)?(www\.)?(([-a-zA-Z0-9@:%._\+~#=]{2,256}\.)?devpost\.com)\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/; +const DEVPOST_REGEX = + /^(http(s)?:(\/\/)?)?(www\.)?(([-a-zA-Z0-9@:%._\+~#=]{2,256}\.)?devpost\.com)\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/; // from https://emailregex.com -const EMAIL_REGEX = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; +const EMAIL_REGEX = + /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; const HACKER_STATUS_NONE = "None"; const HACKER_STATUS_APPLIED = "Applied"; const HACKER_STATUS_ACCEPTED = "Accepted"; @@ -16,14 +16,14 @@ const HACKER_STATUS_CONFIRMED = "Confirmed"; const HACKER_STATUS_WITHDRAWN = "Withdrawn"; const HACKER_STATUS_CHECKED_IN = "Checked-in"; const HACKER_STATUSES = [ - HACKER_STATUS_NONE, - HACKER_STATUS_APPLIED, - HACKER_STATUS_ACCEPTED, - HACKER_STATUS_WAITLISTED, - HACKER_STATUS_CONFIRMED, - HACKER_STATUS_WITHDRAWN, - HACKER_STATUS_CHECKED_IN, - HACKER_STATUS_DECLINED + HACKER_STATUS_NONE, + HACKER_STATUS_APPLIED, + HACKER_STATUS_ACCEPTED, + HACKER_STATUS_WAITLISTED, + HACKER_STATUS_CONFIRMED, + HACKER_STATUS_WITHDRAWN, + HACKER_STATUS_CHECKED_IN, + HACKER_STATUS_DECLINED, ]; // This date is Jan 6, 2020 00:00:00 GMT -0500 const APPLICATION_CLOSE_TIME = 1578286800000; @@ -31,8 +31,8 @@ const APPLICATION_CLOSE_TIME = 1578286800000; const CONFIRMATION_TYPE_INVITE = "Invite"; const CONFIRMATION_TYPE_ORGANIC = "Organic"; const CONFIRMATION_TYPES = [ - CONFIRMATION_TYPE_INVITE, - CONFIRMATION_TYPE_ORGANIC + CONFIRMATION_TYPE_INVITE, + CONFIRMATION_TYPE_ORGANIC, ]; const TRAVEL_STATUS_NONE = "None"; // Hacker has not been offered compensation for travelling @@ -43,30 +43,30 @@ const TRAVEL_STATUS_VALID = "Valid"; // Hacker has been offered some amount of c const TRAVEL_STATUS_INVALID = "Invalid"; // Hacker has been offered some amount of compensation for travelling but have uploaded reciepts which we have confirmed to be an inapproprate amount const TRAVEL_STATUS_CLAIMED = "Claimed"; // Hacker has been offered some amount of compensation and has recieved such the funds const TRAVEL_STATUSES = [ - TRAVEL_STATUS_NONE, - TRAVEL_STATUS_BUS, - TRAVEL_STATUS_POLICY, - TRAVEL_STATUS_OFFERED, - TRAVEL_STATUS_VALID, - TRAVEL_STATUS_INVALID, - TRAVEL_STATUS_CLAIMED + TRAVEL_STATUS_NONE, + TRAVEL_STATUS_BUS, + TRAVEL_STATUS_POLICY, + TRAVEL_STATUS_OFFERED, + TRAVEL_STATUS_VALID, + TRAVEL_STATUS_INVALID, + TRAVEL_STATUS_CLAIMED, ]; const SAMPLE_DIET_RESTRICTIONS = [ - "None", - "Vegan", - "Vegetarian", - "Keto", - "Gluten free", - "Pescetarian", - "Peanut allergy", - "Milk allergy", - "Egg allergy", - "Allergy", - "No beef", - "No porc", - "No fish", - "No shellfish" + "None", + "Vegan", + "Vegetarian", + "Keto", + "Gluten free", + "Pescetarian", + "Peanut allergy", + "Milk allergy", + "Egg allergy", + "Allergy", + "No beef", + "No porc", + "No fish", + "No shellfish", ]; const HACKER = "Hacker"; @@ -87,67 +87,69 @@ const PREVIOUS_HACKATHONS = [0, 1, 2, 3, 4, 5]; const ATTENDANCE_PREFERENCES = ["Remote", "In Person"]; const ROLE_CATEGORIES = { - SELF: ":self", - ALL: ":all" + SELF: ":self", + ALL: ":all", }; // enum of type of requests const REQUEST_TYPES = { - GET: "GET", - POST: "POST", - PATCH: "PATCH", - DELETE: "DELETE", - PUT: "PUT" + GET: "GET", + POST: "POST", + PATCH: "PATCH", + DELETE: "DELETE", + PUT: "PUT", }; //Define names of the roles specifically associated with permission to create an account -const POST_ROLES = {}; -POST_ROLES[HACKER] = "postHacker"; -POST_ROLES[SPONSOR_T1] = "postSponsor"; -POST_ROLES[SPONSOR_T2] = "postSponsor"; -POST_ROLES[SPONSOR_T3] = "postSponsor"; -POST_ROLES[SPONSOR_T4] = "postSponsor"; -POST_ROLES[SPONSOR_T5] = "postSponsor"; -POST_ROLES[VOLUNTEER] = "postVolunteer"; -POST_ROLES[STAFF] = "postStaff"; +const POST_ROLES = { + Hacker: "postHacker", + SponsorT1: "postSponsor", + SponsorT2: "postSponsor", + SponsorT3: "postSponsor", + SponsorT4: "postSponsor", + SponsorT5: "postSponsor", + Volunteer: "postSponsor", + Staff: "postSponsor", +}; const USER_TYPES = [HACKER, VOLUNTEER, STAFF, SPONSOR]; const SPONSOR_TIERS = [ - SPONSOR_T1, - SPONSOR_T2, - SPONSOR_T3, - SPONSOR_T4, - SPONSOR_T5 + SPONSOR_T1, + SPONSOR_T2, + SPONSOR_T3, + SPONSOR_T4, + SPONSOR_T5, ]; const EXTENDED_USER_TYPES = [ - HACKER, - VOLUNTEER, - STAFF, - SPONSOR_T1, - SPONSOR_T2, - SPONSOR_T3, - SPONSOR_T4, - SPONSOR_T5 + HACKER, + VOLUNTEER, + STAFF, + SPONSOR_T1, + SPONSOR_T2, + SPONSOR_T3, + SPONSOR_T4, + SPONSOR_T5, ]; // matches optional http://, https://, http:, https:, and optional www. // matches the domain, and then optional route, path, query parameters -const URL_REGEX = /^(http(s)?:(\/\/)?)?(www\.)?([-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6})\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/; +const URL_REGEX = + /^(http(s)?:(\/\/)?)?(www\.)?([-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6})\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/; const ANY_REGEX = /^.+$/; const MAX_TEAM_SIZE = 4; const WEEK_OF = "Week Of"; -const EMAIL_SUBJECTS = {}; +const EMAIL_SUBJECTS: any = {}; EMAIL_SUBJECTS[HACKER_STATUS_NONE] = `Get started on your application!`; EMAIL_SUBJECTS[ - HACKER_STATUS_APPLIED + HACKER_STATUS_APPLIED ] = `Thanks for applying to ${HACKATHON_NAME}!`; EMAIL_SUBJECTS[HACKER_STATUS_ACCEPTED] = `Great update from ${HACKATHON_NAME}`; EMAIL_SUBJECTS[HACKER_STATUS_DECLINED] = `Update from ${HACKATHON_NAME}`; EMAIL_SUBJECTS[HACKER_STATUS_WAITLISTED] = `Update from ${HACKATHON_NAME}`; EMAIL_SUBJECTS[ - HACKER_STATUS_CONFIRMED + HACKER_STATUS_CONFIRMED ] = `Thanks for confirming your attendance to ${HACKATHON_NAME}`; EMAIL_SUBJECTS[HACKER_STATUS_WITHDRAWN] = "Sorry to see you go"; EMAIL_SUBJECTS[HACKER_STATUS_CHECKED_IN] = `Welcome to ${HACKATHON_NAME}`; @@ -155,75 +157,75 @@ EMAIL_SUBJECTS[HACKER_STATUS_CHECKED_IN] = `Welcome to ${HACKATHON_NAME}`; EMAIL_SUBJECTS[WEEK_OF] = `Welcome to ${HACKATHON_NAME}`; const CONFIRM_ACC_EMAIL_SUBJECT = `Confirm your ${HACKATHON_NAME} Account`; -const CREATE_ACC_EMAIL_SUBJECTS = {}; +const CREATE_ACC_EMAIL_SUBJECTS: any = {}; CREATE_ACC_EMAIL_SUBJECTS[ - HACKER + HACKER ] = `You've been invited to create a hacker account for ${HACKATHON_NAME}`; CREATE_ACC_EMAIL_SUBJECTS[ - SPONSOR + SPONSOR ] = `You've been invited to create a sponsor account for ${HACKATHON_NAME}`; CREATE_ACC_EMAIL_SUBJECTS[ - VOLUNTEER + VOLUNTEER ] = `You've been invited to create a volunteer account for ${HACKATHON_NAME}`; CREATE_ACC_EMAIL_SUBJECTS[ - STAFF + STAFF ] = `You've been invited to create a staff account for ${HACKATHON_NAME}`; const CACHE_TIMEOUT_STATS = 5 * 60 * 1000; const CACHE_KEY_STATS = "hackerStats"; -module.exports = { - HACKATHON_NAME: HACKATHON_NAME, - DEVPOST_REGEX: DEVPOST_REGEX, - EMAIL_REGEX: EMAIL_REGEX, - ANY_REGEX: ANY_REGEX, - HACKER_STATUS_NONE: HACKER_STATUS_NONE, - HACKER_STATUS_APPLIED: HACKER_STATUS_APPLIED, - HACKER_STATUS_ACCEPTED: HACKER_STATUS_ACCEPTED, - HACKER_STATUS_DECLINED: HACKER_STATUS_DECLINED, - HACKER_STATUS_WAITLISTED: HACKER_STATUS_WAITLISTED, - HACKER_STATUS_CONFIRMED: HACKER_STATUS_CONFIRMED, - HACKER_STATUS_WITHDRAWN: HACKER_STATUS_WITHDRAWN, - HACKER_STATUS_CHECKED_IN: HACKER_STATUS_CHECKED_IN, - HACKER_STATUSES: HACKER_STATUSES, - TRAVEL_STATUS_NONE: TRAVEL_STATUS_NONE, - TRAVEL_STATUS_BUS: TRAVEL_STATUS_BUS, - TRAVEL_STATUS_POLICY: TRAVEL_STATUS_POLICY, - TRAVEL_STATUS_OFFERED: TRAVEL_STATUS_OFFERED, - TRAVEL_STATUS_VALID: TRAVEL_STATUS_VALID, - TRAVEL_STATUS_INVALID: TRAVEL_STATUS_INVALID, - TRAVEL_STATUS_CLAIMED: TRAVEL_STATUS_CLAIMED, - TRAVEL_STATUSES: TRAVEL_STATUSES, - APPLICATION_CLOSE_TIME: APPLICATION_CLOSE_TIME, - REQUEST_TYPES: REQUEST_TYPES, - JOB_INTERESTS: JOB_INTERESTS, - SHIRT_SIZES: SHIRT_SIZES, - PREVIOUS_HACKATHONS: PREVIOUS_HACKATHONS, - ATTENDANCE_PREFERENCES: ATTENDANCE_PREFERENCES, - USER_TYPES: USER_TYPES, - SPONSOR_TIERS: SPONSOR_TIERS, - EXTENDED_USER_TYPES: EXTENDED_USER_TYPES, - URL_REGEX: URL_REGEX, - EMAIL_SUBJECTS: EMAIL_SUBJECTS, - CREATE_ACC_EMAIL_SUBJECTS: CREATE_ACC_EMAIL_SUBJECTS, - CONFIRM_ACC_EMAIL_SUBJECT: CONFIRM_ACC_EMAIL_SUBJECT, - HACKER: HACKER, - SPONSOR: SPONSOR, - VOLUNTEER: VOLUNTEER, - STAFF: STAFF, - SPONSOR_T1: SPONSOR_T1, - SPONSOR_T2: SPONSOR_T2, - SPONSOR_T3: SPONSOR_T3, - SPONSOR_T4: SPONSOR_T4, - SPONSOR_T5: SPONSOR_T5, - ROLE_CATEGORIES: ROLE_CATEGORIES, - POST_ROLES: POST_ROLES, - CACHE_TIMEOUT_STATS: CACHE_TIMEOUT_STATS, - CACHE_KEY_STATS: CACHE_KEY_STATS, - MAX_TEAM_SIZE: MAX_TEAM_SIZE, - WEEK_OF: WEEK_OF, - SAMPLE_DIET_RESTRICTIONS: SAMPLE_DIET_RESTRICTIONS, - CONFIRMATION_TYPES: CONFIRMATION_TYPES, - CONFIRMATION_TYPE_INVITE: CONFIRMATION_TYPE_INVITE, - CONFIRMATION_TYPE_ORGANIC: CONFIRMATION_TYPE_ORGANIC +export { + HACKATHON_NAME, + DEVPOST_REGEX, + EMAIL_REGEX, + ANY_REGEX, + HACKER_STATUS_NONE, + HACKER_STATUS_APPLIED, + HACKER_STATUS_ACCEPTED, + HACKER_STATUS_DECLINED, + HACKER_STATUS_WAITLISTED, + HACKER_STATUS_CONFIRMED, + HACKER_STATUS_WITHDRAWN, + HACKER_STATUS_CHECKED_IN, + HACKER_STATUSES, + TRAVEL_STATUS_NONE, + TRAVEL_STATUS_BUS, + TRAVEL_STATUS_POLICY, + TRAVEL_STATUS_OFFERED, + TRAVEL_STATUS_VALID, + TRAVEL_STATUS_INVALID, + TRAVEL_STATUS_CLAIMED, + TRAVEL_STATUSES, + APPLICATION_CLOSE_TIME, + REQUEST_TYPES, + JOB_INTERESTS, + SHIRT_SIZES, + PREVIOUS_HACKATHONS, + ATTENDANCE_PREFERENCES, + USER_TYPES, + SPONSOR_TIERS, + EXTENDED_USER_TYPES, + URL_REGEX, + EMAIL_SUBJECTS, + CREATE_ACC_EMAIL_SUBJECTS, + CONFIRM_ACC_EMAIL_SUBJECT, + HACKER, + SPONSOR, + VOLUNTEER, + STAFF, + SPONSOR_T1, + SPONSOR_T2, + SPONSOR_T3, + SPONSOR_T4, + SPONSOR_T5, + ROLE_CATEGORIES, + POST_ROLES, + CACHE_TIMEOUT_STATS, + CACHE_KEY_STATS, + MAX_TEAM_SIZE, + WEEK_OF, + SAMPLE_DIET_RESTRICTIONS, + CONFIRMATION_TYPES, + CONFIRMATION_TYPE_INVITE, + CONFIRMATION_TYPE_ORGANIC, }; diff --git a/constants/success.constant.js b/constants/success.constant.ts similarity index 59% rename from constants/success.constant.js rename to constants/success.constant.ts index 13e63959..03174aef 100644 --- a/constants/success.constant.js +++ b/constants/success.constant.ts @@ -1,5 +1,3 @@ -"use strict"; - const ACCOUNT_GET_BY_EMAIL = "Account found by user email."; const ACCOUNT_GET_BY_ID = "Account found by user id."; const ACCOUNT_READ = "Account retrieval successful."; @@ -55,60 +53,49 @@ const TEAM_HACKER_LEAVE = "Removal from team successful."; const VOLUNTEER_GET_BY_ID = "Volunteer found by id"; const VOLUNTEER_CREATE = "Volunteer creation successful."; -module.exports = { - ACCOUNT_GET_BY_EMAIL: ACCOUNT_GET_BY_EMAIL, - ACCOUNT_GET_BY_ID: ACCOUNT_GET_BY_ID, - ACCOUNT_CREATE: ACCOUNT_CREATE, - ACCOUNT_UPDATE: ACCOUNT_UPDATE, - ACCOUNT_INVITE: ACCOUNT_INVITE, - ACCOUNT_GET_INVITES: ACCOUNT_GET_INVITES, - ACCOUNT_READ: ACCOUNT_READ, - AUTH_LOGIN: AUTH_LOGIN, - AUTH_LOGOUT: AUTH_LOGOUT, - AUTH_SEND_RESET_EMAIL: AUTH_SEND_RESET_EMAIL, - AUTH_RESET_PASSWORD: AUTH_RESET_PASSWORD, - AUTH_CONFIRM_ACCOUNT: AUTH_CONFIRM_ACCOUNT, - AUTH_GET_ROLE_BINDINGS: AUTH_GET_ROLE_BINDINGS, - AUTH_SEND_CONFIRMATION_EMAIL: AUTH_SEND_CONFIRMATION_EMAIL, - AUTH_GET_ROLES: AUTH_GET_ROLES, - - HACKER_GET_BY_ID: HACKER_GET_BY_ID, - HACKER_READ: HACKER_READ, - HACKER_CREATE: HACKER_CREATE, - HACKER_UPDATE: HACKER_UPDATE, - - HACKER_UPDATE_BATCH: HACKER_UPDATE_BATCH, - - HACKER_SENT_WEEK_OF: HACKER_SENT_WEEK_OF, - HACKER_SENT_DAY_OF: HACKER_SENT_DAY_OF, - - RESUME_UPLOAD: RESUME_UPLOAD, - RESUME_DOWNLOAD: RESUME_DOWNLOAD, - - TRAVEL_READ: TRAVEL_READ, - TRAVEL_CREATE: TRAVEL_CREATE, - TRAVE_UPDATE: TRAVEL_UPDATE, - - ROLE_CREATE: ROLE_CREATE, - - SEARCH_QUERY: SEARCH_QUERY, - SEARCH_NO_RESULTS: SEARCH_NO_RESULTS, - - SETTINGS_GET: SETTINGS_GET, - SETTINGS_PATCH: SETTINGS_PATCH, - - SPONSOR_GET_BY_ID: SPONSOR_GET_BY_ID, - SPONSOR_CREATE: SPONSOR_CREATE, - SPONSOR_READ: SPONSOR_READ, - SPONSOR_UPDATE: SPONSOR_UPDATE, - - TEAM_GET_BY_ID: TEAM_GET_BY_ID, - TEAM_CREATE: TEAM_CREATE, - TEAM_JOIN: TEAM_JOIN, - TEAM_UPDATE: TEAM_UPDATE, - TEAM_READ: TEAM_READ, - TEAM_HACKER_LEAVE: TEAM_HACKER_LEAVE, - - VOLUNTEER_GET_BY_ID: VOLUNTEER_GET_BY_ID, - VOLUNTEER_CREATE: VOLUNTEER_CREATE +export { + ACCOUNT_GET_BY_EMAIL, + ACCOUNT_GET_BY_ID, + ACCOUNT_CREATE, + ACCOUNT_UPDATE, + ACCOUNT_INVITE, + ACCOUNT_GET_INVITES, + ACCOUNT_READ, + AUTH_LOGIN, + AUTH_LOGOUT, + AUTH_SEND_RESET_EMAIL, + AUTH_RESET_PASSWORD, + AUTH_CONFIRM_ACCOUNT, + AUTH_GET_ROLE_BINDINGS, + AUTH_SEND_CONFIRMATION_EMAIL, + AUTH_GET_ROLES, + HACKER_GET_BY_ID, + HACKER_READ, + HACKER_CREATE, + HACKER_UPDATE, + HACKER_UPDATE_BATCH, + HACKER_SENT_WEEK_OF, + HACKER_SENT_DAY_OF, + RESUME_UPLOAD, + RESUME_DOWNLOAD, + TRAVEL_READ, + TRAVEL_CREATE, + TRAVEL_UPDATE, + ROLE_CREATE, + SEARCH_QUERY, + SEARCH_NO_RESULTS, + SETTINGS_GET, + SETTINGS_PATCH, + SPONSOR_GET_BY_ID, + SPONSOR_CREATE, + SPONSOR_READ, + SPONSOR_UPDATE, + TEAM_GET_BY_ID, + TEAM_CREATE, + TEAM_JOIN, + TEAM_UPDATE, + TEAM_READ, + TEAM_HACKER_LEAVE, + VOLUNTEER_GET_BY_ID, + VOLUNTEER_CREATE, }; diff --git a/controllers/account.controller.ts b/controllers/account.controller.ts new file mode 100644 index 00000000..3dd6a01a --- /dev/null +++ b/controllers/account.controller.ts @@ -0,0 +1,122 @@ +import { Response as ExpressResponse } from "express"; +import { autoInjectable } from "tsyringe"; +import { AccountService } from "../services/account.service"; +import * as SuccessConstants from "../constants/success.constant"; +import * as ErrorConstants from "../constants/error.constant"; +import { + Body, + Controller, + Get, + Params, + Patch, + Post, + Response +} from "@decorators/express"; +import Account from "../models/account.model"; +import { EnsureAuthenticated } from "../middlewares/authenticated.middleware"; +import { EnsureAuthorization } from "../middlewares/authorization.middleware"; +import { AuthorizationLevel } from "../constants/authorization-level.constant"; + +@autoInjectable() +@Controller("/account") +export class AccountController { + constructor(private readonly accountService: AccountService) {} + + @Get("/", [ + EnsureAuthenticated, + EnsureAuthorization([ + AuthorizationLevel.Staff, + AuthorizationLevel.Account + ]) + ]) + async getByEmail( + @Response() response: ExpressResponse, + @Body("email") email: string + ) { + const account = await this.accountService.findByEmail(email); + + return account + ? response.status(200).json({ + message: SuccessConstants.ACCOUNT_READ, + data: account + }) + : response.status(404).json({ + message: ErrorConstants.ACCOUNT_404_MESSAGE + }); + } + + @Get("/:identifier", [ + EnsureAuthenticated, + EnsureAuthorization([ + AuthorizationLevel.Staff, + AuthorizationLevel.Account + ]) + ]) + async getByIdentifier( + @Response() response: ExpressResponse, + @Params("identifier") identifier: number + ) { + const account: + | Account + | undefined = await this.accountService.findByIdentifier( + identifier + ); + + return account + ? response.status(200).json({ + message: SuccessConstants.ACCOUNT_READ, + data: account + }) + : response.status(404).json({ + message: ErrorConstants.ACCOUNT_404_MESSAGE + }); + } + + @Post("/") + async create( + @Response() response: ExpressResponse, + @Body() account: Account + ) { + const result: Account = await this.accountService.save(account); + + return result + ? response.status(200).json({ + message: SuccessConstants.ACCOUNT_CREATE, + data: result + }) + : response.status(422).json({ + message: ErrorConstants.ACCOUNT_DUPLICATE_422_MESSAGE + }); + } + + // (Add middleware for sendConfirmAccountEmail and update database confirmed: false, email: newEmail) + @Patch("/:identifier", [ + EnsureAuthenticated, + EnsureAuthorization([ + AuthorizationLevel.Staff, + AuthorizationLevel.Account + ]) + ]) + async update( + @Response() response: ExpressResponse, + @Params("identifier") identifier: number, + @Body() update: Partial + ) { + //TODO - Implement resend e-mail confirmation and verification. + const result = await this.accountService.update(identifier, update); + + return result + ? response.status(200).json({ + message: SuccessConstants.ACCOUNT_UPDATE, + data: result + }) + : response.status(404).json({ + message: ErrorConstants.ACCOUNT_404_MESSAGE, + data: { + identifier: identifier + } + }); + } + + //TODO - Implement (gotInvites, invitedAccount) +} diff --git a/controllers/authentication.controller.ts b/controllers/authentication.controller.ts new file mode 100644 index 00000000..6f1ef651 --- /dev/null +++ b/controllers/authentication.controller.ts @@ -0,0 +1,50 @@ +import { Controller, Post, Request, Response } from "@decorators/express"; +import { autoInjectable } from "tsyringe"; +import { + Request as ExpressRequest, + Response as ExpressResponse +} from "express"; +import { EmailAndPasswordStrategy } from "../strategy/emailAndPassword.strategy"; +import passport from "passport"; +import Account from "../models/account.model"; +import * as ErrorConstants from "../constants/error.constant"; +import * as SuccessConstants from "../constants/success.constant"; + +@autoInjectable() +@Controller("/authentication") +export class AuthenticationController { + constructor(private readonly strategy: EmailAndPasswordStrategy) {} + + @Post("/sign-in") + async signIn( + @Request() request: ExpressRequest, + @Response() response: ExpressResponse + ) { + passport.authenticate(this.strategy, (error: any, user: Account) => { + if (error) + return response.status(500).json({ + message: ErrorConstants.GENERIC_500_MESSAGE, + error: error + }); + + if (!user) + return response.status(401).json({ + message: ErrorConstants.AUTH_401_MESSAGE, + error: {} + }); + + request.login(user, (error) => { + if (error) + return response.status(500).json({ + message: ErrorConstants.LOGIN_500_MESSAGE, + error: {} + }); + + return response.status(200).json({ + message: SuccessConstants.AUTH_LOGIN, + data: {} + }); + }); + })(request, response); + } +} diff --git a/middlewares/authenticated.middleware.ts b/middlewares/authenticated.middleware.ts new file mode 100644 index 00000000..eb529cc9 --- /dev/null +++ b/middlewares/authenticated.middleware.ts @@ -0,0 +1,27 @@ +import { Middleware } from "@decorators/express"; +import { Request, Response, NextFunction } from "express"; +import { ParamsDictionary } from "express-serve-static-core"; +import { ParsedQs } from "qs"; +import * as ErrorConstants from "../constants/error.constant"; + +export class EnsureAuthenticated implements Middleware { + use( + request: Request< + ParamsDictionary, + any, + any, + ParsedQs, + Record + >, + _: Response>, + next: NextFunction + ): void { + if (request.isUnauthenticated()) + return next({ + status: 401, + message: ErrorConstants.AUTH_401_MESSAGE, + error: { route: request.path } + }); + return next(); + } +} diff --git a/middlewares/authorization.middleware.ts b/middlewares/authorization.middleware.ts new file mode 100644 index 00000000..e221540c --- /dev/null +++ b/middlewares/authorization.middleware.ts @@ -0,0 +1,84 @@ +import { Middleware } from "@decorators/express"; +import { Request, Response, NextFunction } from "express"; +import { ParamsDictionary } from "express-serve-static-core"; +import { ParsedQs } from "qs"; +import { container, delay, inject, injectable } from "tsyringe"; +import * as ErrorConstants from "../constants/error.constant"; +import { AuthorizationLevel } from "../constants/authorization-level.constant"; +import Account from "../models/account.model"; +import { AccountService } from "../services/account.service"; + +// TODO - Improve the logic of the middleware to reduce duplication of response. +// TODO - Provide proper comments / documentation. +// TODO - Find a better way to pass parameters rather than encapsulating middleware class. +// Current solution found from https://github.com/serhiisol/node-decorators/issues/111 +// Library Author Suggest's Dependency Injection. +export function EnsureAuthorization(roles: Array): any { + @injectable() + class EnsureAuthorizationClass implements Middleware { + constructor( + @inject(delay(() => AccountService)) + private readonly accountService: AccountService + ) {} + + async use( + request: Request< + ParamsDictionary, + any, + any, + ParsedQs, + Record + >, + response: Response>, + next: NextFunction + ) { + if ( + roles.includes(AuthorizationLevel.None) || + //@ts-ignore + request.user?.accountType === + AuthorizationLevel.Staff.toString() + ) + return next(); + + if ( + !roles.includes(AuthorizationLevel.Account) && + //@ts-ignore + !roles.includes(request.user?.accountType) + ) + return response.status(403).json({ + message: ErrorConstants.AUTH_403_MESSAGE, + error: { route: request.originalUrl } + }); + + if (request.params["identifier"]) { + const query: + | Account + | undefined = await this.accountService.findByIdentifier( + parseInt(request.params["identifier"]) + ); + //@ts-ignore + if (query?.identifier !== request.user?.identifier) + return response.status(403).json({ + message: ErrorConstants.AUTH_403_MESSAGE, + error: { route: request.originalUrl } + }); + } + + if (request.params["email"] != null) { + const query: + | Account + | undefined = await this.accountService.findByEmail( + request.params["email"] + ); + //@ts-ignore + if (query?.email !== request.user?.email) + return response.status(403).json({ + message: ErrorConstants.AUTH_403_MESSAGE, + error: { route: request.originalUrl } + }); + } + return next(); + } + } + return container.resolve(EnsureAuthorizationClass); +} diff --git a/models/account.model.ts b/models/account.model.ts index 23102f06..91ac634c 100644 --- a/models/account.model.ts +++ b/models/account.model.ts @@ -1,37 +1,39 @@ -import { Column, Entity, PrimaryGeneratedColumn, BaseEntity } from "typeorm"; +import { Column, Entity, PrimaryGeneratedColumn } from "typeorm"; import { compareSync } from "bcrypt"; -import { IsEmail, IsPhoneNumber } from "class-validator"; +import { IsDate, IsEmail, IsPhoneNumber } from "class-validator"; import * as Constants from "../constants/general.constant"; +import { classToPlain, Exclude } from "class-transformer"; @Entity() -export class Account extends BaseEntity { +export abstract class Account { @PrimaryGeneratedColumn() identifier: number; - @Column("varchar", { nullable: false }) + @Column({ nullable: false }) firstName: string; - @Column("varchar", { nullable: false }) + @Column({ nullable: false }) lastName: string; - @Column("varchar", { default: "Prefer not to say" }) + @Column({ default: "Prefer not to say" }) pronoun: string; - @Column("varchar", { default: "Prefer not to say" }) + @Column({ default: "Prefer not to say" }) gender: string; - @Column("varchar", { nullable: false, unique: true }) + @Column({ nullable: false, unique: true }) @IsEmail() email: string; - @Column("varchar", { nullable: false }) + @Column({ nullable: false }) + @Exclude({ toPlainOnly: true }) password: string; - @Column("varchar") + @Column() dietaryRestrictions: string; - @Column("bool", { default: false }) - confirmed: Boolean; + @Column({ default: false }) + confirmed: boolean; @Column({ enum: Constants.EXTENDED_USER_TYPES, @@ -44,15 +46,10 @@ export class Account extends BaseEntity { @Column() @IsPhoneNumber() - phoneNumber: number; + phoneNumber: string; toJSON() { - return this; - } - - // Delete's Password - toStrippedJSON() { - return { ...this, password: undefined }; + return classToPlain(this); } /** diff --git a/package.json b/package.json index c2f697e7..78888a85 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,7 @@ "version": "3.1.3", "private": true, "scripts": { - "build": "tsc", - "start": "DEBUG=hackboard:* NODE_ENV=test rimraf dist/ && tsc && cp .env ./dist/.env && nodemon --ignore gcp_creds.json ./dist/bin/www.js", + "start": "DEBUG=hackboard:* NODE_ENV=test rimraf dist/ && tsc && cp .env ./dist/.env && nodemon --ignore gcp_creds.json ./dist/app.js", "start-windows": "set DEBUG=hackboard:* && set NODE_ENV=test && nodemon --ignore gcp_creds.json ./bin/www.js", "deploy": "NODE_ENV=deployment node ./bin/www.js", "debug": "DEBUG=hackboard:* NODE_ENV=test nodemon --ignore gcp_creds.json ./bin/www.js", @@ -15,9 +14,12 @@ "lint": "eslint --fix '**/*.js'" }, "dependencies": { + "@decorators/di": "^1.0.3", + "@decorators/express": "^2.6.0", "@google-cloud/storage": "^5.10.0", "@sendgrid/mail": "^7.4.5", "bcrypt": "^5.0.1", + "class-transformer": "^0.5.1", "class-validator": "^0.13.2", "cookie-parser": "^1.4.5", "cookie-session": "^2.0.0-rc.1", @@ -40,6 +42,7 @@ "q": "^1.5.1", "qrcode": "^1.4.4", "reflect-metadata": "^0.1.13", + "tsyringe": "^4.6.0", "typeorm": "^0.2.41", "typescript": "^4.5.2", "winston": "^3.3.3" diff --git a/services/account.service.ts b/services/account.service.ts index 7e60f4c2..4142d22c 100644 --- a/services/account.service.ts +++ b/services/account.service.ts @@ -1,146 +1,67 @@ -const Hacker = require("../models/hacker.model"); import Account from "../models/account.model"; -import * as logger from "./logger.service"; import { hashSync } from "bcrypt"; +import { getRepository, Repository, UpdateResult } from "typeorm"; +import { autoInjectable } from "tsyringe"; -/** - * @function findById - * @param {Number} id - * @return {Account} Will resolve to either account or null. - * @description Finds an account by identifier. - */ -async function findById(id: number): Promise { - const TAG = `[Account Service # findById]:`; - return await Account.findOne(id).then((account) => { - logger.queryCallbackFactory(TAG, "account", id); - return account; - }); -} +@autoInjectable() +export class AccountService { + private readonly accountRepository: Repository; -/** - * @function findByHackerId - * @param {number} identifier the Hacker's ID - * @returns {Promise} The account of the hacker, minus the password. Returns null if the hacker does not exist, or if the hacker is not associated with an account. - * Get the account by using the hacker's ID. - */ -//TODO: Complete this message. -async function findByHackerId(identifier: number) { - const TAG = `[Account Service # findByHackerId]:`; - const query = { - _id: identifier - }; - const hacker = await Hacker.findById( - query, - logger.queryCallbackFactory(TAG, "account", query) - ).populate({ - path: "accountId", - select: " -password" - }); - if (!hacker || !hacker.accountId) { - return null; + constructor() { + this.accountRepository = getRepository(Account); } - return hacker.accountId; -} - -/** - * @function findByEmail - * @param {String} email - * @return {Account} Will resolve to either account or null. - * @description Find an account by email. - */ -function findByEmail(email: string) { - const query = { email: email }; - - return findOne(query); -} - -/** - * @param {String} email - * @param {String} password - * @return {Account | null} either account or null - */ -async function getAccountIfValid(email: string, password: string) { - const account = await findByEmail(email); - return !!account && account.comparePassword(password) ? account : null; -} - -/** - * @function hashPassword - * @param {String} password - * @return {string} hashed password - * @description Hashes password with bcrypt. - */ -function hashPassword(password: string) { - return hashSync(password, 10); -} - -/** - * @function findOne - * @param {*} query - * @return {Account} Will resolve to either account or null. - * @description Finds an account by some query. - */ -function findOne(query: Object): Promise { - const TAG = `[Account Service # findOne ]:`; + public async findByIdentifier( + identifier: number + ): Promise { + return await this.accountRepository.findOne(identifier); + } - return Account.findOne(query).then((account) => { - logger.queryCallbackFactory(TAG, "account", query); - return account; - }); -} + public async findByEmail(email: string): Promise { + return await this.accountRepository.findOne({ + where: { email: email } + }); + } -/** - * @function addOneAccount - * @param {{identifier: number, firstName: string, lastName: string, email: string, password: string}} accountDetails - * @return {Promise} The promise will resolve to the account object if save is successful. - * @description Adds a new account to database. - */ -//TODO: Make all functions that call this async. -async function addOneAccount(accountDetails: Object): Promise { - const TAG = `[Account Service # addOneAccount ]:`; + public async save(account: Account): Promise { + account.password = this.hashPassword(account.password); + return await this.accountRepository.save(account); + } - const account = Account.create(accountDetails); + public async update( + identifier: number, + account: Partial + ): Promise { + return await this.accountRepository.update(identifier, account); + } - return await account.save(); -} + public async updateEmail( + identifier: number, + email: string + ): Promise { + return await this.accountRepository.update(identifier, { + email: email, + confirmed: false + }); + } -/** - * @function updateOne - * @param {number} identifier - * @param {{identifier?: number, firstName?: string, lastName?: string, email?: string, password?: string}} accountDetails - * @return {DocumentQuery} The document query will resolve to either account or null. - * @description Changes account information to the specified information in accountDetails. - */ -function updateOne(identifier: number, accountDetails: Object) { - const TAG = `[Account Service # updateOne ]:`; + public async updatePassword(identifier: number, password: string) { + return await this.accountRepository.update(identifier, { + password: this.hashPassword(password) + }); + } - return Account.update(identifier, accountDetails).then((account) => { - logger.updateCallbackFactory(TAG, "account"); - return account; - }); -} + public async getAccountIfValid( + email: string, + password: string + ): Promise { + const account = await this.findByEmail(email); + return account && account.comparePassword(password) + ? account + : undefined; + } -/** - * Updates the password for an account. This function also hashes the password. - * @param {number} identifier String representing the ObjectId of the account - * @param {string} newPassword the new password for the account (in plain-text). - */ -async function updatePassword(identifier: number, newPassword: string) { - const hashed = hashPassword(newPassword); - return await updateOne(identifier, { - password: hashed - }); + public hashPassword(password: string): string { + return hashSync(password, 10); + } } - -export { - findOne, - findById, - findByHackerId, - findByEmail, - addOneAccount, - getAccountIfValid, - hashPassword, - updateOne, - updatePassword -}; diff --git a/services/database.service.ts b/services/database.service.ts index 8ed18592..9235ca83 100644 --- a/services/database.service.ts +++ b/services/database.service.ts @@ -1,118 +1,31 @@ -import { Connection, createConnection } from "typeorm"; -const logger = require("./logger.service"); - -const TAG = "[ DATABASE SERVICE ]"; -import * as env from "./env.service"; -import Account from "../models/account.model"; -import AccountConfirmation from "../models/accountConfirmationToken.model"; -import Application from "../models/application.model"; -import Bus from "../models/bus.model"; -import EmailTemplate from "../models/emailTemplate.model"; -import Hacker from "../models/hacker.model"; -import PasswordReset from "../models/passwordResetToken.model"; -import Role from "../models/role.model"; -import RoleBinding from "../models/roleBinding.model"; -import Settings from "../models/settings.model"; -import Sponsor from "../models/sponsor.model"; -import Staff from "../models/staff.model"; -import Team from "../models/team.model"; -import Travel from "../models/travel.model"; -import Volunteer from "../models/volunteer.model"; - -// if DB is defined as an env var, it will go there, elsewise, try local -// you ideally set DB to your database uri that the provider gives you -// it should be easily findable - -// DATABASE SERVICE -function getHostFromEnvironment() { - return process.env.NODE_ENV == "development" - ? process.env.DB_HOST_DEV - : process.env.NODE_ENV == "deployment" - ? process.env.DB_HOST_DEPLOY - : process.env.DB_HOST_TEST; -} - -function getPortFromEnvironment() { - return process.env.NODE_ENV == "development" - ? process.env.DB_PORT_DEV - : process.env.NODE_ENV == "deployment" - ? process.env.DB_PORT_DEPLOY - : process.env.DB_PORT_TEST; -} - -function getNameFromEnvironment() { - return process.env.NODE_ENV == "development" - ? process.env.DB_NAME_DEV - : process.env.NODE_ENV == "deployment" - ? process.env.DB_NAME_DEPLOY - : process.env.DB_NAME_TEST; -} - -function getUserFromEnvironment() { - return process.env.NODE_ENV == "development" - ? process.env.DB_USER_DEV - : process.env.NODE_ENV == "deployment" - ? process.env.DB_USER_DEPLOY - : process.env.DB_USER_TEST; -} - -function getPassFromEnvironment() { - return process.env.NODE_ENV == "development" - ? process.env.DB_PASS_DEV - : process.env.NODE_ENV == "deployment" - ? process.env.DB_PASS_DEPLOY - : process.env.DB_PASS_TEST; -} - -async function connect(app: any, callback: any) { - const host = getHostFromEnvironment(); - // TODO - Fix this hack. - const port = parseInt(getPortFromEnvironment()!); - const user = getUserFromEnvironment(); - const password = getPassFromEnvironment(); - const database = getNameFromEnvironment(); - logger.info(`${TAG} Connecting to db on ${host}`); - await createConnection({ - type: "postgres", - host: host, - port: port, - username: user, - password: password, - database: database, - entities: [ - Account, - AccountConfirmation, - Application, - Bus, - EmailTemplate, - Hacker, - PasswordReset, - Role, - RoleBinding, - Settings, - Sponsor, - Staff, - Team, - Travel, - Volunteer - ] - }) - .then((connection: Connection) => { - connection.synchronize(); - logger.info(`${TAG} Connected to database on ${host}`); - if (app) { - app.emit("event:connected to db"); - } - if (callback) { - callback(); - } - }) - .catch((error) => { - logger.error( - `${TAG} Failed to connect to database at ${host}. Error: ${error}` - ); - throw `Failed to connect to database at ${host}`; +import { createConnection } from "typeorm"; + +import { autoInjectable, singleton } from "tsyringe"; +import { EnvService } from "./env.service"; + +@autoInjectable() +@singleton() +export class DatabaseService { + constructor(private readonly envService: EnvService) {} + + public async connect() { + await createConnection({ + type: "postgres", + host: this.getDatabaseAttribute("HOST"), + port: parseInt(this.getDatabaseAttribute("PORT")!), + username: this.getDatabaseAttribute("USER"), + password: this.getDatabaseAttribute("PASSPORT"), + database: this.getDatabaseAttribute("NAME"), + synchronize: true, + entities: [__dirname + "/../**/**.model{.ts,.js}"] }); + } + + private getDatabaseAttribute(name: string) { + return this.envService.isDevelopment() + ? this.envService.get(`DB_${name}_ENV`) + : this.envService.isProduction() + ? this.envService.get(`DB_${name}_DEPLOY`) + : this.envService.get(`DB_${name}_TEST`); + } } - -export { connect }; diff --git a/services/email.service.ts b/services/email.service.ts index 7ae6fa79..473f5394 100644 --- a/services/email.service.ts +++ b/services/email.service.ts @@ -1,16 +1,15 @@ -"use strict"; -const logger = require("./logger.service"); import client from "@sendgrid/mail"; -import * as fs from "fs"; -import * as path from "path"; -const TAG = `[ EMAIL.SERVICE ]`; -const env = require("../services/env.service"); +import { readFileSync } from "fs"; +import { join } from "path"; const Constants = require("../constants/general.constant"); import * as Handlebars from "handlebars"; +import { autoInjectable } from "tsyringe"; +import { EnvService } from "./env.service"; -class EmailService { - constructor(apiKey: string = "") { - client.setApiKey(apiKey); +@autoInjectable() +export class EmailService { + constructor(private readonly envService: EnvService) { + client.setApiKey(this.envService.get("SENDGRID_API_KEY") ?? ""); } /** @@ -19,7 +18,7 @@ class EmailService { * @param {(err?)=>void} callback */ send(mailData: any, callback = (error?: Object) => {}) { - if (env.isTest()) { + if (this.envService.isTest()) { //Silence all actual emails if we're testing mailData.mailSettings = { sandboxMode: { @@ -66,17 +65,14 @@ class EmailService { ticket: string, callback = (error?: Object) => {} ) { - const handlebarsPath = path.join( - __dirname, - `../assets/email/Ticket.hbs` - ); + const handlebarsPath = join(__dirname, `../assets/email/Ticket.hbs`); const html = this.renderEmail(handlebarsPath, { firstName: firstName, ticket: ticket }); const mailData = { to: recipient, - from: process.env.NO_REPLY_EMAIL, + from: this.envService.get("NO_REPLY_EMAIL"), subject: Constants.EMAIL_SUBJECTS[Constants.WEEK_OF], html: html }; @@ -102,16 +98,13 @@ class EmailService { recipient: string, callback = (error?: Object) => {} ) { - const handlebarsPath = path.join( - __dirname, - `../assets/email/Welcome.hbs` - ); + const handlebarsPath = join(__dirname, `../assets/email/Welcome.hbs`); const html = this.renderEmail(handlebarsPath, { firstName: firstName }); const mailData = { to: recipient, - from: process.env.NO_REPLY_EMAIL, + from: this.envService.get("NO_REPLY_EMAIL"), subject: Constants.EMAIL_SUBJECTS[Constants.WEEK_OF], html: html }; @@ -133,13 +126,13 @@ class EmailService { status: string, callback = (error?: Object) => {} ) { - const handlebarsPath = path.join( + const handlebarsPath = join( __dirname, `../assets/email/statusEmail/${status}.hbs` ); const mailData = { to: recipient, - from: process.env.NO_REPLY_EMAIL, + from: this.envService.get("NO_REPLY_EMAIL"), subject: Constants.EMAIL_SUBJECTS[status], html: this.renderEmail(handlebarsPath, { firstName: firstName @@ -162,10 +155,8 @@ class EmailService { * @param {*} context any variables that need to be replaced in the template file */ renderEmail(path: string, context: Object) { - const templateStr = fs.readFileSync(path).toString(); + const templateStr = readFileSync(path).toString(); const template = Handlebars.compile(templateStr); return template(context); } } - -module.exports = new EmailService(process.env.SENDGRID_API_KEY); diff --git a/services/env.service.ts b/services/env.service.ts index e163128f..84d84998 100644 --- a/services/env.service.ts +++ b/services/env.service.ts @@ -1,47 +1,61 @@ -import { config } from "dotenv"; +import { config, DotenvConfigOutput } from "dotenv"; import * as fs from "fs"; -import * as path from "path"; -const Logger = require("./logger.service"); - -function load(path: string) { - const result = config({ - path: path - }); - createGCPFile(); - return result; +import { join } from "path"; +import { autoInjectable, singleton } from "tsyringe"; + +interface GoogleCloudPlatformCredentials { + type: string | undefined; + project_id: string | undefined; + private_key_id: string | undefined; + private_key: string | undefined; + client_email: string | undefined; + client_id: string | undefined; + auth_uri: string | undefined; + token_uri: string | undefined; + auth_provider_x509_cert_url: string | undefined; + client_x509_cert_url: string | undefined; } -const isDevelopment = (): boolean => process.env.NODE_ENV === "test"; - -const isProduction = (): boolean => process.env.NODE_ENV === "deployment"; - -const isTest = (): boolean => process.env.NODE_ENV === "test"; - -export { load, isDevelopment, isProduction, isTest }; - -function createGCPFile() { - const creds = { - type: process.env.TYPE, - project_id: process.env.PROJECT_ID, - private_key_id: process.env.PRIVATE_KEY_ID, - private_key: process.env.PRIVATE_KEY, - client_email: process.env.CLIENT_EMAIL, - client_id: process.env.CLIENT_ID, - auth_uri: process.env.AUTH_URI, - token_uri: process.env.TOKEN_URI, - auth_provider_x509_cert_url: process.env.AUTH_PROVIDER_X509_CERT_URL, - client_x509_cert_url: process.env.CLIENT_X509_CERT_URL - }; - for (var property in creds) { - if (creds.hasOwnProperty(property)) { - if (typeof property === "undefined") { - Logger.error(`GCP credential ${property} was undefined.`); - } - } +@autoInjectable() +@singleton() +export class EnvService { + constructor() { + const result: DotenvConfigOutput = config({ + path: join(__dirname, "../.env") + }); + if (result.error) throw result.error; + this.createGoogleCloudPlatformFile(); } - const stringified = JSON.stringify(creds); - const unEscaped = stringified.replace(/\\\\n/g, "\\n"); - const fileLocation = path.join(__dirname, "../gcp_creds.json"); - fs.writeFileSync(fileLocation, unEscaped); - process.env.GOOGLE_APPLICATION_CREDENTIALS = fileLocation; + + private createGoogleCloudPlatformFile() { + const credentials: GoogleCloudPlatformCredentials = { + type: process.env.TYPE, + project_id: process.env.PROJECT_ID, + private_key_id: process.env.PRIVATE_KEY_ID, + private_key: process.env.PRIVATE_KEY, + client_email: process.env.CLIENT_EMAIL, + client_id: process.env.CLIENT_ID, + auth_uri: process.env.AUTH_URI, + token_uri: process.env.TOKEN_URI, + auth_provider_x509_cert_url: + process.env.AUTH_PROVIDER_X509_CERT_URL, + client_x509_cert_url: process.env.CLIENT_X509_CERT_URL + }; + + const stringified = JSON.stringify(credentials); + const unEscaped = stringified.replace(/\\\\n/g, "\\n"); + const fileLocation = join(__dirname, "../../gcp_creds.json"); + fs.writeFileSync(fileLocation, unEscaped); + process.env.GOOGLE_APPLICATION_CREDENTIALS = fileLocation; + } + + public get(key: string) { + return process.env[key]; + } + + public isDevelopment = (): boolean => process.env.NODE_ENV === "test"; + + public isProduction = (): boolean => process.env.NODE_ENV === "deployment"; + + public isTest = (): boolean => process.env.NODE_ENV === "test"; } diff --git a/services/logger.service.ts b/services/logger.service.ts index 5d81b21d..785cbe11 100755 --- a/services/logger.service.ts +++ b/services/logger.service.ts @@ -5,80 +5,59 @@ import winston, { log, verbose, debug, - silly + silly, + Logger } from "winston"; import expressWinston from "express-winston"; +import { inject, injectable, singleton } from "tsyringe"; +import { ErrorRequestHandler, Handler, Response } from "express"; +import { EnvService } from "./env.service"; +import { Format } from "logform"; -const colorize = process.env.NODE_ENV !== "deployment"; +@injectable() +@singleton() +export class LoggerService { + private readonly logger: Logger; + private readonly requestLogger: Handler; + private readonly errorLogger: ErrorRequestHandler; -const errorLogger = expressWinston.errorLogger({ - transports: [new winston.transports.Console()], - format: winston.format.combine( - winston.format.json(), - winston.format.colorize(), - winston.format.timestamp() - ) -}); + constructor(@inject(EnvService) envService: EnvService) { + const format: Format = winston.format.combine( + winston.format.colorize({ all: true }), + winston.format.timestamp({ + format: "MM/D/YYYY HH:MM:SS" + }), + winston.format.printf((info) => { + return `${info.timestamp} [${info.level}] : ${info.message}`; + }) + ); -const requestLogger = expressWinston.logger({ - transports: [new winston.transports.Console()], - format: winston.format.combine( - winston.format.json(), - winston.format.colorize(), - winston.format.timestamp() - ), - colorize: colorize, - expressFormat: true, - meta: false -}); + this.logger = winston.createLogger({ + transports: [new winston.transports.Console()], + format: format + }); -function queryCallbackFactory(TAG: string, model: string, query: Object) { - // err is error, res is result - return (err: Error, res: Object) => { - if (err) { - winston.error( - `${TAG} Failed to verify if ${model} exist or not using ${JSON.stringify( - query - )}`, - err - ); - } else if (res) { - winston.debug( - `${TAG} ${model} using ${JSON.stringify( - query - )} exist in the database` - ); - } else { - winston.debug( - `${TAG} ${model} using ${JSON.stringify( - query - )} do not exist in the database` - ); - } - }; -} + this.requestLogger = expressWinston.logger({ + transports: [new winston.transports.Console()], + format: format, + colorize: !envService.isProduction() + }); -function updateCallbackFactory(TAG: string, model: string) { - return (err: Error, res: Object) => { - if (err) { - winston.error(`${TAG} failed to change ${model}`); - } else if (!res) { - winston.error(`${TAG} failed to find ${model} in database`); - } else { - winston.debug(`${TAG} changed ${model} information`); - } - }; -} + this.errorLogger = expressWinston.errorLogger({ + transports: [new winston.transports.Console()], + format: format + }); + } -export { - updateCallbackFactory, - queryCallbackFactory, - requestLogger, - errorLogger, - error, - warn, - info, - verbose, - debug, - silly -}; + public getLogger() { + return this.logger; + } + + public getRequestLogger(): Handler { + return this.requestLogger; + } + + public getErrorLogger(): ErrorRequestHandler { + return this.errorLogger; + } +} diff --git a/strategy/emailAndPassword.strategy.ts b/strategy/emailAndPassword.strategy.ts new file mode 100644 index 00000000..5c93c41d --- /dev/null +++ b/strategy/emailAndPassword.strategy.ts @@ -0,0 +1,59 @@ +import passport from "passport"; +import { Strategy } from "passport-local"; +import { autoInjectable, singleton } from "tsyringe"; +import Account from "../models/account.model"; +import { AccountService } from "../services/account.service"; + +@autoInjectable() +@singleton() +export class EmailAndPasswordStrategy extends Strategy { + constructor(private readonly accountService: AccountService) { + super( + { + usernameField: "email", + passwordField: "password" + }, + ( + email: string, + password: string, + done: (error: any, user?: any) => void + ) => this.verify(email, password, done) + ); + + passport.serializeUser( + (user: Account, done: (error: any, identifier?: number) => void) => + done(null, user.identifier) + ); + + passport.deserializeUser( + async ( + identifier: number, + done: ( + error: any, + user?: false | Express.User | null | undefined + ) => void + ) => { + await this.accountService + .findByIdentifier(identifier) + .then((user) => done(null, user)) + .catch((reason) => done(reason)); + } + ); + } + + async verify( + email: string, + password: string, + done: (error: any, user?: any) => void + ) { + await this.accountService + .getAccountIfValid(email.toLowerCase(), password) + .then((account) => { + if (account) done(null, account); + else done(null, false); + }) + .catch((reason) => { + done(reason, false); + }); + } +} From ab0df18489a29ceef4b2f3bd37741c9c72993ecf Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Sat, 18 Dec 2021 12:51:14 -0500 Subject: [PATCH 05/72] feat: update e-mail templates to MJML. why the change? -> - reducing code complexity and supporting all major e-mail clients automatically. - ability to use Passport (GUI Application) which allows you to design e-mails and export them to MJML (afaik). - allowing dev team to get code directly from design team. todo -> - update social links (facebook group, slack to discord) for mchacks 9. - update any remaining mchacks 7 mentions to mchacks 9. - as MJML is simply a markup language we still require a templating engine such as handlebars to handle variable injection. - in our code where we call the handlebars template compile method we must call the mjml2html method internally. - example: compileHandlebarsTemplate(mjml2html(...)). --- assets/email/AccountConfirmation.hbs | 431 ----------------- assets/email/AccountConfirmation.mjml | 41 ++ assets/email/AccountInvitation.hbs | 458 ------------------ assets/email/Footer.mjml | 11 + assets/email/HackingPolicy.mjml | 30 ++ assets/email/Header.mjml | 7 + assets/email/ResetPassword.hbs | 430 ----------------- assets/email/ResetPassword.mjml | 44 ++ assets/email/SocialMedia.mjml | 29 ++ assets/email/Ticket.hbs | 500 -------------------- assets/email/Ticket.mjml | 145 ++++++ assets/email/Welcome.hbs | 464 ------------------ assets/email/Welcome.mjml | 64 +++ assets/email/marketingEmail/3Days.hbs | 450 ------------------ assets/email/marketingEmail/3Days.mjml | 82 ++++ assets/email/marketingEmail/EmailBlast.hbs | 465 ------------------ assets/email/marketingEmail/EmailBlast.mjml | 72 +++ assets/email/statusEmail/Accepted.hbs | 458 ------------------ assets/email/statusEmail/Accepted.mjml | 42 ++ assets/email/statusEmail/Applied.hbs | 455 ------------------ assets/email/statusEmail/Applied.mjml | 34 ++ assets/email/statusEmail/Checked-In.mjml | 42 ++ assets/email/statusEmail/Checked-in.hbs | 465 ------------------ assets/email/statusEmail/Confirmed.hbs | 449 ------------------ assets/email/statusEmail/Confirmed.mjml | 29 ++ assets/email/statusEmail/Declined.hbs | 453 ------------------ assets/email/statusEmail/Declined.mjml | 34 ++ assets/email/statusEmail/None.hbs | 457 ------------------ assets/email/statusEmail/None.mjml | 36 ++ assets/email/statusEmail/Waitlisted.hbs | 452 ------------------ assets/email/statusEmail/Waitlisted.mjml | 34 ++ assets/email/statusEmail/Withdrawn.hbs | 451 ------------------ assets/email/statusEmail/Withdrawn.mjml | 28 ++ assets/email/test.hbs | 1 - assets/email/test.mjml | 12 + 35 files changed, 816 insertions(+), 6839 deletions(-) delete mode 100644 assets/email/AccountConfirmation.hbs create mode 100644 assets/email/AccountConfirmation.mjml delete mode 100644 assets/email/AccountInvitation.hbs create mode 100644 assets/email/Footer.mjml create mode 100644 assets/email/HackingPolicy.mjml create mode 100644 assets/email/Header.mjml delete mode 100644 assets/email/ResetPassword.hbs create mode 100644 assets/email/ResetPassword.mjml create mode 100644 assets/email/SocialMedia.mjml delete mode 100644 assets/email/Ticket.hbs create mode 100644 assets/email/Ticket.mjml delete mode 100644 assets/email/Welcome.hbs create mode 100644 assets/email/Welcome.mjml delete mode 100644 assets/email/marketingEmail/3Days.hbs create mode 100644 assets/email/marketingEmail/3Days.mjml delete mode 100644 assets/email/marketingEmail/EmailBlast.hbs create mode 100644 assets/email/marketingEmail/EmailBlast.mjml delete mode 100644 assets/email/statusEmail/Accepted.hbs create mode 100644 assets/email/statusEmail/Accepted.mjml delete mode 100644 assets/email/statusEmail/Applied.hbs create mode 100644 assets/email/statusEmail/Applied.mjml create mode 100644 assets/email/statusEmail/Checked-In.mjml delete mode 100644 assets/email/statusEmail/Checked-in.hbs delete mode 100644 assets/email/statusEmail/Confirmed.hbs create mode 100644 assets/email/statusEmail/Confirmed.mjml delete mode 100644 assets/email/statusEmail/Declined.hbs create mode 100644 assets/email/statusEmail/Declined.mjml delete mode 100644 assets/email/statusEmail/None.hbs create mode 100644 assets/email/statusEmail/None.mjml delete mode 100644 assets/email/statusEmail/Waitlisted.hbs create mode 100644 assets/email/statusEmail/Waitlisted.mjml delete mode 100644 assets/email/statusEmail/Withdrawn.hbs create mode 100644 assets/email/statusEmail/Withdrawn.mjml delete mode 100644 assets/email/test.hbs create mode 100644 assets/email/test.mjml diff --git a/assets/email/AccountConfirmation.hbs b/assets/email/AccountConfirmation.hbs deleted file mode 100644 index a390b3f8..00000000 --- a/assets/email/AccountConfirmation.hbs +++ /dev/null @@ -1,431 +0,0 @@ - - - - - - - We've got your application! - - - -
- - - - -
- - - - - - - - - - - -
- - - - - -
- Logo -
- -
- - - - - -
- -

- Hey there! 👋 -

- If your account was just created or your email was recently updated, you'll need to confirm your email to access our hacker - dashboard. -

- Get that sorted by clicking below! -

- -

-
- McHacks Team -
- mchacks.ca -

- -
- -
- - - -
- -
-
- - - diff --git a/assets/email/AccountConfirmation.mjml b/assets/email/AccountConfirmation.mjml new file mode 100644 index 00000000..95a773ba --- /dev/null +++ b/assets/email/AccountConfirmation.mjml @@ -0,0 +1,41 @@ + + + We've got your application! + + + + + + + + + + Hey there! 👋 + + + + If your account was just created or your email was recently updated, you'll need to confirm your email to access our + hacker dashboard. + + + + Get that sorted by clicking below! + + + + + Confirm Your Email Address + + + + + McHacks Team +
+ mchacks.ca +
+
+
+ + +
+
diff --git a/assets/email/AccountInvitation.hbs b/assets/email/AccountInvitation.hbs deleted file mode 100644 index 06cdbffa..00000000 --- a/assets/email/AccountInvitation.hbs +++ /dev/null @@ -1,458 +0,0 @@ - - - - - - - We've got your application! - - - -
- - - - -
- - - - - - - - - - - -
- - - - - -
- Logo -
- -
- - - - - -
- -

- Hey there! 👋 -

- You've been invited to create an account on our sponsor - dashboard. On the sponsor dashboard you can find important - information about check-in, mentoring, judging, workshops, Discord, and - the schedule for the weekend. On the sponsor dashboard you will be able - to look up hacker applications and information. Additionally, if you - have resume access you will be able to download hacker resumes through - the dashboard. -

- Sponsor check-in starts at 6:00 pm on Friday, January 29th on the - McHacks Discord server and opening ceremonies will begin at 7:00 pm. Be - sure to get set up on the McHacks Discord server at https://discord.gg/g4Pya8jcxM - and contact your coordinator to set up your server roles. -

- Get access to the sponsor dashboard by clicking on the button below. -

- -

- If you have any questions, feel free to reach out to your coordinator. -

-

-
- McHacks Team -
- mchacks.ca -

- -
- -
- - - -
- -
-
- - - diff --git a/assets/email/Footer.mjml b/assets/email/Footer.mjml new file mode 100644 index 00000000..533a9d2d --- /dev/null +++ b/assets/email/Footer.mjml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/email/HackingPolicy.mjml b/assets/email/HackingPolicy.mjml new file mode 100644 index 00000000..09d87f5d --- /dev/null +++ b/assets/email/HackingPolicy.mjml @@ -0,0 +1,30 @@ + + + + Hacking Policy + + + + All projects built at our hackathon can be made by teams of 1-4 people. + If you're looking to find like-minded participants to work with, you + can post in our + Facebook group + or in #team-formation on Discord. + + + + In the interest of fairness, participants aren't allowed to work on + pre-existing projects or begin their projects before hacking at McHacks + begins. Any attempts of dishonesty or cheating will result in + disqualification. + + + + That being said, you're more than welcome to familiarize yourself with + all the tech and tools you intend to build with beforehand! You can + check our Devpost + which will be updated soon with our available prizes to inspire ideas + for your project! 🎁 + + + diff --git a/assets/email/Header.mjml b/assets/email/Header.mjml new file mode 100644 index 00000000..1f53758a --- /dev/null +++ b/assets/email/Header.mjml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/assets/email/ResetPassword.hbs b/assets/email/ResetPassword.hbs deleted file mode 100644 index dad4eb22..00000000 --- a/assets/email/ResetPassword.hbs +++ /dev/null @@ -1,430 +0,0 @@ - - - - - - - We've got your application! - - - -
- - - - -
- - - - - - - - - - - -
- - - - - -
- Logo -
- -
- - - - - -
- -

- Hey there! 👋 -

- Looks like you forgot your password. That's okay, it happens now and - then! -

- Click the button below to get things started again. It will lead you to - a page where you can reset your password. -

- -

- See you on the flip side, -

- McHacks Team -
- mchacks.ca -

-
- -
- - - -
- -
-
- - - diff --git a/assets/email/ResetPassword.mjml b/assets/email/ResetPassword.mjml new file mode 100644 index 00000000..a3668f6d --- /dev/null +++ b/assets/email/ResetPassword.mjml @@ -0,0 +1,44 @@ + + + We've got your application! + + + + + + + + + + Hey there! 👋 + + + + Looks like you forgot your password. That's okay, it happens now and + then! + + + + Click the button below to get things started again. It will lead you to + a page where you can reset your password. + + + + + Reset Your Password + + + + + See you on the flip side, +
+ McHacks Team +
+ mchacks.ca +
+
+
+ + +
+
diff --git a/assets/email/SocialMedia.mjml b/assets/email/SocialMedia.mjml new file mode 100644 index 00000000..f28d163c --- /dev/null +++ b/assets/email/SocialMedia.mjml @@ -0,0 +1,29 @@ + + + + That's All For Now, Folks! + + + + + Follow us on + Facebook, + Twitter, + and + Instagram + for important updates and news about McHacks! If you have any + questions, feel free to reach out at + contact@mchacks.ca. + + + + + + + + McHacks Team +
+ mchacks.ca +
+
+
diff --git a/assets/email/Ticket.hbs b/assets/email/Ticket.hbs deleted file mode 100644 index a6ee46bf..00000000 --- a/assets/email/Ticket.hbs +++ /dev/null @@ -1,500 +0,0 @@ - - - - - - - McHacks 6: Important Information - - - -
- - - - -
- - - - - - - - - - - -
- - - - - -
- Logo -
- -
- - - - - -
-

4 - Days until McHacks 6!

-

- Hi {{firstName}}! -

- McHacks 6 is this coming weekend and we're excited to spend an epic - weekend with you hacking away! 🎉 -

- Before we get to that, let's go through some important information to - get you ready for the hackathon: -
-

Communication

- Join our Facebook - group for announcements, to RSVP for workshops/activities, chat - with other hackers, and form teams! -

- During the hackathon, we'll be using both the FB group and the official - McHacks - 6 Slack. Be sure to join the Slack so you're updated on - everything going on as they happen! -

- We'll also have a live site with the schedule, announcements, and - everything else you need to know at mchacks.ca - closer to the event. -

-

Registration

- Out of town check-in begins on Saturday at 8:00 am and local check-in - at 9:30 am. Remember to bring your student ID as you'll need it to - register! -

- We'll only be allowing accepted and a limited amount of waitlisted - hackers into the hackathon. Your status must be "confirmed" on your hacker - dashboard to be allowed into the hackathon. -

- You'll also need your Hack Pass so we know who you are! Grab it on your - hacker - dashboard or save a copy of it right here: -

-
-

-

What - to Bring

- You should bring your student ID and anything you’d need for a - productive, healthy, and fun weekend: laptop, phone, chargers, - deodorant (!), change of clothes, etc. We'll have a sleeping space - available during the night for hackers to get some rest. 😴 -

- Don't worry about food and drinks, we've got you covered there! We also - encourage bringing a reusable mug so we can reduce our carbon footprint - together. 🍃 -

-

Transportation

- McHacks 6 will be hosted at Theatre - St James in the Old Port of Montreal. -

- If you have a seat on one of our buses, they'll drop you off right - outside the venue. If you're arranging your own travel, you can take - the metro to the Square-Victoria–OACI station, a short walk away from - the venue. -

-

Hacking - Policy

- All projects built at our hackathon can be made by teams of 1-4 people. - If you're looking to find like-minded participants to work with, you - can post in our Facebook - group or in #team-formation on Slack. -

- In the interest of fairness, participants aren't allowed to work on - pre-existing projects or begin their projects before hacking at McHacks - begins. Any attempts of dishonesty or cheating will result in - disqualification. -

- That being said, you're more than welcome to familiarize yourself with - all the tech and tools you intend to build with beforehand! You can - check our Devpost - which will be updated soon with our available prizes to inspire ideas - for your project! 🎁 -

-

That's - all for now, folks!

- Follow us on Facebook, - Twitter, - and Instagram - for important updates and news about McHacks 6! If you have any - questions, feel free to reach out at contact@mchacks.ca. -

-

-
- McHacks Team -
- mchacks.ca -

- -
- -
- - - -
- -
-
- - - \ No newline at end of file diff --git a/assets/email/Ticket.mjml b/assets/email/Ticket.mjml new file mode 100644 index 00000000..fa805047 --- /dev/null +++ b/assets/email/Ticket.mjml @@ -0,0 +1,145 @@ + + + McHacks 9: Important Information + + + + + + + + + + 4 Days Until McHacks 9! + + + + Hi {{ firstName }}! + + + + McHacks 9 is this coming weekend and we're excited to spend an epic + weekend with you hacking away! 🎉 + + + + Before we get to that, let's go through some important information to + get you ready for the hackathon: + + + + + + + + Communication + + + + Join our + Facebook group + for announcements, to RSVP for workshops/activities, chat with other hackers, and form teams! + + + + During the hackathon, we'll be using both the FB group and the official + McHacks 9 Discord + Be sure to join the Discord so you're updated on + everything going on as they happen! + + + + We'll also have a live site with the schedule, announcements, and + everything else you need to know at + mchacks.ca + closer to the event + + + + + + + + + Registration + + + + Out of town check-in begins on Saturday at 8:00 am and local check-in + at 9:30 am. Remember to bring your student ID as you'll need it to + register! + + + + We'll only be allowing accepted and a limited amount of waitlisted + hackers into the hackathon. Your status must be "confirmed" on your + hacker dashboard + to be allowed into the hackathon. + + + + You'll also need your Hack Pass so we know who you are! Grab it on your + hacker dashboard + or save a copy of it right here: + + + + + + That being said, you're more than welcome to familiarize yourself with + all the tech and tools you intend to build with beforehand! You can + check our Devpost + which will be updated soon with our available prizes to inspire ideas + for your project! 🎁 + + + + + + + + What You'll Need To Bring + + + + You should bring your student ID and anything you’d need for a + productive, healthy, and fun weekend: laptop, phone, chargers, + deodorant (!), change of clothes, etc. We'll have a sleeping space + available during the night for hackers to get some rest. 😴 + + + + Don't worry about food and drinks, we've got you covered there! We also + encourage bringing a reusable mug so we can reduce our carbon footprint + together. 🍃 + + + + + + + + Transportation + + + + McHacks 9 will be hosted at + Theatre St James + in the Old Port of Montreal. + + + + If you have a seat on one of our buses, they'll drop you off right + outside the venue. If you're arranging your own travel, you can take + the metro to the Square-Victoria–OACI station, a short walk away from + the venue. + + + + + + + + + + diff --git a/assets/email/Welcome.hbs b/assets/email/Welcome.hbs deleted file mode 100644 index ae69d24d..00000000 --- a/assets/email/Welcome.hbs +++ /dev/null @@ -1,464 +0,0 @@ - - - - - - - McHacks 6: Important Information - - - -
- - - - -
- - - - - - - - - - - -
- - - - - -
- Logo -
- -
- - - - - -
-

- Welcome to McHacks 6! -

-

- Hi {{firstName}}! -

- McHacks 6 is finally here, and we're excited to spend an epic - weekend with you hacking away! 🎉 -

- Before we get to that, let's go through some important information to - get you ready for the hackathon: -
-

Communication

- Join our Facebook - group for announcements, to RSVP for workshops/activities, chat - with other hackers, and form teams! -

- During the hackathon, we'll be using both the FB group and the official - McHacks - 6 Slack. Be sure to join the Slack so you're updated on - everything going on as they happen! -

- We'll also have a live site with the schedule, announcements, and - everything else you need to know at mchacks.ca - closer to the event -

-

Hacking - Policy

- All projects built at our hackathon can be made by teams of 1-4 people. - If you're looking to find like-minded participants to work with, you - can post in our Facebook - group or in #team-formation on Slack. -

- In the interest of fairness, participants aren't allowed to work on - pre-existing projects or begin their projects before hacking at McHacks - begins. Any attempts of dishonesty or cheating will result in - disqualification. -

- That being said, you're more than welcome to familiarize yourself with - all the tech and tools you intend to build with beforehand! You can - check our Devpost - which will be updated soon with our available prizes to inspire ideas - for your project! 🎁 -

-

That's - all for now, folks!

- Follow us on Facebook, - Twitter, - and Instagram - for important updates and news about McHacks 6! If you have any - questions, feel free to reach out at contact@mchacks.ca. -

-

-
- McHacks Team -
- mchacks.ca -

- -
- -
- - - -
- -
-
- - - \ No newline at end of file diff --git a/assets/email/Welcome.mjml b/assets/email/Welcome.mjml new file mode 100644 index 00000000..f95d460e --- /dev/null +++ b/assets/email/Welcome.mjml @@ -0,0 +1,64 @@ + + + McHacks 9: Important Information + + + + + + + + + + Welcome To McHacks 9! + + + + Hi {{ firstName }}! + + + + McHacks 6 is finally here, and we're excited to spend an epic + weekend with you hacking away! 🎉 + + + + Before we get to that, let's go through some important information to + get you ready for the hackathon: + + + + + + + + Communication + + + + Join our + Facebook group + for announcements, to RSVP for workshops/activities, chat with other hackers, and form teams! + + + + During the hackathon, we'll be using both the FB group and the official + McHacks 9 Discord + Be sure to join the Discord so you're updated on + everything going on as they happen! + + + + We'll also have a live site with the schedule, announcements, and + everything else you need to know at + mchacks.ca + closer to the event + + + + + + + + + diff --git a/assets/email/marketingEmail/3Days.hbs b/assets/email/marketingEmail/3Days.hbs deleted file mode 100644 index b0ad126f..00000000 --- a/assets/email/marketingEmail/3Days.hbs +++ /dev/null @@ -1,450 +0,0 @@ - - - - - - - McHacks is back! - - - -
- - - - -
- - - - - - - - - - - -
- - - - - -
- Logo -
- -
- - - - - -
- - -

-

- There’s just 3 days left to apply to Canada’s favorite hackathon! Have - you started your McHacks 7 application yet? What are you waiting for? -

- McHacks is back this winter for round 7! Join us February 1-2, 2020 in - the beautiful city of Montreal for a weekend full of engaging workshops, - making new friends, impressive tech, and awesome hacking. -

-

- Follow us on Facebook, - Twitter, - and Instagram - for important updates and news about McHacks! If you have any - questions, feel free to reach out at contact@mchacks.ca. -

- -

- If you’ve already applied, share this email with your friends and don’t - forget to respond to our Facebook - event. We hope to see you there! -

-

-
- McHacks Team -
- mchacks.ca -

- - unsubscribe - -
- -
-
- -
-
- - - diff --git a/assets/email/marketingEmail/3Days.mjml b/assets/email/marketingEmail/3Days.mjml new file mode 100644 index 00000000..ec1363a8 --- /dev/null +++ b/assets/email/marketingEmail/3Days.mjml @@ -0,0 +1,82 @@ + + + McHacks is back! + + + + + + + + + + There’s just 3 days left to apply to Canada’s favorite hackathon! Have + you started your McHacks 7 application yet? What are you waiting for? + + + + McHacks is back this winter for round 7! Join us February 1-2, 2020 in + the beautiful city of Montreal for a weekend full of engaging workshops, + making new friends, impressive tech, and awesome hacking. + + + + 🚀 Update complete. You're now ready for McHacks 7! 😀🎉 + + + + Canada's favorite hackathon is back again this winter and better than + ever! Join us on February 1-2, 2020 for a weekend full of engaging + workshops, impressive tech, exceptional food, and awesome hacking. + + + + Learn something, make new friends, and help build the future in the + beautiful city of Montreal. We hope to see you there, whether it's your + first hackathon or your 10th. + + + + + Apply Now! + + + + + If you're ahead of the game and applied already, feel free to recycle + this email to a friend and help us keep the hype going! +

+ Follow us on + Facebook, + Twitter, + and + Instagram + for important updates and news about McHacks! If you have any + questions, feel free to reach out at + contact@mchacks.ca. +
+ + + If you’ve already applied, share this email with your friends and don’t + forget to respond to our + Facebook event. + We hope to see you there! + + + + McHacks Team +
+ mchacks.ca +
+ + + + Unsubscribe + + +
+
+ + +
+
diff --git a/assets/email/marketingEmail/EmailBlast.hbs b/assets/email/marketingEmail/EmailBlast.hbs deleted file mode 100644 index 24dc9ba0..00000000 --- a/assets/email/marketingEmail/EmailBlast.hbs +++ /dev/null @@ -1,465 +0,0 @@ - - - - - - - McHacks is back! - - - -
- - - - -
- - - - - - - - - - - -
- - - - - -
- Logo -
- -
- - - - - -
- -

- 💾 Installing HackMcGill firmware… -

- 💻 Getting the latest McHacks update... -

- 🚀 Update complete. You're now ready for McHacks 7! 😀🎉 -

- Canada's favorite hackathon is back again this winter and better than - ever! Join us on February 1-2, 2020 for a weekend full of engaging - workshops, impressive tech, exceptional food, and awesome hacking. -

- Learn something, make new friends, and help build the future in the - beautiful city of Montreal. We hope to see you there, whether it's your - first hackathon or your 10th. -

- -

- If you're ahead of the game and applied already, feel free to recycle - this email to a friend and help us keep the hype going! -

- Follow us on Facebook, - Twitter, - and Instagram - for important updates and news about McHacks! If you have any - questions, feel free to reach out at contact@mchacks.ca. -

-

-
- McHacks Team -
- mchacks.ca -

- - unsubscribe - -
- -
- - - -
- -
-
- - - diff --git a/assets/email/marketingEmail/EmailBlast.mjml b/assets/email/marketingEmail/EmailBlast.mjml new file mode 100644 index 00000000..3297b99a --- /dev/null +++ b/assets/email/marketingEmail/EmailBlast.mjml @@ -0,0 +1,72 @@ + + + McHacks is back! + + + + + + + + + + 💾 Installing HackMcGill firmware… + + + + 💻 Getting the latest McHacks update... + + + + 🚀 Update complete. You're now ready for McHacks 7! 😀🎉 + + + + Canada's favorite hackathon is back again this winter and better than + ever! Join us on February 1-2, 2020 for a weekend full of engaging + workshops, impressive tech, exceptional food, and awesome hacking. + + + + Learn something, make new friends, and help build the future in the + beautiful city of Montreal. We hope to see you there, whether it's your + first hackathon or your 10th. + + + + + Apply Now! + + + + + If you're ahead of the game and applied already, feel free to recycle + this email to a friend and help us keep the hype going! +

+ Follow us on + Facebook, + Twitter, + and + Instagram + for important updates and news about McHacks! If you have any + questions, feel free to reach out at + contact@mchacks.ca. +
+ + + McHacks Team +
+ mchacks.ca +
+ + + + Unsubscribe + + +
+
+ + +
+
diff --git a/assets/email/statusEmail/Accepted.hbs b/assets/email/statusEmail/Accepted.hbs deleted file mode 100644 index a586300a..00000000 --- a/assets/email/statusEmail/Accepted.hbs +++ /dev/null @@ -1,458 +0,0 @@ - - - - - - - We've got your application! - - - -
- - - - -
- - - - - - - - - - - -
- - - - - -
- Logo -
- -
- - - - - -
-

-

-

- Congratulations, {{firstName}}! 🎉 -

- We’re thrilled to offer you a spot at McHacks! We can't wait to see what - you create with us this year. -

- Confirm your attendance on our hacker - dashboard no later than January 25th at 11:59PM EST. -

- If you can no longer attend McHacks, please let us know as soon as - possible by withdrawing your application on our hacker - dashboard so we can pass your spot along to someone else. -

- In the meantime, follow us on Facebook, - Twitter, - and Instagram - for important updates and news about McHacks! If you have any questions, - feel free to reach out at contact@mchacks.ca. -

-

-

-
- McHacks Team -
- mchacks.ca -

- -
- -
- - - -
- -
-
- - - diff --git a/assets/email/statusEmail/Accepted.mjml b/assets/email/statusEmail/Accepted.mjml new file mode 100644 index 00000000..f77abda8 --- /dev/null +++ b/assets/email/statusEmail/Accepted.mjml @@ -0,0 +1,42 @@ + + + We've Got Your Application! + + + + + + + + + + + Congratulations, {{ firstName }}! 🎉 + + + + We’re thrilled to offer you a spot at McHacks! We can't wait to see what + you create with us this year. + + + + Confirm your attendance on our + hacker dashboard + no later than January 25th at 11:59PM EST. + + + + If you can no longer attend McHacks, please let us know as soon as + possible by withdrawing your application on our + hacker dashboard + so we can pass your spot along to someone else. + + + + + + + + + + diff --git a/assets/email/statusEmail/Applied.hbs b/assets/email/statusEmail/Applied.hbs deleted file mode 100644 index f0c66918..00000000 --- a/assets/email/statusEmail/Applied.hbs +++ /dev/null @@ -1,455 +0,0 @@ - - - - - - - We've got your application! - - - -
- - - - -
- - - - - - - - - - - -
- - - - - -
- Logo -
- -
- - - - - -
-

-

-

- Hey there, {{firstName}}! 👋 -

- Your application for McHacks has been safely received! 🎉 -

- You can view and edit your application on our hacker - dashboard until the deadline on December - 26th at - 12:00pm ET. -

- In the meantime, follow us on Facebook, - Twitter, - and Instagram - for important updates and news about McHacks! If you have any questions, - feel free to reach out at contact@mchacks.ca. -

-

-

-
- McHacks Team -
- mchacks.ca -

- -
- -
- - - -
- -
-
- - - diff --git a/assets/email/statusEmail/Applied.mjml b/assets/email/statusEmail/Applied.mjml new file mode 100644 index 00000000..b00229e9 --- /dev/null +++ b/assets/email/statusEmail/Applied.mjml @@ -0,0 +1,34 @@ + + + We've Got Your Application! + + + + + + + + + + + Hey there, {{ firstName }}! 👋 + + + + Your application for McHacks has been safely received! 🎉 + + + + You can view and edit your application on our + hacker dashboard + until the deadline on + December 26th at 12:00pm ET. + + + + + + + + + diff --git a/assets/email/statusEmail/Checked-In.mjml b/assets/email/statusEmail/Checked-In.mjml new file mode 100644 index 00000000..0f0c09ab --- /dev/null +++ b/assets/email/statusEmail/Checked-In.mjml @@ -0,0 +1,42 @@ + + + We've Got Your Application! + + + + + + + + + + + Hi {{ firstName }}, + + + + This email is to confirm your check-in at McHacks! + + + + Don't forget to join the McHacks participants + Facebook group + and + Discord + for announcements, to chat with other hackers, ask questions, and form teams! + + + + Check out our + Live site + for the full schedule, maps of the venue, and + information on wifi, bathrooms, prizes, and more. + + + + + + + + + diff --git a/assets/email/statusEmail/Checked-in.hbs b/assets/email/statusEmail/Checked-in.hbs deleted file mode 100644 index 4c0bf4c3..00000000 --- a/assets/email/statusEmail/Checked-in.hbs +++ /dev/null @@ -1,465 +0,0 @@ - - - - - - - We've got your application! - - - -
- - - - -
- - - - - - - - - - - -
- - - - - -
- Logo -
- -
- - - - - -
-

-

-

- Hi {{firstName}}, -

- This email is to confirm your check-in at McHacks! -

- Don't forget to join the McHacks participants Facebook - group and Slack - for announcements, to chat with other hackers, ask questions, and form - teams! - - -

- Check out our - Live site for the full schedule, maps of the venue, and - information on wifi, bathrooms, prizes, and more. - - -

- Follow us on Facebook, - Twitter, - and Instagram - for important updates and news about McHacks! If you have any questions, - feel free to reach out at contact@mchacks.ca. -

-

-

-
- McHacks Team -
- mchacks.ca -

- -
- -
- - - -
- -
-
- - - diff --git a/assets/email/statusEmail/Confirmed.hbs b/assets/email/statusEmail/Confirmed.hbs deleted file mode 100644 index a524ea50..00000000 --- a/assets/email/statusEmail/Confirmed.hbs +++ /dev/null @@ -1,449 +0,0 @@ - - - - - - - We've got your application! - - - -
- - - - -
- - - - - - - - - - - -
- - - - - -
- Logo -
- -
- - - - - -
-

-

-

- Hi, {{firstName}}, -

- Thanks for confirming your attendance for McHacks! We hope you’re just - as excited as we are. Keep an eye out for our week-of email with more - details regarding McHacks. Happy hacking! -

- Follow us on Facebook, - Twitter, - and Instagram - for important updates about McHacks! If you have any questions, - feel free to reach out at contact@mchacks.ca. -

-

-

-
- McHacks Team -
- mchacks.ca -

- -
- -
- - - -
- -
-
- - - diff --git a/assets/email/statusEmail/Confirmed.mjml b/assets/email/statusEmail/Confirmed.mjml new file mode 100644 index 00000000..1d99239f --- /dev/null +++ b/assets/email/statusEmail/Confirmed.mjml @@ -0,0 +1,29 @@ + + + We've Got Your Application! + + + + + + + + + + + Hi {{ firstName }}, + + + + Thanks for confirming your attendance for McHacks! We hope you’re just + as excited as we are. Keep an eye out for our week-of email with more + details regarding McHacks. Happy hacking! + + + + + + + + + diff --git a/assets/email/statusEmail/Declined.hbs b/assets/email/statusEmail/Declined.hbs deleted file mode 100644 index c4d682b9..00000000 --- a/assets/email/statusEmail/Declined.hbs +++ /dev/null @@ -1,453 +0,0 @@ - - - - - - - We've got your application! - - - -
- - - - -
- - - - - - - - - - - -
- - - - - -
- Logo -
- -
- - - - - -
-

-

-

- Hi {{firstName}}, -

- Thank you for applying to McHacks! We're sorry to inform you that we're - unable to offer you a spot at McHacks. -

- We received an overwhelming number of applicants this year and - unfortunately can't accept everyone. We hope you understand and - encourage you to apply again in the future. -

- Follow us on Facebook, - Twitter, - and Instagram - for important updates about McHacks. -

- If you have any questions, - feel free to reach out at contact@mchacks.ca. -

-

-
- McHacks Team -
- mchacks.ca -

- -
- -
- - - -
- -
-
- - - diff --git a/assets/email/statusEmail/Declined.mjml b/assets/email/statusEmail/Declined.mjml new file mode 100644 index 00000000..9b95c21a --- /dev/null +++ b/assets/email/statusEmail/Declined.mjml @@ -0,0 +1,34 @@ + + + We've Got Your Application! + + + + + + + + + + + Hi {{ firstName }}, + + + + Thank you for applying to McHacks! We're sorry to inform you that we're + unable to offer you a spot at McHacks. + + + + We received an overwhelming number of applicants this year and + unfortunately can't accept everyone. We hope you understand and + encourage you to apply again in the future. + + + + + + + + + diff --git a/assets/email/statusEmail/None.hbs b/assets/email/statusEmail/None.hbs deleted file mode 100644 index 5f4218f0..00000000 --- a/assets/email/statusEmail/None.hbs +++ /dev/null @@ -1,457 +0,0 @@ - - - - - - - We've got your application! - - - -
- - - - -
- - - - - - - - - - - -
- - - - - -
- Logo -
- -
- - - - - -
-

-

-

- Hey {{firstName}}! 👋 -

- You're one step closer to an epic weekend at McHacks, Canada's favourite - hackathon! Ready to start your application? Sign in to our hacker - dashboard to get started! -

- Applications close on December - 26th at - 12:00pm ET so - be sure to - click submit before then to be considered. -

- In the meantime, follow us on Facebook, - Twitter, - and Instagram - for important updates and news about McHacks! If you have any questions, - feel free to reach out at contact@mchacks.ca. -

-

-

-
- McHacks Team -
- mchacks.ca -

- -
- -
- - - -
- -
-
- - - diff --git a/assets/email/statusEmail/None.mjml b/assets/email/statusEmail/None.mjml new file mode 100644 index 00000000..9c35db27 --- /dev/null +++ b/assets/email/statusEmail/None.mjml @@ -0,0 +1,36 @@ + + + We've Got Your Application! + + + + + + + + + + + Hey {{ firstName }}! 👋 + + + + You're one step closer to an epic weekend at McHacks, Canada's favourite + hackathon! Ready to start your application? Sign in to our + hacker dashboard + to get started! + + + + Applications close on + December 26th at 12:00pm ET + so be sure to click submit before then to be considered. + + + + + + + + + diff --git a/assets/email/statusEmail/Waitlisted.hbs b/assets/email/statusEmail/Waitlisted.hbs deleted file mode 100644 index 54b6bc2f..00000000 --- a/assets/email/statusEmail/Waitlisted.hbs +++ /dev/null @@ -1,452 +0,0 @@ - - - - - - - We've got your application! - - - -
- - - - -
- - - - - - - - - - - -
- - - - - -
- Logo -
- -
- - - - - -
-

-

-

- Hi {{firstName}}, -

- Thank you for applying to McHacks. We received a ton of great - applicants this year and are unfortunately unable to offer you a place - at McHacks this year. -

- But don't sweat yet, we've placed you on the waitlist and will let you - know if a spot opens up! -

- In the meantime, follow us on Facebook, - Twitter, - and Instagram - for important updates and news about McHacks! If you have any questions, - feel free to reach out at contact@mchacks.ca. -

-

-

-
- McHacks Team -
- mchacks.ca -

- -
- -
- - - -
- -
-
- - - diff --git a/assets/email/statusEmail/Waitlisted.mjml b/assets/email/statusEmail/Waitlisted.mjml new file mode 100644 index 00000000..73f01492 --- /dev/null +++ b/assets/email/statusEmail/Waitlisted.mjml @@ -0,0 +1,34 @@ + + + We've Got Your Application! + + + + + + + + + + + Hi {{ firstName }}, + + + + Thank you for applying to McHacks. We received a ton of great + applicants this year and are unfortunately unable to offer you a place + at McHacks this year. + + + + But don't sweat yet, we've placed you on the waitlist and will let you + know if a spot opens up! + + + + + + + + + diff --git a/assets/email/statusEmail/Withdrawn.hbs b/assets/email/statusEmail/Withdrawn.hbs deleted file mode 100644 index 8c0b0cf2..00000000 --- a/assets/email/statusEmail/Withdrawn.hbs +++ /dev/null @@ -1,451 +0,0 @@ - - - - - - - We've got your application! - - - -
- - - - -
- - - - - - - - - - - -
- - - - - -
- Logo -
- -
- - - - - -
-

-

-

- Hi {{firstName}}, -

- We're sorry to hear that you won't be able to attend McHacks this year. - 😢 -

- Follow us on Facebook, - Twitter, - and Instagram - for important updates and news about McHacks. -

- If you have any questions, - feel free to reach out at contact@mchacks.ca. -

- We hope to see you next year! -

-

-
- McHacks Team -
- mchacks.ca -

- -
- -
- - - -
- -
-
- - - diff --git a/assets/email/statusEmail/Withdrawn.mjml b/assets/email/statusEmail/Withdrawn.mjml new file mode 100644 index 00000000..857f1302 --- /dev/null +++ b/assets/email/statusEmail/Withdrawn.mjml @@ -0,0 +1,28 @@ + + + We've Got Your Application! + + + + + + + + + + + Hi {{ firstName }}, + + + + We're sorry to hear that you won't be able to attend McHacks this year. + 😢 + + + + + + + + + diff --git a/assets/email/test.hbs b/assets/email/test.hbs deleted file mode 100644 index 7fb29606..00000000 --- a/assets/email/test.hbs +++ /dev/null @@ -1 +0,0 @@ -
This is used for testing email service. DO NOT REMOVE.{{TEST}}. link
\ No newline at end of file diff --git a/assets/email/test.mjml b/assets/email/test.mjml new file mode 100644 index 00000000..83a28e95 --- /dev/null +++ b/assets/email/test.mjml @@ -0,0 +1,12 @@ + + + + + + This is used for testing email service. DO NOT REMOVE. {{ TEST }}. + link + + + + + From 016142a402b4e9509373cc1d870dcab2358c6400 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Sat, 18 Dec 2021 18:24:11 -0500 Subject: [PATCH 06/72] refactor: remove unnecessary files. - remove intellij/jetbrain ide configuration files (no one on our team uses these anymore afaik). - remove Dockerfile as we no longer deploy on Google Cloud. - remove Google Cloud service and ingress files for deploy as once again we no longer deploy on Google Cloud. - remove www.js as the entry point for our app is now app.ts --- .dockerignore | 2 - .idea/Hackboard.iml | 12 ---- .idea/jsLibraryMappings.xml | 6 -- .idea/misc.xml | 6 -- .idea/modules.xml | 8 --- .idea/runConfigurations/bin_www.xml | 11 ---- .idea/vcs.xml | 14 ----- Dockerfile | 18 ------ bin/www.js | 87 ----------------------------- ingress.yaml | 16 ------ service.yaml | 23 -------- 11 files changed, 203 deletions(-) delete mode 100755 .dockerignore delete mode 100755 .idea/Hackboard.iml delete mode 100755 .idea/jsLibraryMappings.xml delete mode 100755 .idea/misc.xml delete mode 100755 .idea/modules.xml delete mode 100755 .idea/runConfigurations/bin_www.xml delete mode 100755 .idea/vcs.xml delete mode 100755 Dockerfile delete mode 100755 bin/www.js delete mode 100644 ingress.yaml delete mode 100644 service.yaml diff --git a/.dockerignore b/.dockerignore deleted file mode 100755 index 5171c540..00000000 --- a/.dockerignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -npm-debug.log \ No newline at end of file diff --git a/.idea/Hackboard.iml b/.idea/Hackboard.iml deleted file mode 100755 index 24643cc3..00000000 --- a/.idea/Hackboard.iml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/jsLibraryMappings.xml b/.idea/jsLibraryMappings.xml deleted file mode 100755 index d23208fb..00000000 --- a/.idea/jsLibraryMappings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100755 index 28a804d8..00000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100755 index 3301494c..00000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/runConfigurations/bin_www.xml b/.idea/runConfigurations/bin_www.xml deleted file mode 100755 index c9f522eb..00000000 --- a/.idea/runConfigurations/bin_www.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100755 index ff4fb78e..00000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - diff --git a/Dockerfile b/Dockerfile deleted file mode 100755 index 493f0275..00000000 --- a/Dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -FROM node:carbon - -ENV PORT 8080 - -WORKDIR /usr/src/app - -COPY package*.json ./ -ADD VERSION . - -RUN npm install -g n -RUN n 9.9.0 -RUN npm install npm -g -RUN npm install - -COPY . . - -EXPOSE 8080 -CMD [ "npm", "run", "debug" ] \ No newline at end of file diff --git a/bin/www.js b/bin/www.js deleted file mode 100755 index 3dcc082c..00000000 --- a/bin/www.js +++ /dev/null @@ -1,87 +0,0 @@ -"use strict"; -/** - * Module dependencies. - */ -import "reflect-metadata"; -const app = require("../app").app; -const debug = require("debug")("hackboard:server"); -const http = require("http"); -const version = require("../services/version.service"); - -/** - * Get port from environment and store in Express. - */ - -const port = normalizePort(process.env.PORT || "3000"); -app.set("port", port); - -/** - * Create HTTP server. - */ - -const server = http.createServer(app); - -/** - * Normalize a port into a number, string, or false. - */ - -function normalizePort(val) { - const p = parseInt(val, 10); - - if (Number.isNaN(p)) { - // named pipe - return val; - } - - if (p >= 0) { - // port number - return p; - } - return false; -} - -/** - * Event listener for HTTP server "error" event. - */ - -function onError(error) { - if (error.syscall !== "listen") { - throw error; - } - - const bind = typeof port === "string" ? "Pipe " + port : "Port " + port; - - // handle specific listen errors with friendly messages - switch (error.code) { - case "EACCES": - console.error(bind + " requires elevated privileges"); - process.exit(1); - break; - case "EADDRINUSE": - console.error(bind + " is already in use"); - process.exit(1); - break; - default: - throw error; - } -} - -/** - * Event listener for HTTP server "listening" event. - */ - -function onListening() { - const addr = server.address(); - const bind = - typeof addr === "string" ? "pipe " + addr : "port " + addr.port; - debug("Listening on " + bind); - debug(`VERSION ${version.get()}`); -} - -/** - * Listen on provided port, on all network interfaces. - */ - -server.listen(port); -server.on("error", onError); -server.on("listening", onListening); diff --git a/ingress.yaml b/ingress.yaml deleted file mode 100644 index fb78f840..00000000 --- a/ingress.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: hackboard-ingress - annotations: - kubernetes.io/ingress.global-static-ip-name: hackboard-ingress-static-ip -spec: - # tls: - # - secretName: hackboard-secret - # rules: - # - http: - # paths: - # - path: /* - backend: - serviceName: hackboard-service - servicePort: 80 \ No newline at end of file diff --git a/service.yaml b/service.yaml deleted file mode 100644 index 282b0502..00000000 --- a/service.yaml +++ /dev/null @@ -1,23 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: hackboard-service - labels: - run: hackboard # because that's the label on the deployment (not sure what labels do tho) - # annotations: - # cloud.google.com/app-protocols: '{"hackboard-https-port":"HTTPS","hackboard-http-port":"HTTP"}' -spec: - selector: - run: hackboard # because that's the selector on the deployment (not sure what labels do tho) - ports: - - name: http #hackboard-http-port - protocol: TCP - port: 80 - targetPort: 8080 # because the deployment port is 80/TCP - # - name: hackboard-https-port - # protocol: TCP - # port: 443 - type: LoadBalancer - -# endpoint of service same as ip of pods -> means communication between service and pod (direction?) -# can talk to this service with cluster-ip:port from any other node on cluster \ No newline at end of file From 1adb9318271e023e2680515f08a4eb4eb0631a30 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Wed, 22 Dec 2021 17:57:25 -0500 Subject: [PATCH 07/72] fix: change invalid directories for e-mail partials to valid ones. --- assets/email/AccountConfirmation.mjml | 4 ++-- assets/email/ResetPassword.mjml | 4 ++-- assets/email/Ticket.mjml | 10 +++++----- assets/email/Welcome.mjml | 8 ++++---- assets/email/marketingEmail/3Days.mjml | 4 ++-- assets/email/marketingEmail/EmailBlast.mjml | 4 ++-- assets/email/statusEmail/Accepted.mjml | 8 ++++---- assets/email/statusEmail/Applied.mjml | 6 +++--- assets/email/statusEmail/Checked-In.mjml | 6 +++--- assets/email/statusEmail/Confirmed.mjml | 6 +++--- assets/email/statusEmail/Declined.mjml | 6 +++--- assets/email/statusEmail/None.mjml | 6 +++--- assets/email/statusEmail/Waitlisted.mjml | 6 +++--- assets/email/statusEmail/Withdrawn.mjml | 6 +++--- 14 files changed, 42 insertions(+), 42 deletions(-) diff --git a/assets/email/AccountConfirmation.mjml b/assets/email/AccountConfirmation.mjml index 95a773ba..5cdca747 100644 --- a/assets/email/AccountConfirmation.mjml +++ b/assets/email/AccountConfirmation.mjml @@ -4,7 +4,7 @@ - + @@ -36,6 +36,6 @@ - + diff --git a/assets/email/ResetPassword.mjml b/assets/email/ResetPassword.mjml index a3668f6d..f5e1c075 100644 --- a/assets/email/ResetPassword.mjml +++ b/assets/email/ResetPassword.mjml @@ -4,7 +4,7 @@ - + @@ -39,6 +39,6 @@ - + diff --git a/assets/email/Ticket.mjml b/assets/email/Ticket.mjml index fa805047..db5c9e78 100644 --- a/assets/email/Ticket.mjml +++ b/assets/email/Ticket.mjml @@ -4,7 +4,7 @@ - + @@ -136,10 +136,10 @@ - - - + + + - + diff --git a/assets/email/Welcome.mjml b/assets/email/Welcome.mjml index f95d460e..314f52fd 100644 --- a/assets/email/Welcome.mjml +++ b/assets/email/Welcome.mjml @@ -4,7 +4,7 @@ - + @@ -56,9 +56,9 @@ - - + + - + diff --git a/assets/email/marketingEmail/3Days.mjml b/assets/email/marketingEmail/3Days.mjml index ec1363a8..abf88b0b 100644 --- a/assets/email/marketingEmail/3Days.mjml +++ b/assets/email/marketingEmail/3Days.mjml @@ -4,7 +4,7 @@ - + @@ -77,6 +77,6 @@ - + diff --git a/assets/email/marketingEmail/EmailBlast.mjml b/assets/email/marketingEmail/EmailBlast.mjml index 3297b99a..2475ce6a 100644 --- a/assets/email/marketingEmail/EmailBlast.mjml +++ b/assets/email/marketingEmail/EmailBlast.mjml @@ -4,7 +4,7 @@ - + @@ -67,6 +67,6 @@ - + diff --git a/assets/email/statusEmail/Accepted.mjml b/assets/email/statusEmail/Accepted.mjml index f77abda8..a9a7d154 100644 --- a/assets/email/statusEmail/Accepted.mjml +++ b/assets/email/statusEmail/Accepted.mjml @@ -4,7 +4,7 @@ - + @@ -34,9 +34,9 @@ - - + + - + diff --git a/assets/email/statusEmail/Applied.mjml b/assets/email/statusEmail/Applied.mjml index b00229e9..39ab11f6 100644 --- a/assets/email/statusEmail/Applied.mjml +++ b/assets/email/statusEmail/Applied.mjml @@ -4,7 +4,7 @@ - + @@ -27,8 +27,8 @@ - + - + diff --git a/assets/email/statusEmail/Checked-In.mjml b/assets/email/statusEmail/Checked-In.mjml index 0f0c09ab..d43ed5fa 100644 --- a/assets/email/statusEmail/Checked-In.mjml +++ b/assets/email/statusEmail/Checked-In.mjml @@ -4,7 +4,7 @@ - + @@ -35,8 +35,8 @@ - + - + diff --git a/assets/email/statusEmail/Confirmed.mjml b/assets/email/statusEmail/Confirmed.mjml index 1d99239f..7d9d2e13 100644 --- a/assets/email/statusEmail/Confirmed.mjml +++ b/assets/email/statusEmail/Confirmed.mjml @@ -4,7 +4,7 @@ - + @@ -22,8 +22,8 @@ - + - + diff --git a/assets/email/statusEmail/Declined.mjml b/assets/email/statusEmail/Declined.mjml index 9b95c21a..691ca9e8 100644 --- a/assets/email/statusEmail/Declined.mjml +++ b/assets/email/statusEmail/Declined.mjml @@ -4,7 +4,7 @@ - + @@ -27,8 +27,8 @@ - + - + diff --git a/assets/email/statusEmail/None.mjml b/assets/email/statusEmail/None.mjml index 9c35db27..f1ba26eb 100644 --- a/assets/email/statusEmail/None.mjml +++ b/assets/email/statusEmail/None.mjml @@ -4,7 +4,7 @@ - + @@ -29,8 +29,8 @@ - + - + diff --git a/assets/email/statusEmail/Waitlisted.mjml b/assets/email/statusEmail/Waitlisted.mjml index 73f01492..05874898 100644 --- a/assets/email/statusEmail/Waitlisted.mjml +++ b/assets/email/statusEmail/Waitlisted.mjml @@ -4,7 +4,7 @@ - + @@ -27,8 +27,8 @@ - + - + diff --git a/assets/email/statusEmail/Withdrawn.mjml b/assets/email/statusEmail/Withdrawn.mjml index 857f1302..f140b7dd 100644 --- a/assets/email/statusEmail/Withdrawn.mjml +++ b/assets/email/statusEmail/Withdrawn.mjml @@ -4,7 +4,7 @@ - + @@ -21,8 +21,8 @@ - + - + From db3561e867d5db09c849e3615e778a2c69bac519 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Wed, 22 Dec 2021 18:59:43 -0500 Subject: [PATCH 08/72] feat: add new/updated packages. --- package-lock.json | 2119 +++++++++++++++++++++++++++++++++++++-------- package.json | 7 +- 2 files changed, 1786 insertions(+), 340 deletions(-) diff --git a/package-lock.json b/package-lock.json index e71e9b77..eda2207f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,9 +8,12 @@ "name": "hackerAPI", "version": "3.1.3", "dependencies": { + "@decorators/di": "^1.0.3", + "@decorators/express": "^2.6.0", "@google-cloud/storage": "^5.10.0", "@sendgrid/mail": "^7.4.5", "bcrypt": "^5.0.1", + "class-transformer": "^0.5.1", "class-validator": "^0.13.2", "cookie-parser": "^1.4.5", "cookie-session": "^2.0.0-rc.1", @@ -24,8 +27,10 @@ "handlebars": "^4.7.7", "jsonwebtoken": "^8.5.1", "memory-cache": "^0.2.0", + "mjml": "^4.11.0", "mongoose": "^5.13.3", "multer": "^1.4.2", + "nodemailer": "^6.7.2", "passport": "^0.4.1", "passport-local": "^1.0.0", "pg": "^8.7.1", @@ -33,6 +38,7 @@ "q": "^1.5.1", "qrcode": "^1.4.4", "reflect-metadata": "^0.1.13", + "tsyringe": "^4.6.0", "typeorm": "^0.2.41", "typescript": "^4.5.2", "winston": "^3.3.3" @@ -42,9 +48,12 @@ "@types/express": "^4.17.13", "@types/express-winston": "^4.0.0", "@types/google-cloud__storage": "^1.7.2", + "@types/jsonwebtoken": "^8.5.6", + "@types/mjml": "^4.7.0", "@types/mongodb": "^3.6.20", "@types/mongoose": "^5.11.97", "@types/multer": "^1.4.7", + "@types/nodemailer": "^6.4.4", "@types/passport": "^1.0.7", "@types/passport-local": "^1.0.34", "@types/superagent": "^4.1.13", @@ -58,8 +67,7 @@ "mocha": "^9.0.3", "nodemon": "^2.0.12", "prettier": "1.19.1", - "rimraf": "^3.0.2", - "ts-node": "^10.4.0" + "rimraf": "^3.0.2" } }, "node_modules/@babel/code-frame": { @@ -165,25 +173,15 @@ "node": ">=4" } }, - "node_modules/@cspotcode/source-map-consumer": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", - "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", - "dev": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", - "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", - "dev": true, + "node_modules/@babel/runtime": { + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz", + "integrity": "sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA==", "dependencies": { - "@cspotcode/source-map-consumer": "0.8.0" + "regenerator-runtime": "^0.13.4" }, "engines": { - "node": ">=12" + "node": ">=6.9.0" } }, "node_modules/@dabh/diagnostics": { @@ -196,6 +194,29 @@ "kuler": "^2.0.0" } }, + "node_modules/@decorators/di": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@decorators/di/-/di-1.0.3.tgz", + "integrity": "sha512-wafyQo5lqGABT+Lh7Od9/qULg7DG/kZFU3mLUKZFuiV/KATYlnv198yQxaZUZerhUDoTl/cZKu9t4mJa0rZK4Q==", + "dependencies": { + "reflect-metadata": "0.1.13" + }, + "engines": { + "node": ">=7.1.0" + } + }, + "node_modules/@decorators/express": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@decorators/express/-/express-2.6.0.tgz", + "integrity": "sha512-th/LqSAHAAW1ob2CU6hxtsfnryGThmz0AmGP45rA3Yoi0Q7+FHAZVfH7NJSYHITai/uXjjOtZPPW/V0gFfbgUw==", + "engines": { + "node": ">=7.1.0" + }, + "peerDependencies": { + "@decorators/di": ">=1.0.2", + "express": ">=4.16.3" + } + }, "node_modules/@eslint/eslintrc": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", @@ -400,30 +421,6 @@ "node": ">= 10" } }, - "node_modules/@tsconfig/node10": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", - "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", - "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", - "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", - "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", - "dev": true - }, "node_modules/@types/bcrypt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.0.tgz", @@ -522,12 +519,36 @@ "@types/request": "*" } }, + "node_modules/@types/jsonwebtoken": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.6.tgz", + "integrity": "sha512-+P3O/xC7nzVizIi5VbF34YtqSonFsdnbXBnWUCYRiKOi1f9gA4sEFvXkrGr/QVV23IbMYvcoerI7nnhDUiWXRQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", "dev": true }, + "node_modules/@types/mjml": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@types/mjml/-/mjml-4.7.0.tgz", + "integrity": "sha512-aWWu8Lxq2SexXGs+lBPRUpN3kFf0sDRo3Y4jz7BQ15cQvMfyZOadgFJsNlHmDqI6D2Qjx0PIK+1f9IMXgq9vTA==", + "dev": true, + "dependencies": { + "@types/mjml-core": "*" + } + }, + "node_modules/@types/mjml-core": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/@types/mjml-core/-/mjml-core-4.7.1.tgz", + "integrity": "sha512-k5IRafi93tyZBGF+0BTrcBDvG47OueI+Q7TC4V4UjGQn0AMVvL3Y+S26QF/UHMmMJW5r1hxLyv3StX2/+FatFg==", + "dev": true + }, "node_modules/@types/mongodb": { "version": "3.6.20", "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.20.tgz", @@ -561,6 +582,15 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.10.tgz", "integrity": "sha512-3aRnHa1KlOEEhJ6+CvyHKK5vE9BcLGjtUpwvqYLRvYNQKMfabu3BwfJaA/SLW8dxe28LsNDjtHwePTuzn3gmOA==" }, + "node_modules/@types/nodemailer": { + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.4.tgz", + "integrity": "sha512-Ksw4t7iliXeYGvIQcSIgWQ5BLuC/mljIEbjf615svhZL10PE9t+ei8O9gDaD3FPCasUJn9KTLwz2JFJyiiyuqw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/passport": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.7.tgz", @@ -707,15 +737,6 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -756,7 +777,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, "engines": { "node": ">=6" } @@ -792,7 +812,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -870,12 +889,6 @@ "node": ">=10" } }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -1019,7 +1032,6 @@ "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" } @@ -1130,6 +1142,11 @@ "node": ">=0.6" } }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" + }, "node_modules/boom": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/boom/-/boom-7.3.0.tgz", @@ -1174,7 +1191,6 @@ "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" }, @@ -1344,6 +1360,15 @@ "node": ">=6" } }, + "node_modules/camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", + "dependencies": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, "node_modules/camelcase": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.1.tgz", @@ -1425,11 +1450,50 @@ "node": "*" } }, + "node_modules/cheerio": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", + "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", + "dependencies": { + "cheerio-select": "^1.5.0", + "dom-serializer": "^1.3.2", + "domhandler": "^4.2.0", + "htmlparser2": "^6.1.0", + "parse5": "^6.0.1", + "parse5-htmlparser2-tree-adapter": "^6.0.1", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.5.0.tgz", + "integrity": "sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==", + "dependencies": { + "css-select": "^4.1.3", + "css-what": "^5.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0", + "domutils": "^2.7.0" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cheerio/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, "node_modules/chokidar": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", - "dev": true, "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -1460,6 +1524,11 @@ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "dev": true }, + "node_modules/class-transformer": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", + "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==" + }, "node_modules/class-validator": { "version": "0.13.2", "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.13.2.tgz", @@ -1469,6 +1538,17 @@ "validator": "^13.7.0" } }, + "node_modules/clean-css": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz", + "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 4.0" + } + }, "node_modules/cli-boxes": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", @@ -1599,8 +1679,7 @@ "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, "node_modules/component-emitter": { "version": "1.3.0", @@ -1670,6 +1749,20 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/config-chain/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, "node_modules/configstore": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", @@ -1798,12 +1891,6 @@ "node": ">= 0.10" } }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -1835,6 +1922,32 @@ "node": ">=8" } }, + "node_modules/css-select": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.0.tgz", + "integrity": "sha512-6YVG6hsH9yIb/si3Th/is8Pex7qnVHO6t7q7U6TIUnkQASGbS8tnUDBftnPynLNnuUl/r2+PTd0ekiiq7R0zJw==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^5.1.0", + "domhandler": "^4.3.0", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", + "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/date-and-time": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-2.0.1.tgz", @@ -1978,6 +2091,11 @@ "node": ">=0.10" } }, + "node_modules/detect-node": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", + "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==" + }, "node_modules/dicer": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", @@ -2037,6 +2155,57 @@ "node": ">=6.0.0" } }, + "node_modules/dom-serializer": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", + "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", + "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/dot-prop": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", @@ -2081,6 +2250,42 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/editorconfig": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", + "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", + "dependencies": { + "commander": "^2.19.0", + "lru-cache": "^4.1.5", + "semver": "^5.6.0", + "sigmund": "^1.0.1" + }, + "bin": { + "editorconfig": "bin/editorconfig" + } + }, + "node_modules/editorconfig/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/editorconfig/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/editorconfig/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -2137,8 +2342,7 @@ "node_modules/entities": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", - "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", - "dev": true + "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==" }, "node_modules/es-abstract": { "version": "1.19.1", @@ -2722,7 +2926,6 @@ "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" }, @@ -2903,7 +3106,6 @@ "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": [ @@ -3070,7 +3272,6 @@ "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" }, @@ -3297,7 +3498,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, "bin": { "he": "bin/he" } @@ -3316,6 +3516,44 @@ "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==", "deprecated": "This module has moved and is now available at @hapi/hoek. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues." }, + "node_modules/html-minifier": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-4.0.0.tgz", + "integrity": "sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==", + "dependencies": { + "camel-case": "^3.0.0", + "clean-css": "^4.2.1", + "commander": "^2.19.0", + "he": "^1.2.0", + "param-case": "^2.1.1", + "relateurl": "^0.2.7", + "uglify-js": "^3.5.1" + }, + "bin": { + "html-minifier": "cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, "node_modules/http-cache-semantics": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", @@ -3542,7 +3780,6 @@ "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" }, @@ -3606,7 +3843,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -3623,7 +3859,6 @@ "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" }, @@ -3694,7 +3929,6 @@ "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" } @@ -3874,6 +4108,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/js-beautify": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.0.tgz", + "integrity": "sha512-yuck9KirNSCAwyNJbqW+BxJqJ0NLJ4PwBUzQQACl5O3qHMBXVkXb/rD0ilh/Lat/tn88zSZ+CAHOlk0DsY7GuQ==", + "dependencies": { + "config-chain": "^1.1.12", + "editorconfig": "^0.15.3", + "glob": "^7.1.3", + "nopt": "^5.0.0" + }, + "bin": { + "css-beautify": "js/bin/css-beautify.js", + "html-beautify": "js/bin/html-beautify.js", + "js-beautify": "js/bin/js-beautify.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -3979,6 +4232,32 @@ "semver": "bin/semver" } }, + "node_modules/juice": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/juice/-/juice-7.0.0.tgz", + "integrity": "sha512-AjKQX31KKN+uJs+zaf+GW8mBO/f/0NqSh2moTMyvwBY+4/lXIYTU8D8I2h6BAV3Xnz6GGsbalUyFqbYMe+Vh+Q==", + "dependencies": { + "cheerio": "^1.0.0-rc.3", + "commander": "^5.1.0", + "mensch": "^0.3.4", + "slick": "^1.12.2", + "web-resource-inliner": "^5.0.0" + }, + "bin": { + "juice": "bin/juice" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/juice/node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "engines": { + "node": ">= 6" + } + }, "node_modules/jwa": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", @@ -4179,6 +4458,11 @@ "node": ">=0.1.90" } }, + "node_modules/lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=" + }, "node_modules/lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", @@ -4221,12 +4505,6 @@ "semver": "bin/semver.js" } }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, "node_modules/markdown-it": { "version": "11.0.1", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-11.0.1.tgz", @@ -4268,6 +4546,11 @@ "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", "optional": true }, + "node_modules/mensch": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/mensch/-/mensch-0.3.4.tgz", + "integrity": "sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==" + }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -4359,53 +4642,451 @@ "node": ">= 8" } }, - "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "node_modules/mjml": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml/-/mjml-4.11.0.tgz", + "integrity": "sha512-kYuCAds/8F7m7xNEs3TFkrc0jxnNYIkexQIUNByPLQJFoFRltpgXLSdoyreGAniQtDGITPE+p8FIocLUBKsOHg==", "dependencies": { - "minimist": "^1.2.5" + "@babel/runtime": "^7.14.6", + "mjml-cli": "4.11.0", + "mjml-core": "4.11.0", + "mjml-migrate": "4.11.0", + "mjml-preset-core": "4.11.0", + "mjml-validator": "4.11.0" }, "bin": { - "mkdirp": "bin/cmd.js" + "mjml": "bin/mjml" } }, - "node_modules/mocha": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.1.3.tgz", - "integrity": "sha512-Xcpl9FqXOAYqI3j79pEtHBBnQgVXIhpULjGQa7DVb0Po+VzmSIK9kanAiWLHoRR/dbZ2qpdPshuXr8l1VaHCzw==", - "dev": true, + "node_modules/mjml-accordion": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-accordion/-/mjml-accordion-4.11.0.tgz", + "integrity": "sha512-u6cPMl4z8JeRIq0sGHWfzwE5SqwBhSPHJ8wElhfU7CK6gAoUTz4BIL/03da2whXk0S34n5CSU453JpuWV+3bQQ==", "dependencies": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.2", - "debug": "4.3.2", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.1.7", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "3.0.4", - "ms": "2.1.3", - "nanoid": "3.1.25", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "which": "2.0.2", - "workerpool": "6.1.5", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha" - }, - "engines": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "node_modules/mjml-body": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-body/-/mjml-body-4.11.0.tgz", + "integrity": "sha512-+SQXOjKOr9IMblmslrUbv+ahF/SkqT7mAuix1P/F9ev3aS+WN7Gy/lyJLaq1zhSQCmzrBDovHez3bJ7NGToU0g==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "node_modules/mjml-button": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-button/-/mjml-button-4.11.0.tgz", + "integrity": "sha512-v/MwA2Kq2MlHJwrajdAqUihjAQivD8FpkpOAcqdgqI1ffaEDzd6FGFt5qOtVD9BncChQ4a51haOnPd+kbBLlCA==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "node_modules/mjml-carousel": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-carousel/-/mjml-carousel-4.11.0.tgz", + "integrity": "sha512-/owKKSg3DNes1rauPPhlGCFdZ4zzoxdztPLGOm9TSjkbL5q2cN9NMfzNdTYLnnVG5G5XWX0THjDeeq+bGnHw8w==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "node_modules/mjml-cli": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-cli/-/mjml-cli-4.11.0.tgz", + "integrity": "sha512-jgkxNY+sY+CwiUlO6VX8cwVjlLBXIzE7X4fXkQ2RjXpbAvsN8uDafST8oL8PDlxNIjOwK6YJySzZSLXSKTF5Zg==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "chokidar": "^3.0.0", + "glob": "^7.1.1", + "html-minifier": "^4.0.0", + "js-beautify": "^1.6.14", + "lodash": "^4.17.21", + "mjml-core": "4.11.0", + "mjml-migrate": "4.11.0", + "mjml-parser-xml": "4.11.0", + "mjml-validator": "4.11.0", + "yargs": "^16.1.0" + }, + "bin": { + "mjml-cli": "bin/mjml" + } + }, + "node_modules/mjml-column": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-column/-/mjml-column-4.11.0.tgz", + "integrity": "sha512-yuupexywYXuXTvxxGLPZw6S/D6fz4b41ZarOkEPW8Pbj7FkfnBTO3QokAS5KapJ9x6sIAVs+cCgUul87dwOBzg==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "node_modules/mjml-core": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-core/-/mjml-core-4.11.0.tgz", + "integrity": "sha512-UTI1exu9/0lOF40aacAzC9A7RrJPcay7WYurYsb+X2LbDyfBlSx5ZCtuUTHwLfIz3PL6rSg8yrZ3KtlmhQJ/kQ==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "cheerio": "1.0.0-rc.10", + "detect-node": "2.0.4", + "html-minifier": "^4.0.0", + "js-beautify": "^1.6.14", + "juice": "^7.0.0", + "lodash": "^4.17.21", + "mjml-migrate": "4.11.0", + "mjml-parser-xml": "4.11.0", + "mjml-validator": "4.11.0" + } + }, + "node_modules/mjml-divider": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-divider/-/mjml-divider-4.11.0.tgz", + "integrity": "sha512-jS8Sa7uuFTmThtrcV3FICtbqmA0yJplldaNJwW5upiq7MEXuSwLNzjNeodaTpsVWevf/stE3C4lBA3+V4ascMg==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "node_modules/mjml-group": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-group/-/mjml-group-4.11.0.tgz", + "integrity": "sha512-Yv1ZcPNk4bxOK/eol6bjJvRJBaOCzVY88QO8IfCQifAZuiXhatxwsuwaRKNcTi4cB+IHwl4JguZHgsFRi/Gf/g==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "node_modules/mjml-head": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-head/-/mjml-head-4.11.0.tgz", + "integrity": "sha512-KNaSsOlf5FNwHyZQD6YNZN2Eo/o7n+mZISFLyp9MvNFaT3NKIRJDaInD1WjN+w2aHdXAw4sDV3+/9/EET2bh1A==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "node_modules/mjml-head-attributes": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-head-attributes/-/mjml-head-attributes-4.11.0.tgz", + "integrity": "sha512-azeDRLGH7cU6PoXLd08E/H3UDHFsblBTcme++OWrj5B21vaFguOBySO2eWFTyWLthy+xst8FftWV46f8BWvciw==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "node_modules/mjml-head-breakpoint": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-head-breakpoint/-/mjml-head-breakpoint-4.11.0.tgz", + "integrity": "sha512-OQ/WpXHagGoiUmBjoMHuxdigyLQrHNL6+Op0LHO87vN1GH2ap4YLcSSegIsThQLi/I7V4/JFZbzS5jV4xd4SMg==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "node_modules/mjml-head-font": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-head-font/-/mjml-head-font-4.11.0.tgz", + "integrity": "sha512-AJQ9lhNzNr0hwPjUID76LNna3U8ycmFH1lyipZOWHTivOVGkSYs8PaboxORfU/QAEDKo/p8LafBAoDPEdSigxA==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "node_modules/mjml-head-html-attributes": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-head-html-attributes/-/mjml-head-html-attributes-4.11.0.tgz", + "integrity": "sha512-Gew9EAuqFu9QR3g+8FyE9WHNMszx1ejzo8dRDIuTaBCDEpaIaPVO7G5rGhT7ADqZufeYtRhBXfXjcShPD/a30g==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "node_modules/mjml-head-preview": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-head-preview/-/mjml-head-preview-4.11.0.tgz", + "integrity": "sha512-f79+OtwC8CYcQpglGNfm3s74qVecdwLlDm9DD/LJvZwIdaALeIfZF36nz6+rtCLMhND+wxgqxqkmbbuS6AbO+A==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "node_modules/mjml-head-style": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-head-style/-/mjml-head-style-4.11.0.tgz", + "integrity": "sha512-jw0r9Ld56SkJmDUBx+27xOH+oY2O06FBcKSJIkZLJ/sefbjgJa2/ti2eso/LeGgrmTw8zge7g1pp0Fl+kPjsGA==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "node_modules/mjml-head-title": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-head-title/-/mjml-head-title-4.11.0.tgz", + "integrity": "sha512-mjYsKoE9+5LI8V0mK9SAKVKspF19TVius2q5I1FXLRdBmt4Ei87CdrSui+iixGrug0Lwt4P2W3+mK8kVGNnJAQ==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "node_modules/mjml-hero": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-hero/-/mjml-hero-4.11.0.tgz", + "integrity": "sha512-tZDCGjQrDICwbsDnLvfVEsQ5+GdrIozB3oO3NxC6m2Eq04VKNBkIqq+QvJyouOxzJ3CZgO2B4rylzxc6YXuHsw==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "node_modules/mjml-image": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-image/-/mjml-image-4.11.0.tgz", + "integrity": "sha512-qjvKS/x2arDNgKppPecmg69VyXdQbb1CNVqPwowJLyfjioTw4hxQ93suWoBKJJojRjkwauj9IRMC8TR9ffn0HQ==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "node_modules/mjml-migrate": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-migrate/-/mjml-migrate-4.11.0.tgz", + "integrity": "sha512-Y+9U4w9LwlTkfTkHX9GdalIQDO4JQxboG4PM8g7vRKNhKSZDZH8QSr0SNhX0+fMQmjb9b0nztWbMVVvNZfMoPQ==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "js-beautify": "^1.6.14", + "lodash": "^4.17.21", + "mjml-core": "4.11.0", + "mjml-parser-xml": "4.11.0", + "yargs": "^16.1.0" + }, + "bin": { + "migrate": "lib/cli.js" + } + }, + "node_modules/mjml-navbar": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-navbar/-/mjml-navbar-4.11.0.tgz", + "integrity": "sha512-FEd+8RD6ra8652jXdMbhfhzT1YY8TA30c34qjJ+ULlFgvLH4GNnYRIOHp/Mgd/L38Qf3bhK/rK9ELBidJ36dLQ==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "node_modules/mjml-parser-xml": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-parser-xml/-/mjml-parser-xml-4.11.0.tgz", + "integrity": "sha512-3toQ9UKyfzXWXJ7PlTExBjzGXAzJNORv39sorPv5sG2KJsvPC6NE+e+/1GyqYFhk4JffHoDfd4mQ6w050qYATQ==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "detect-node": "2.0.4", + "htmlparser2": "^4.1.0", + "lodash": "^4.17.15" + } + }, + "node_modules/mjml-parser-xml/node_modules/domhandler": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", + "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", + "dependencies": { + "domelementtype": "^2.0.1" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/mjml-parser-xml/node_modules/htmlparser2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz", + "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^3.0.0", + "domutils": "^2.0.0", + "entities": "^2.0.0" + } + }, + "node_modules/mjml-preset-core": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-preset-core/-/mjml-preset-core-4.11.0.tgz", + "integrity": "sha512-HU9ZFzS+A7Dx0B/EbnqYjdcIQQuxpOVRfFReQBlllZYwjWaRUjDIeIjF+cdnCb9QveuSNo4msIG00h/MKPYiGQ==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "mjml-accordion": "4.11.0", + "mjml-body": "4.11.0", + "mjml-button": "4.11.0", + "mjml-carousel": "4.11.0", + "mjml-column": "4.11.0", + "mjml-divider": "4.11.0", + "mjml-group": "4.11.0", + "mjml-head": "4.11.0", + "mjml-head-attributes": "4.11.0", + "mjml-head-breakpoint": "4.11.0", + "mjml-head-font": "4.11.0", + "mjml-head-html-attributes": "4.11.0", + "mjml-head-preview": "4.11.0", + "mjml-head-style": "4.11.0", + "mjml-head-title": "4.11.0", + "mjml-hero": "4.11.0", + "mjml-image": "4.11.0", + "mjml-navbar": "4.11.0", + "mjml-raw": "4.11.0", + "mjml-section": "4.11.0", + "mjml-social": "4.11.0", + "mjml-spacer": "4.11.0", + "mjml-table": "4.11.0", + "mjml-text": "4.11.0", + "mjml-wrapper": "4.11.0" + } + }, + "node_modules/mjml-raw": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-raw/-/mjml-raw-4.11.0.tgz", + "integrity": "sha512-DyUwC/JrE8tF7v9XaKQpQ/yAg5tT2uAWSDI6J5x3t3TNFJmRPd3iorSu8v6t1s3OiekuxfagsDDPLFuzpGwZSw==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "node_modules/mjml-section": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-section/-/mjml-section-4.11.0.tgz", + "integrity": "sha512-OpinxE019Z1symrEFku3UddsvSql2aolcAiOThFuAAXz3+tUuooofGMy/XyyMOuOnktOx/5PMcVFsV84/Jye/g==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "node_modules/mjml-social": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-social/-/mjml-social-4.11.0.tgz", + "integrity": "sha512-tM5njGtang0VRWt+XCuMTnZP2IJehUd+kdsC7CnMKQhYI2X4vzEaOBLgXRWvhcT4pSBzEJkXB9sQ+y7JmLO10g==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "node_modules/mjml-spacer": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-spacer/-/mjml-spacer-4.11.0.tgz", + "integrity": "sha512-9s6PjFgznKEFgFZCSa4vTYVDQ6kRH5ucMHGraoHS4VMZLA8QIaVakHd4Sl0n+SGWCqair4xZ3vYYMhOBKIXmMw==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "node_modules/mjml-table": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-table/-/mjml-table-4.11.0.tgz", + "integrity": "sha512-ccniRz1MoDqKS6zoNM59xi81M7zy/tkvd/6weyH9XAZiU7ATgOxoBuIMy+d0uSTlKPWNwoi2FqR5YSedxT2YPw==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "node_modules/mjml-text": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-text/-/mjml-text-4.11.0.tgz", + "integrity": "sha512-xrY5+uepxUg+q5KKuKX2s9KQnnlsMN5aoCt0JSbjt4H9ZwBpqXPD4Z2uJ8eZS33FvnXzUYPNVdKralvXnrsXKA==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "node_modules/mjml-validator": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-validator/-/mjml-validator-4.11.0.tgz", + "integrity": "sha512-oDL9tHcL4PaCZMwH6T/lLpS7LV9cm9lIwnzJy+y5/S81MGMV6kPr6xXHgS0A01G7sseg6+rHgqBnUgzUob4Ilg==", + "dependencies": { + "@babel/runtime": "^7.14.6" + } + }, + "node_modules/mjml-wrapper": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-wrapper/-/mjml-wrapper-4.11.0.tgz", + "integrity": "sha512-WXGKxS+DlYalx5ofwq3bttj26BLEcaueeQ+0BcffXIELojUzd0+xTyX09v0QemUCBmKpHB2QaKMGhzYuSkupyg==", + "dependencies": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0", + "mjml-section": "4.11.0" + } + }, + "node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mocha": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.1.3.tgz", + "integrity": "sha512-Xcpl9FqXOAYqI3j79pEtHBBnQgVXIhpULjGQa7DVb0Po+VzmSIK9kanAiWLHoRR/dbZ2qpdPshuXr8l1VaHCzw==", + "dev": true, + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.2", + "debug": "4.3.2", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.7", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "nanoid": "3.1.25", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "workerpool": "6.1.5", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { "node": ">= 12.0.0" }, "funding": { @@ -4728,6 +5409,14 @@ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, + "node_modules/no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dependencies": { + "lower-case": "^1.1.1" + } + }, "node_modules/node-addon-api": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", @@ -4752,6 +5441,14 @@ "node": ">= 6.0.0" } }, + "node_modules/nodemailer": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.2.tgz", + "integrity": "sha512-Dz7zVwlef4k5R71fdmxwR8Q39fiboGbu3xgswkzGwczUfjp873rVxt1O46+Fh0j1ORnAC6L9+heI8uUpO6DT7Q==", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/nodemon": { "version": "2.0.15", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.15.tgz", @@ -4838,7 +5535,6 @@ "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" } @@ -4866,6 +5562,17 @@ "node": "^12.13.0 || ^14.15.0 || >=16" } }, + "node_modules/nth-check": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", + "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -5042,6 +5749,14 @@ "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" }, + "node_modules/param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "dependencies": { + "no-case": "^2.2.0" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -5233,7 +5948,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true, "engines": { "node": ">=8.6" }, @@ -5359,6 +6073,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -5371,6 +6090,11 @@ "node": ">= 0.10" } }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, "node_modules/pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", @@ -5672,7 +6396,6 @@ "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" }, @@ -5685,6 +6408,11 @@ "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" }, + "node_modules/regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + }, "node_modules/regexp-clone": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz", @@ -5726,6 +6454,14 @@ "node": ">=8" } }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/require-at": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/require-at/-/require-at-1.0.6.tgz", @@ -6019,6 +6755,11 @@ "resolved": "https://registry.npmjs.org/sift/-/sift-13.5.2.tgz", "integrity": "sha512-+gxdEOMA2J+AI+fVsCqeNn7Tgx3M9ZN9jdi95939l1IJ8cZsqS8sqpJyOkic2SJk+1+98Uwryt/gL6XDaV+UZA==" }, + "node_modules/sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=" + }, "node_modules/signal-exit": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", @@ -6054,6 +6795,14 @@ "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" }, + "node_modules/slick": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/slick/-/slick-1.12.2.tgz", + "integrity": "sha1-vQSN23TefRymkV+qSldXCzVQwtc=", + "engines": { + "node": "*" + } + }, "node_modules/snakeize": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/snakeize/-/snakeize-0.1.0.tgz", @@ -6412,7 +7161,6 @@ "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" }, @@ -6465,68 +7213,6 @@ "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" }, - "node_modules/ts-node": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.4.0.tgz", - "integrity": "sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "0.7.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/ts-node/node_modules/acorn": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz", - "integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ts-node/node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/tslib": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", @@ -6540,6 +7226,22 @@ "node": ">=0.6.x" } }, + "node_modules/tsyringe": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.6.0.tgz", + "integrity": "sha512-BMQAZamSfEmIQzH8WJeRu1yZGQbPSDuI9g+yEiKZFIcO46GPZuMOC2d0b52cVBdw1d++06JnDSIIZvEnogMdAw==", + "dependencies": { + "tslib": "^1.9.3" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/tsyringe/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -6788,7 +7490,6 @@ "version": "3.14.3", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.3.tgz", "integrity": "sha512-mic3aOdiq01DuSVx0TseaEzMIVqebMZ0Z3vaeDhFEh9bsc24hV1TFvN74reA2vs08D0ZWfNjAcJ3UbVLaBss+g==", - "optional": true, "bin": { "uglifyjs": "bin/uglifyjs" }, @@ -6872,6 +7573,11 @@ "url": "https://github.com/yeoman/update-notifier?sponsor=1" } }, + "node_modules/upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=" + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -6920,6 +7626,14 @@ "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, + "node_modules/valid-data-url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/valid-data-url/-/valid-data-url-3.0.1.tgz", + "integrity": "sha512-jOWVmzVceKlVVdwjNSenT4PbGghU0SBIizAev8ofZVgivk/TVHXSbNL8LP6M3spZvkR9/QolkyJavGSX5Cs0UA==", + "engines": { + "node": ">=10" + } + }, "node_modules/validator": { "version": "13.7.0", "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", @@ -6936,6 +7650,69 @@ "node": ">= 0.8" } }, + "node_modules/web-resource-inliner": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/web-resource-inliner/-/web-resource-inliner-5.0.0.tgz", + "integrity": "sha512-AIihwH+ZmdHfkJm7BjSXiEClVt4zUFqX4YlFAzjL13wLtDuUneSaFvDBTbdYRecs35SiU7iNKbMnN+++wVfb6A==", + "dependencies": { + "ansi-colors": "^4.1.1", + "escape-goat": "^3.0.0", + "htmlparser2": "^4.0.0", + "mime": "^2.4.6", + "node-fetch": "^2.6.0", + "valid-data-url": "^3.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/web-resource-inliner/node_modules/domhandler": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", + "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", + "dependencies": { + "domelementtype": "^2.0.1" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/web-resource-inliner/node_modules/escape-goat": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-3.0.0.tgz", + "integrity": "sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/web-resource-inliner/node_modules/htmlparser2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz", + "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^3.0.0", + "domutils": "^2.0.0", + "entities": "^2.0.0" + } + }, + "node_modules/web-resource-inliner/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -7209,15 +7986,6 @@ "node": ">=10" } }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -7329,19 +8097,12 @@ } } }, - "@cspotcode/source-map-consumer": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", - "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", - "dev": true - }, - "@cspotcode/source-map-support": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", - "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", - "dev": true, + "@babel/runtime": { + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz", + "integrity": "sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA==", "requires": { - "@cspotcode/source-map-consumer": "0.8.0" + "regenerator-runtime": "^0.13.4" } }, "@dabh/diagnostics": { @@ -7354,6 +8115,20 @@ "kuler": "^2.0.0" } }, + "@decorators/di": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@decorators/di/-/di-1.0.3.tgz", + "integrity": "sha512-wafyQo5lqGABT+Lh7Od9/qULg7DG/kZFU3mLUKZFuiV/KATYlnv198yQxaZUZerhUDoTl/cZKu9t4mJa0rZK4Q==", + "requires": { + "reflect-metadata": "0.1.13" + } + }, + "@decorators/express": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@decorators/express/-/express-2.6.0.tgz", + "integrity": "sha512-th/LqSAHAAW1ob2CU6hxtsfnryGThmz0AmGP45rA3Yoi0Q7+FHAZVfH7NJSYHITai/uXjjOtZPPW/V0gFfbgUw==", + "requires": {} + }, "@eslint/eslintrc": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", @@ -7516,30 +8291,6 @@ "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==" }, - "@tsconfig/node10": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", - "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", - "dev": true - }, - "@tsconfig/node12": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", - "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", - "dev": true - }, - "@tsconfig/node14": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", - "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", - "dev": true - }, - "@tsconfig/node16": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", - "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", - "dev": true - }, "@types/bcrypt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.0.tgz", @@ -7636,12 +8387,36 @@ "@types/request": "*" } }, + "@types/jsonwebtoken": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.6.tgz", + "integrity": "sha512-+P3O/xC7nzVizIi5VbF34YtqSonFsdnbXBnWUCYRiKOi1f9gA4sEFvXkrGr/QVV23IbMYvcoerI7nnhDUiWXRQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", "dev": true }, + "@types/mjml": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@types/mjml/-/mjml-4.7.0.tgz", + "integrity": "sha512-aWWu8Lxq2SexXGs+lBPRUpN3kFf0sDRo3Y4jz7BQ15cQvMfyZOadgFJsNlHmDqI6D2Qjx0PIK+1f9IMXgq9vTA==", + "dev": true, + "requires": { + "@types/mjml-core": "*" + } + }, + "@types/mjml-core": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/@types/mjml-core/-/mjml-core-4.7.1.tgz", + "integrity": "sha512-k5IRafi93tyZBGF+0BTrcBDvG47OueI+Q7TC4V4UjGQn0AMVvL3Y+S26QF/UHMmMJW5r1hxLyv3StX2/+FatFg==", + "dev": true + }, "@types/mongodb": { "version": "3.6.20", "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.20.tgz", @@ -7674,6 +8449,15 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.10.tgz", "integrity": "sha512-3aRnHa1KlOEEhJ6+CvyHKK5vE9BcLGjtUpwvqYLRvYNQKMfabu3BwfJaA/SLW8dxe28LsNDjtHwePTuzn3gmOA==" }, + "@types/nodemailer": { + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.4.tgz", + "integrity": "sha512-Ksw4t7iliXeYGvIQcSIgWQ5BLuC/mljIEbjf615svhZL10PE9t+ei8O9gDaD3FPCasUJn9KTLwz2JFJyiiyuqw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/passport": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.7.tgz", @@ -7806,12 +8590,6 @@ "dev": true, "requires": {} }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true - }, "agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -7844,8 +8622,7 @@ "ansi-colors": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==" }, "ansi-regex": { "version": "5.0.1", @@ -7869,7 +8646,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, "requires": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -7929,12 +8705,6 @@ "readable-stream": "^3.6.0" } }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -8038,8 +8808,7 @@ "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 + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" }, "bl": { "version": "2.2.1", @@ -8139,6 +8908,11 @@ } } }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" + }, "boom": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/boom/-/boom-7.3.0.tgz", @@ -8176,7 +8950,6 @@ "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" } @@ -8303,6 +9076,15 @@ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, + "camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, "camelcase": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.1.tgz", @@ -8365,11 +9147,43 @@ "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", "dev": true }, + "cheerio": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", + "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", + "requires": { + "cheerio-select": "^1.5.0", + "dom-serializer": "^1.3.2", + "domhandler": "^4.2.0", + "htmlparser2": "^6.1.0", + "parse5": "^6.0.1", + "parse5-htmlparser2-tree-adapter": "^6.0.1", + "tslib": "^2.2.0" + }, + "dependencies": { + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + } + } + }, + "cheerio-select": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.5.0.tgz", + "integrity": "sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==", + "requires": { + "css-select": "^4.1.3", + "css-what": "^5.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0", + "domutils": "^2.7.0" + } + }, "chokidar": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", - "dev": true, "requires": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -8392,6 +9206,11 @@ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "dev": true }, + "class-transformer": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", + "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==" + }, "class-validator": { "version": "0.13.2", "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.13.2.tgz", @@ -8401,6 +9220,14 @@ "validator": "^13.7.0" } }, + "clean-css": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz", + "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==", + "requires": { + "source-map": "~0.6.0" + } + }, "cli-boxes": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", @@ -8511,8 +9338,7 @@ "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, "component-emitter": { "version": "1.3.0", @@ -8578,6 +9404,22 @@ } } }, + "config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + }, + "dependencies": { + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + } + } + }, "configstore": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", @@ -8685,12 +9527,6 @@ "vary": "^1" } }, - "create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -8715,6 +9551,23 @@ "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" }, + "css-select": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.0.tgz", + "integrity": "sha512-6YVG6hsH9yIb/si3Th/is8Pex7qnVHO6t7q7U6TIUnkQASGbS8tnUDBftnPynLNnuUl/r2+PTd0ekiiq7R0zJw==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^5.1.0", + "domhandler": "^4.3.0", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, + "css-what": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", + "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==" + }, "date-and-time": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-2.0.1.tgz", @@ -8814,6 +9667,11 @@ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" }, + "detect-node": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", + "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==" + }, "dicer": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", @@ -8857,13 +9715,46 @@ "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.2.tgz", "integrity": "sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg==" }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, + "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": "1.3.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", + "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==" + }, + "domhandler": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", + "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", "requires": { - "esutils": "^2.0.2" + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" } }, "dot-prop": { @@ -8904,6 +9795,38 @@ "safe-buffer": "^5.0.1" } }, + "editorconfig": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", + "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", + "requires": { + "commander": "^2.19.0", + "lru-cache": "^4.1.5", + "semver": "^5.6.0", + "sigmund": "^1.0.1" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + } + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -8954,8 +9877,7 @@ "entities": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", - "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", - "dev": true + "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==" }, "es-abstract": { "version": "1.19.1", @@ -9407,7 +10329,6 @@ "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" } @@ -9539,7 +10460,6 @@ "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": { @@ -9657,7 +10577,6 @@ "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" } @@ -9817,8 +10736,7 @@ "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" }, "highlight.js": { "version": "10.7.3", @@ -9830,6 +10748,31 @@ "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz", "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==" }, + "html-minifier": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-4.0.0.tgz", + "integrity": "sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==", + "requires": { + "camel-case": "^3.0.0", + "clean-css": "^4.2.1", + "commander": "^2.19.0", + "he": "^1.2.0", + "param-case": "^2.1.1", + "relateurl": "^0.2.7", + "uglify-js": "^3.5.1" + } + }, + "htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, "http-cache-semantics": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", @@ -9993,7 +10936,6 @@ "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" } @@ -10032,8 +10974,7 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, "is-fullwidth-code-point": { "version": "3.0.0", @@ -10044,7 +10985,6 @@ "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" } @@ -10087,8 +11027,7 @@ "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 + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, "is-number-object": { "version": "1.0.6", @@ -10205,6 +11144,17 @@ "iterate-iterator": "^1.0.1" } }, + "js-beautify": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.0.tgz", + "integrity": "sha512-yuck9KirNSCAwyNJbqW+BxJqJ0NLJ4PwBUzQQACl5O3qHMBXVkXb/rD0ilh/Lat/tn88zSZ+CAHOlk0DsY7GuQ==", + "requires": { + "config-chain": "^1.1.12", + "editorconfig": "^0.15.3", + "glob": "^7.1.3", + "nopt": "^5.0.0" + } + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -10300,6 +11250,25 @@ } } }, + "juice": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/juice/-/juice-7.0.0.tgz", + "integrity": "sha512-AjKQX31KKN+uJs+zaf+GW8mBO/f/0NqSh2moTMyvwBY+4/lXIYTU8D8I2h6BAV3Xnz6GGsbalUyFqbYMe+Vh+Q==", + "requires": { + "cheerio": "^1.0.0-rc.3", + "commander": "^5.1.0", + "mensch": "^0.3.4", + "slick": "^1.12.2", + "web-resource-inliner": "^5.0.0" + }, + "dependencies": { + "commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==" + } + } + }, "jwa": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", @@ -10478,6 +11447,11 @@ } } }, + "lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=" + }, "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", @@ -10507,12 +11481,6 @@ } } }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, "markdown-it": { "version": "11.0.1", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-11.0.1.tgz", @@ -10548,6 +11516,11 @@ "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", "optional": true }, + "mensch": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/mensch/-/mensch-0.3.4.tgz", + "integrity": "sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==" + }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -10612,6 +11585,391 @@ "yallist": "^4.0.0" } }, + "mjml": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml/-/mjml-4.11.0.tgz", + "integrity": "sha512-kYuCAds/8F7m7xNEs3TFkrc0jxnNYIkexQIUNByPLQJFoFRltpgXLSdoyreGAniQtDGITPE+p8FIocLUBKsOHg==", + "requires": { + "@babel/runtime": "^7.14.6", + "mjml-cli": "4.11.0", + "mjml-core": "4.11.0", + "mjml-migrate": "4.11.0", + "mjml-preset-core": "4.11.0", + "mjml-validator": "4.11.0" + } + }, + "mjml-accordion": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-accordion/-/mjml-accordion-4.11.0.tgz", + "integrity": "sha512-u6cPMl4z8JeRIq0sGHWfzwE5SqwBhSPHJ8wElhfU7CK6gAoUTz4BIL/03da2whXk0S34n5CSU453JpuWV+3bQQ==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "mjml-body": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-body/-/mjml-body-4.11.0.tgz", + "integrity": "sha512-+SQXOjKOr9IMblmslrUbv+ahF/SkqT7mAuix1P/F9ev3aS+WN7Gy/lyJLaq1zhSQCmzrBDovHez3bJ7NGToU0g==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "mjml-button": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-button/-/mjml-button-4.11.0.tgz", + "integrity": "sha512-v/MwA2Kq2MlHJwrajdAqUihjAQivD8FpkpOAcqdgqI1ffaEDzd6FGFt5qOtVD9BncChQ4a51haOnPd+kbBLlCA==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "mjml-carousel": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-carousel/-/mjml-carousel-4.11.0.tgz", + "integrity": "sha512-/owKKSg3DNes1rauPPhlGCFdZ4zzoxdztPLGOm9TSjkbL5q2cN9NMfzNdTYLnnVG5G5XWX0THjDeeq+bGnHw8w==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "mjml-cli": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-cli/-/mjml-cli-4.11.0.tgz", + "integrity": "sha512-jgkxNY+sY+CwiUlO6VX8cwVjlLBXIzE7X4fXkQ2RjXpbAvsN8uDafST8oL8PDlxNIjOwK6YJySzZSLXSKTF5Zg==", + "requires": { + "@babel/runtime": "^7.14.6", + "chokidar": "^3.0.0", + "glob": "^7.1.1", + "html-minifier": "^4.0.0", + "js-beautify": "^1.6.14", + "lodash": "^4.17.21", + "mjml-core": "4.11.0", + "mjml-migrate": "4.11.0", + "mjml-parser-xml": "4.11.0", + "mjml-validator": "4.11.0", + "yargs": "^16.1.0" + } + }, + "mjml-column": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-column/-/mjml-column-4.11.0.tgz", + "integrity": "sha512-yuupexywYXuXTvxxGLPZw6S/D6fz4b41ZarOkEPW8Pbj7FkfnBTO3QokAS5KapJ9x6sIAVs+cCgUul87dwOBzg==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "mjml-core": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-core/-/mjml-core-4.11.0.tgz", + "integrity": "sha512-UTI1exu9/0lOF40aacAzC9A7RrJPcay7WYurYsb+X2LbDyfBlSx5ZCtuUTHwLfIz3PL6rSg8yrZ3KtlmhQJ/kQ==", + "requires": { + "@babel/runtime": "^7.14.6", + "cheerio": "1.0.0-rc.10", + "detect-node": "2.0.4", + "html-minifier": "^4.0.0", + "js-beautify": "^1.6.14", + "juice": "^7.0.0", + "lodash": "^4.17.21", + "mjml-migrate": "4.11.0", + "mjml-parser-xml": "4.11.0", + "mjml-validator": "4.11.0" + } + }, + "mjml-divider": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-divider/-/mjml-divider-4.11.0.tgz", + "integrity": "sha512-jS8Sa7uuFTmThtrcV3FICtbqmA0yJplldaNJwW5upiq7MEXuSwLNzjNeodaTpsVWevf/stE3C4lBA3+V4ascMg==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "mjml-group": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-group/-/mjml-group-4.11.0.tgz", + "integrity": "sha512-Yv1ZcPNk4bxOK/eol6bjJvRJBaOCzVY88QO8IfCQifAZuiXhatxwsuwaRKNcTi4cB+IHwl4JguZHgsFRi/Gf/g==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "mjml-head": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-head/-/mjml-head-4.11.0.tgz", + "integrity": "sha512-KNaSsOlf5FNwHyZQD6YNZN2Eo/o7n+mZISFLyp9MvNFaT3NKIRJDaInD1WjN+w2aHdXAw4sDV3+/9/EET2bh1A==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "mjml-head-attributes": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-head-attributes/-/mjml-head-attributes-4.11.0.tgz", + "integrity": "sha512-azeDRLGH7cU6PoXLd08E/H3UDHFsblBTcme++OWrj5B21vaFguOBySO2eWFTyWLthy+xst8FftWV46f8BWvciw==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "mjml-head-breakpoint": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-head-breakpoint/-/mjml-head-breakpoint-4.11.0.tgz", + "integrity": "sha512-OQ/WpXHagGoiUmBjoMHuxdigyLQrHNL6+Op0LHO87vN1GH2ap4YLcSSegIsThQLi/I7V4/JFZbzS5jV4xd4SMg==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "mjml-head-font": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-head-font/-/mjml-head-font-4.11.0.tgz", + "integrity": "sha512-AJQ9lhNzNr0hwPjUID76LNna3U8ycmFH1lyipZOWHTivOVGkSYs8PaboxORfU/QAEDKo/p8LafBAoDPEdSigxA==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "mjml-head-html-attributes": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-head-html-attributes/-/mjml-head-html-attributes-4.11.0.tgz", + "integrity": "sha512-Gew9EAuqFu9QR3g+8FyE9WHNMszx1ejzo8dRDIuTaBCDEpaIaPVO7G5rGhT7ADqZufeYtRhBXfXjcShPD/a30g==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "mjml-head-preview": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-head-preview/-/mjml-head-preview-4.11.0.tgz", + "integrity": "sha512-f79+OtwC8CYcQpglGNfm3s74qVecdwLlDm9DD/LJvZwIdaALeIfZF36nz6+rtCLMhND+wxgqxqkmbbuS6AbO+A==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "mjml-head-style": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-head-style/-/mjml-head-style-4.11.0.tgz", + "integrity": "sha512-jw0r9Ld56SkJmDUBx+27xOH+oY2O06FBcKSJIkZLJ/sefbjgJa2/ti2eso/LeGgrmTw8zge7g1pp0Fl+kPjsGA==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "mjml-head-title": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-head-title/-/mjml-head-title-4.11.0.tgz", + "integrity": "sha512-mjYsKoE9+5LI8V0mK9SAKVKspF19TVius2q5I1FXLRdBmt4Ei87CdrSui+iixGrug0Lwt4P2W3+mK8kVGNnJAQ==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "mjml-hero": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-hero/-/mjml-hero-4.11.0.tgz", + "integrity": "sha512-tZDCGjQrDICwbsDnLvfVEsQ5+GdrIozB3oO3NxC6m2Eq04VKNBkIqq+QvJyouOxzJ3CZgO2B4rylzxc6YXuHsw==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "mjml-image": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-image/-/mjml-image-4.11.0.tgz", + "integrity": "sha512-qjvKS/x2arDNgKppPecmg69VyXdQbb1CNVqPwowJLyfjioTw4hxQ93suWoBKJJojRjkwauj9IRMC8TR9ffn0HQ==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "mjml-migrate": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-migrate/-/mjml-migrate-4.11.0.tgz", + "integrity": "sha512-Y+9U4w9LwlTkfTkHX9GdalIQDO4JQxboG4PM8g7vRKNhKSZDZH8QSr0SNhX0+fMQmjb9b0nztWbMVVvNZfMoPQ==", + "requires": { + "@babel/runtime": "^7.14.6", + "js-beautify": "^1.6.14", + "lodash": "^4.17.21", + "mjml-core": "4.11.0", + "mjml-parser-xml": "4.11.0", + "yargs": "^16.1.0" + } + }, + "mjml-navbar": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-navbar/-/mjml-navbar-4.11.0.tgz", + "integrity": "sha512-FEd+8RD6ra8652jXdMbhfhzT1YY8TA30c34qjJ+ULlFgvLH4GNnYRIOHp/Mgd/L38Qf3bhK/rK9ELBidJ36dLQ==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "mjml-parser-xml": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-parser-xml/-/mjml-parser-xml-4.11.0.tgz", + "integrity": "sha512-3toQ9UKyfzXWXJ7PlTExBjzGXAzJNORv39sorPv5sG2KJsvPC6NE+e+/1GyqYFhk4JffHoDfd4mQ6w050qYATQ==", + "requires": { + "@babel/runtime": "^7.14.6", + "detect-node": "2.0.4", + "htmlparser2": "^4.1.0", + "lodash": "^4.17.15" + }, + "dependencies": { + "domhandler": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", + "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", + "requires": { + "domelementtype": "^2.0.1" + } + }, + "htmlparser2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz", + "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^3.0.0", + "domutils": "^2.0.0", + "entities": "^2.0.0" + } + } + } + }, + "mjml-preset-core": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-preset-core/-/mjml-preset-core-4.11.0.tgz", + "integrity": "sha512-HU9ZFzS+A7Dx0B/EbnqYjdcIQQuxpOVRfFReQBlllZYwjWaRUjDIeIjF+cdnCb9QveuSNo4msIG00h/MKPYiGQ==", + "requires": { + "@babel/runtime": "^7.14.6", + "mjml-accordion": "4.11.0", + "mjml-body": "4.11.0", + "mjml-button": "4.11.0", + "mjml-carousel": "4.11.0", + "mjml-column": "4.11.0", + "mjml-divider": "4.11.0", + "mjml-group": "4.11.0", + "mjml-head": "4.11.0", + "mjml-head-attributes": "4.11.0", + "mjml-head-breakpoint": "4.11.0", + "mjml-head-font": "4.11.0", + "mjml-head-html-attributes": "4.11.0", + "mjml-head-preview": "4.11.0", + "mjml-head-style": "4.11.0", + "mjml-head-title": "4.11.0", + "mjml-hero": "4.11.0", + "mjml-image": "4.11.0", + "mjml-navbar": "4.11.0", + "mjml-raw": "4.11.0", + "mjml-section": "4.11.0", + "mjml-social": "4.11.0", + "mjml-spacer": "4.11.0", + "mjml-table": "4.11.0", + "mjml-text": "4.11.0", + "mjml-wrapper": "4.11.0" + } + }, + "mjml-raw": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-raw/-/mjml-raw-4.11.0.tgz", + "integrity": "sha512-DyUwC/JrE8tF7v9XaKQpQ/yAg5tT2uAWSDI6J5x3t3TNFJmRPd3iorSu8v6t1s3OiekuxfagsDDPLFuzpGwZSw==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "mjml-section": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-section/-/mjml-section-4.11.0.tgz", + "integrity": "sha512-OpinxE019Z1symrEFku3UddsvSql2aolcAiOThFuAAXz3+tUuooofGMy/XyyMOuOnktOx/5PMcVFsV84/Jye/g==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "mjml-social": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-social/-/mjml-social-4.11.0.tgz", + "integrity": "sha512-tM5njGtang0VRWt+XCuMTnZP2IJehUd+kdsC7CnMKQhYI2X4vzEaOBLgXRWvhcT4pSBzEJkXB9sQ+y7JmLO10g==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "mjml-spacer": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-spacer/-/mjml-spacer-4.11.0.tgz", + "integrity": "sha512-9s6PjFgznKEFgFZCSa4vTYVDQ6kRH5ucMHGraoHS4VMZLA8QIaVakHd4Sl0n+SGWCqair4xZ3vYYMhOBKIXmMw==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "mjml-table": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-table/-/mjml-table-4.11.0.tgz", + "integrity": "sha512-ccniRz1MoDqKS6zoNM59xi81M7zy/tkvd/6weyH9XAZiU7ATgOxoBuIMy+d0uSTlKPWNwoi2FqR5YSedxT2YPw==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "mjml-text": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-text/-/mjml-text-4.11.0.tgz", + "integrity": "sha512-xrY5+uepxUg+q5KKuKX2s9KQnnlsMN5aoCt0JSbjt4H9ZwBpqXPD4Z2uJ8eZS33FvnXzUYPNVdKralvXnrsXKA==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0" + } + }, + "mjml-validator": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-validator/-/mjml-validator-4.11.0.tgz", + "integrity": "sha512-oDL9tHcL4PaCZMwH6T/lLpS7LV9cm9lIwnzJy+y5/S81MGMV6kPr6xXHgS0A01G7sseg6+rHgqBnUgzUob4Ilg==", + "requires": { + "@babel/runtime": "^7.14.6" + } + }, + "mjml-wrapper": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/mjml-wrapper/-/mjml-wrapper-4.11.0.tgz", + "integrity": "sha512-WXGKxS+DlYalx5ofwq3bttj26BLEcaueeQ+0BcffXIELojUzd0+xTyX09v0QemUCBmKpHB2QaKMGhzYuSkupyg==", + "requires": { + "@babel/runtime": "^7.14.6", + "lodash": "^4.17.21", + "mjml-core": "4.11.0", + "mjml-section": "4.11.0" + } + }, "mkdirp": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", @@ -10879,6 +12237,14 @@ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, + "no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "requires": { + "lower-case": "^1.1.1" + } + }, "node-addon-api": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", @@ -10897,6 +12263,11 @@ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" }, + "nodemailer": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.2.tgz", + "integrity": "sha512-Dz7zVwlef4k5R71fdmxwR8Q39fiboGbu3xgswkzGwczUfjp873rVxt1O46+Fh0j1ORnAC6L9+heI8uUpO6DT7Q==" + }, "nodemon": { "version": "2.0.15", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.15.tgz", @@ -10958,8 +12329,7 @@ "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 + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, "normalize-url": { "version": "4.5.1", @@ -10978,6 +12348,14 @@ "set-blocking": "^2.0.0" } }, + "nth-check": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", + "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "requires": { + "boolbase": "^1.0.0" + } + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -11105,6 +12483,14 @@ "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" }, + "param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "requires": { + "no-case": "^2.2.0" + } + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -11251,8 +12637,7 @@ "picomatch": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" }, "pngjs": { "version": "5.0.0", @@ -11333,6 +12718,11 @@ "iterate-value": "^1.0.2" } }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" + }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -11342,6 +12732,11 @@ "ipaddr.js": "1.9.1" } }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, "pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", @@ -11579,7 +12974,6 @@ "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" } @@ -11589,6 +12983,11 @@ "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + }, "regexp-clone": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz", @@ -11618,6 +13017,11 @@ "rc": "^1.2.8" } }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=" + }, "require-at": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/require-at/-/require-at-1.0.6.tgz", @@ -11851,6 +13255,11 @@ "resolved": "https://registry.npmjs.org/sift/-/sift-13.5.2.tgz", "integrity": "sha512-+gxdEOMA2J+AI+fVsCqeNn7Tgx3M9ZN9jdi95939l1IJ8cZsqS8sqpJyOkic2SJk+1+98Uwryt/gL6XDaV+UZA==" }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=" + }, "signal-exit": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", @@ -11880,6 +13289,11 @@ "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" }, + "slick": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/slick/-/slick-1.12.2.tgz", + "integrity": "sha1-vQSN23TefRymkV+qSldXCzVQwtc=" + }, "snakeize": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/snakeize/-/snakeize-0.1.0.tgz", @@ -12177,7 +13591,6 @@ "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" } @@ -12217,40 +13630,6 @@ "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" }, - "ts-node": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.4.0.tgz", - "integrity": "sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==", - "dev": true, - "requires": { - "@cspotcode/source-map-support": "0.7.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "yn": "3.1.1" - }, - "dependencies": { - "acorn": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz", - "integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==", - "dev": true - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - } - } - }, "tslib": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", @@ -12261,6 +13640,21 @@ "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==" }, + "tsyringe": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.6.0.tgz", + "integrity": "sha512-BMQAZamSfEmIQzH8WJeRu1yZGQbPSDuI9g+yEiKZFIcO46GPZuMOC2d0b52cVBdw1d++06JnDSIIZvEnogMdAw==", + "requires": { + "tslib": "^1.9.3" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -12389,8 +13783,7 @@ "uglify-js": { "version": "3.14.3", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.3.tgz", - "integrity": "sha512-mic3aOdiq01DuSVx0TseaEzMIVqebMZ0Z3vaeDhFEh9bsc24hV1TFvN74reA2vs08D0ZWfNjAcJ3UbVLaBss+g==", - "optional": true + "integrity": "sha512-mic3aOdiq01DuSVx0TseaEzMIVqebMZ0Z3vaeDhFEh9bsc24hV1TFvN74reA2vs08D0ZWfNjAcJ3UbVLaBss+g==" }, "unbox-primitive": { "version": "1.0.1", @@ -12450,6 +13843,11 @@ "xdg-basedir": "^4.0.0" } }, + "upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=" + }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -12489,6 +13887,11 @@ "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, + "valid-data-url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/valid-data-url/-/valid-data-url-3.0.1.tgz", + "integrity": "sha512-jOWVmzVceKlVVdwjNSenT4PbGghU0SBIizAev8ofZVgivk/TVHXSbNL8LP6M3spZvkR9/QolkyJavGSX5Cs0UA==" + }, "validator": { "version": "13.7.0", "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", @@ -12499,6 +13902,50 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, + "web-resource-inliner": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/web-resource-inliner/-/web-resource-inliner-5.0.0.tgz", + "integrity": "sha512-AIihwH+ZmdHfkJm7BjSXiEClVt4zUFqX4YlFAzjL13wLtDuUneSaFvDBTbdYRecs35SiU7iNKbMnN+++wVfb6A==", + "requires": { + "ansi-colors": "^4.1.1", + "escape-goat": "^3.0.0", + "htmlparser2": "^4.0.0", + "mime": "^2.4.6", + "node-fetch": "^2.6.0", + "valid-data-url": "^3.0.0" + }, + "dependencies": { + "domhandler": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", + "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", + "requires": { + "domelementtype": "^2.0.1" + } + }, + "escape-goat": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-3.0.0.tgz", + "integrity": "sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==" + }, + "htmlparser2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz", + "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^3.0.0", + "domutils": "^2.0.0", + "entities": "^2.0.0" + } + }, + "mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==" + } + } + }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -12723,12 +14170,6 @@ "is-plain-obj": "^2.1.0" } }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true - }, "yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 78888a85..d254f527 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "3.1.3", "private": true, "scripts": { - "start": "DEBUG=hackboard:* NODE_ENV=test rimraf dist/ && tsc && cp .env ./dist/.env && nodemon --ignore gcp_creds.json ./dist/app.js", + "start": "DEBUG=hackboard:* NODE_ENV=test rimraf dist/ && tsc && cp .env ./dist/.env && cp -R assets/ ./dist/assets && nodemon --ignore gcp_creds.json ./dist/app.js", "start-windows": "set DEBUG=hackboard:* && set NODE_ENV=test && nodemon --ignore gcp_creds.json ./bin/www.js", "deploy": "NODE_ENV=deployment node ./bin/www.js", "debug": "DEBUG=hackboard:* NODE_ENV=test nodemon --ignore gcp_creds.json ./bin/www.js", @@ -33,8 +33,10 @@ "handlebars": "^4.7.7", "jsonwebtoken": "^8.5.1", "memory-cache": "^0.2.0", + "mjml": "^4.11.0", "mongoose": "^5.13.3", "multer": "^1.4.2", + "nodemailer": "^6.7.2", "passport": "^0.4.1", "passport-local": "^1.0.0", "pg": "^8.7.1", @@ -52,9 +54,12 @@ "@types/express": "^4.17.13", "@types/express-winston": "^4.0.0", "@types/google-cloud__storage": "^1.7.2", + "@types/jsonwebtoken": "^8.5.6", + "@types/mjml": "^4.7.0", "@types/mongodb": "^3.6.20", "@types/mongoose": "^5.11.97", "@types/multer": "^1.4.7", + "@types/nodemailer": "^6.4.4", "@types/passport": "^1.0.7", "@types/passport-local": "^1.0.34", "@types/superagent": "^4.1.13", From 639a78f395b740e60154caccf86dff087d69a5ca Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Wed, 22 Dec 2021 20:05:12 -0500 Subject: [PATCH 09/72] feat: implement 90% of account related features. - remove old route, controller, and service files related to accounts/auth. - TODO: - remove ability to update password from the AccountService#update function. - implementing the resending of account confirmation logic on e-mail update. - invites: - implement the ability to send invites. - implement the ability to track who sent the invites. - automatic account confirmation logic - 100% of the work remains to be done here essentially. - NOTES: - we should maybe remove the ability to update the e-mail from the AccountService#update function as well. - maybe following an implementation similar to the password update flow would be better with a unique route and unique service function. - route controller function calls the updateEmail function in the service - route controller function also resends the mail and all the logic required there. --- controllers/account.controller.js | 81 ---- controllers/account.controller.ts | 54 ++- controllers/auth.controller.js | 55 --- controllers/authentication.controller.ts | 259 +++++++++- middlewares/account.middleware.js | 271 ----------- middlewares/auth.middleware.js | 574 ----------------------- routes/api/account.js | 305 ------------ routes/api/auth.js | 311 ------------ services/account-confirmation.service.ts | 73 +++ services/accountConfirmation.service.ts | 235 ---------- 10 files changed, 381 insertions(+), 1837 deletions(-) delete mode 100644 controllers/account.controller.js delete mode 100644 controllers/auth.controller.js delete mode 100644 middlewares/account.middleware.js delete mode 100644 middlewares/auth.middleware.js delete mode 100644 routes/api/account.js delete mode 100644 routes/api/auth.js create mode 100644 services/account-confirmation.service.ts delete mode 100644 services/accountConfirmation.service.ts diff --git a/controllers/account.controller.js b/controllers/account.controller.js deleted file mode 100644 index 0b891f46..00000000 --- a/controllers/account.controller.js +++ /dev/null @@ -1,81 +0,0 @@ -"use strict"; -const Services = { - Account: require("../services/account.service"), - Logger: require("../services/logger.service") -}; -const Util = require("../middlewares/util.middleware"); -const Constants = { - Error: require("../constants/error.constant"), - Success: require("../constants/success.constant") -}; - -/** - * @function showAccount - * @param {{body: {account: Object}}} req - * @param {*} res - * @return {JSON} Success status and account object - * @description Returns the JSON of account object located in req.body.account - */ -function showAccount(req, res) { - return res.status(200).json({ - message: Constants.Success.ACCOUNT_READ, - data: req.body.account.toStrippedJSON() - }); -} - -/** - * @function addUser - * @param {{body: {accountDetails: {_id: ObjectId, firstName: string, lastName: string, email: string, password: string}}}} req - * @param {*} res - * @return {JSON} Success or error status - * @description Adds a user from information in req.body.accountDetails - */ -function addUser(req, res) { - const acc = req.body.account; - return res.status(200).json({ - message: Constants.Success.ACCOUNT_CREATE, - data: acc.toStrippedJSON() - }); -} - -/** - * @function updatedAccount - * @param {{body: {Object}}} req - * @param {*} res - * @return {JSON} Success or error status - * @description - * Returns a 200 status for an updated account. - * The new account information is located in req.body. - * The id is moved to req.body.id from req.params.id by validation. - */ -function updatedAccount(req, res) { - delete req.body.account; - return res.status(200).json({ - message: Constants.Success.ACCOUNT_UPDATE, - data: req.body - }); -} - -function invitedAccount(req, res) { - return res.status(200).json({ - message: Constants.Success.ACCOUNT_INVITE, - data: {} - }); -} - -function gotInvites(req, res) { - return res.status(200).json({ - message: Constants.Success.ACCOUNT_GET_INVITES, - data: { - invites: req.body.invites - } - }); -} - -module.exports = { - addUser: addUser, - gotInvites: gotInvites, - updatedAccount: updatedAccount, - invitedAccount: invitedAccount, - showAccount: showAccount -}; diff --git a/controllers/account.controller.ts b/controllers/account.controller.ts index 3dd6a01a..f70282e6 100644 --- a/controllers/account.controller.ts +++ b/controllers/account.controller.ts @@ -16,11 +16,19 @@ import Account from "../models/account.model"; import { EnsureAuthenticated } from "../middlewares/authenticated.middleware"; import { EnsureAuthorization } from "../middlewares/authorization.middleware"; import { AuthorizationLevel } from "../constants/authorization-level.constant"; +import { AccountConfirmationService } from "../services/account-confirmation.service"; +import { EmailService } from "../services/email.service"; +import * as GeneralConstants from "../constants/general.constant"; +import { join } from "path"; @autoInjectable() @Controller("/account") export class AccountController { - constructor(private readonly accountService: AccountService) {} + constructor( + private readonly accountService: AccountService, + private readonly accountConfirmationService: AccountConfirmationService, + private readonly mailer: EmailService + ) {} @Get("/", [ EnsureAuthenticated, @@ -79,12 +87,48 @@ export class AccountController { ) { const result: Account = await this.accountService.save(account); + if (result) { + const model = await this.accountConfirmationService.save({ + accountType: GeneralConstants.HACKER, + email: result.email, + confirmationType: GeneralConstants.CONFIRMATION_TYPE_ORGANIC, + account: result + }); + + await this.mailer.send( + { + to: model.email, + subject: "Account Confirmation Instructions", + html: join( + __dirname, + "../assets/email/AccountConfirmation.mjml" + ) + }, + { + link: this.accountConfirmationService.generateLink( + "confirm", + this.accountConfirmationService.generateToken( + model.identifier, + model.account!.identifier + ) + ) + }, + (error?: any) => { + if (error) + response.status(500).send({ + message: ErrorConstants.EMAIL_500_MESSAGE, + data: error + }); + } + ); + } + return result - ? response.status(200).json({ + ? response.status(200).send({ message: SuccessConstants.ACCOUNT_CREATE, data: result }) - : response.status(422).json({ + : response.status(422).send({ message: ErrorConstants.ACCOUNT_DUPLICATE_422_MESSAGE }); } @@ -103,6 +147,7 @@ export class AccountController { @Body() update: Partial ) { //TODO - Implement resend e-mail confirmation and verification. + //TODO - A thrifty user can update their password from here and it would not be hashed, we should attempt to block. const result = await this.accountService.update(identifier, update); return result @@ -119,4 +164,7 @@ export class AccountController { } //TODO - Implement (gotInvites, invitedAccount) + // Invite functionality requires a special account confirmation token change where we verify if the token is valid + // without the account field, this was in the previous code (middleware files) + // to reimpl this functionality we should reference there. } diff --git a/controllers/auth.controller.js b/controllers/auth.controller.js deleted file mode 100644 index 885275bd..00000000 --- a/controllers/auth.controller.js +++ /dev/null @@ -1,55 +0,0 @@ -"use strict"; - -const Success = require("../constants/success.constant"); - -module.exports = { - onSuccessfulLogin: function(req, res) { - return res.status(200).json({ - message: Success.AUTH_LOGIN, - data: {} - }); - }, - logout: function(req, res) { - req.logout(); - return res.status(200).json({ - message: Success.AUTH_LOGOUT, - data: {} - }); - }, - sentResetEmail: function(req, res) { - return res.status(200).json({ - message: Success.AUTH_SEND_RESET_EMAIL, - data: {} - }); - }, - resetPassword: function(req, res) { - return res.status(200).json({ - message: Success.AUTH_RESET_PASSWORD, - data: {} - }); - }, - confirmAccount: function(req, res) { - return res.status(200).json({ - message: Success.AUTH_CONFIRM_ACCOUNT, - data: {} - }); - }, - retrieveRoleBindings: function(req, res) { - return res.status(200).json({ - message: Success.AUTH_GET_ROLE_BINDINGS, - data: req.roleBindings.toJSON() - }); - }, - sentConfirmationEmail: function(req, res) { - return res.status(200).json({ - message: Success.AUTH_SEND_CONFIRMATION_EMAIL, - data: {} - }); - }, - retrievedRoles: function(req, res) { - return res.status(200).json({ - message: Success.AUTH_GET_ROLES, - data: req.roles - }); - } -}; diff --git a/controllers/authentication.controller.ts b/controllers/authentication.controller.ts index 6f1ef651..a765cee0 100644 --- a/controllers/authentication.controller.ts +++ b/controllers/authentication.controller.ts @@ -1,4 +1,14 @@ -import { Controller, Post, Request, Response } from "@decorators/express"; +import { + Body, + Controller, + Get, + Headers, + Params, + Patch, + Post, + Request, + Response +} from "@decorators/express"; import { autoInjectable } from "tsyringe"; import { Request as ExpressRequest, @@ -9,11 +19,30 @@ import passport from "passport"; import Account from "../models/account.model"; import * as ErrorConstants from "../constants/error.constant"; import * as SuccessConstants from "../constants/success.constant"; +import { EnsureAuthenticated } from "../middlewares/authenticated.middleware"; +import { PasswordResetService } from "../services/password-reset.service"; +import { AccountService } from "../services/account.service"; +import PasswordReset from "../models/passwordResetToken.model"; +import { EmailService } from "../services/email.service"; +import { join } from "path"; +import jwt from "jsonwebtoken"; +import { EnvService } from "../services/env.service"; +import { AccountConfirmationService } from "../services/account-confirmation.service"; +import AccountConfirmation from "../models/accountConfirmationToken.model"; +import { EnsureAuthorization } from "../middlewares/authorization.middleware"; +import { AuthorizationLevel } from "../constants/authorization-level.constant"; @autoInjectable() @Controller("/authentication") export class AuthenticationController { - constructor(private readonly strategy: EmailAndPasswordStrategy) {} + constructor( + private readonly strategy: EmailAndPasswordStrategy, + private readonly accountService: AccountService, + private readonly passwordResetService: PasswordResetService, + private readonly accountConfirmationService: AccountConfirmationService, + private readonly mailer: EmailService, + private readonly envService: EnvService + ) {} @Post("/sign-in") async signIn( @@ -47,4 +76,230 @@ export class AuthenticationController { }); })(request, response); } + + @Get("/sign-out", [EnsureAuthenticated]) + signOut( + @Request() request: ExpressRequest, + @Response() response: ExpressResponse + ) { + request.logout(); + + return response.status(200).json({ + message: SuccessConstants.AUTH_LOGOUT, + data: {} + }); + } + + @Post("/password/forgot") + async forgotPassword( + @Response() response: ExpressResponse, + @Body("email") email: string + ) { + const account: + | Account + | undefined = await this.accountService.findByEmail(email); + + if (account) { + const model: PasswordReset = await this.passwordResetService.save( + account + ); + await this.mailer.send( + { + to: email, + subject: "Password Reset Instructions", + html: join(__dirname, "../assets/email/ResetPassword.mjml") + }, + { + link: this.passwordResetService.generateLink( + "password/forgot", + this.passwordResetService.generateToken( + model.identifier, + model.account.identifier + ) + ) + }, + (error?: any) => { + if (error) + response.status(500).send({ + message: ErrorConstants.EMAIL_500_MESSAGE, + data: error + }); + else + response.status(200).send({ + message: SuccessConstants.AUTH_SEND_RESET_EMAIL, + data: {} + }); + } + ); + } + } + + @Post("/password/reset") + async resetPassword( + @Response() response: ExpressResponse, + @Headers("X-Reset-Token") token: string, + @Body("password") password: string + ) { + // Check if the JWT is valid and provide deconstructed object of identifier and account identiifer. + const data = jwt.verify( + token, + this.envService.get("JWT_RESET_PWD_SECRET")! + ) as { + identifier: number; + }; + + const model = await this.passwordResetService.findByIdentifier( + data.identifier + ); + + if (model) { + await this.accountService.updatePassword( + model.account.identifier, + password + ); + await this.passwordResetService.delete(model.identifier); + + response.status(200).send({ + message: SuccessConstants.AUTH_RESET_PASSWORD, + data: {} + }); + } else { + // Either the token was already used, it's invalid, or user does not exist. + response.status(401).send({ + message: ErrorConstants.ACCOUNT_TOKEN_401_MESSAGE, + error: {} + }); + } + } + + @Patch("/password/change", [ + EnsureAuthenticated, + EnsureAuthorization([AuthorizationLevel.Account]) + ]) + async changePassword( + @Request() request: ExpressRequest, + @Response() response: ExpressResponse, + @Body("oldPassword") oldPassword: string, + @Body("newPassword") newPassword: string + ) { + const account = await this.accountService.getAccountIfValid( + //@ts-ignore + request.user?.email, + oldPassword + ); + + // If the user's old password is correct. + if (account) { + await this.accountService.updatePassword( + account.identifier, + newPassword + ); + response.status(200).send({ + message: SuccessConstants.AUTH_RESET_PASSWORD, + data: {} + }); + } + response.status(401).send({ + message: ErrorConstants.AUTH_401_MESSAGE + }); + } + + @Get("/confirm/resend", [EnsureAuthenticated]) + async resendAccountConfirmation( + @Request() request: ExpressRequest, + @Response() response: ExpressResponse + ) { + // We use the non-null asseration opearator as we are sure that the user exists befure of the EnsureAuthenticated middleware. + const account: Account = (await this.accountService.findByIdentifier( + //@ts-ignore + request.user?.identifier + ))!; + + if (account.confirmed) + response.status(422).send({ + message: "Account already confirmed" + }); + + const model: + | AccountConfirmation + | undefined = await this.accountConfirmationService.findByAccount( + account.identifier + ); + + if (!model) + response.status(428).send({ + message: "Account confirmation token does not exist" + }); + + await this.mailer.send( + { + to: account.email, + subject: "Account Confirmation Instructions", + html: join( + __dirname, + "../assets/email/AccountConfirmation.mjml" + ) + }, + { + link: this.accountConfirmationService.generateLink( + "confirm", + this.accountConfirmationService.generateToken( + model!.identifier, + account.identifier + ) + ) + }, + (error?: any) => { + if (error) + response.status(500).send({ + message: ErrorConstants.EMAIL_500_MESSAGE, + data: error + }); + } + ); + + response.status(200).send({ + message: SuccessConstants.AUTH_SEND_CONFIRMATION_EMAIL, + data: {} + }); + } + + @Post("/confirm/:token") + async confirmAccount( + @Response() response: ExpressResponse, + @Params("token") token: string + ) { + // Check if the JWT is valid and provide deconstructed object of identifier and account identiifer. + const data = jwt.verify( + token, + this.envService.get("JWT_CONFIRM_ACC_SECRET")! + ) as { + identifier: number; + account: number; + }; + + const model = await this.accountConfirmationService.findByIdentifier( + data.identifier + ); + + if (model) { + // TODO - Check this to ensure no security vuln - Could the JWT Token be modified in some way. + // A better approach might be storing a digest (hash) of a randomly generated token using crypto. + await this.accountService.update(data.account, { + confirmed: true + }); + await this.accountConfirmationService.delete(model.identifier); + + response.status(200).send({ + message: SuccessConstants.AUTH_CONFIRM_ACCOUNT, + data: {} + }); + } else { + // Either the token was already used, it's invalid, or user does not exist. + response.status(401).send({ + message: ErrorConstants.ACCOUNT_TOKEN_401_MESSAGE, + error: {} + }); + } + } } diff --git a/middlewares/account.middleware.js b/middlewares/account.middleware.js deleted file mode 100644 index a39751be..00000000 --- a/middlewares/account.middleware.js +++ /dev/null @@ -1,271 +0,0 @@ -"use strict"; - -const TAG = `[ ADDRESS.MIDDLEWARE.js ]`; -const Services = { - RoleBinding: require("../services/roleBinding.service"), - Logger: require("../services/logger.service"), - Account: require("../services/account.service"), - AccountConfirmation: require("../services/accountConfirmation.service"), - Email: require("../services/email.service"), - Env: require("../services/env.service") -}; - -const Middleware = { - Util: require("../middlewares/util.middleware") -}; - -const Constants = { - Error: require("../constants/error.constant"), - General: require("../constants/general.constant") -}; - -/** - * @function parsePatch - * @param {body: {id: ObjectId}} req - * @param {*} res - * @param {(err?) => void} next - * @return {void} - * @description Delete the req.body.id that was added by the validation of route parameter. - */ -function parsePatch(req, res, next) { - delete req.body.identifier; - return next(); -} - -/** - * @function parseAccount - * @param {{body: {firstName: string, lastName: string, email: string, password: string}}} req - * @param {*} res - * @param {(err?)=>void} next - * @return {void} - * @description - * Moves firstName, lastName, email, password from req.body to req.body.accountDetails. - * Hashes the password. - * Adds _id to accountDetails. - */ -function parseAccount(req, res, next) { - const accountDetails = { - _id: req.body.identifier, - firstName: req.body.firstName, - lastName: req.body.lastName, - pronoun: req.body.pronoun, - gender: req.body.gender, - email: req.body.email, - password: Services.Account.hashPassword(req.body.password), - dietaryRestrictions: req.body.dietaryRestrictions, - gender: req.body.gender, - birthDate: req.body.birthDate, - phoneNumber: req.body.phoneNumber - }; - - delete req.body.firstName; - delete req.body.lastName; - delete req.body.pronoun; - delete req.body.gender; - delete req.body.email; - delete req.body.password; - delete req.body.dietaryRestrictions; - delete req.body.gender; - delete req.body.birthDate; - delete req.body.phoneNumber; - - req.body.accountDetails = accountDetails; - return next(); -} - -/** - * Middleware that updates the password for the current user - * @param {{body: {password: string}}} req - * @param {*} res - * @param {(err?)=>void} next - */ -async function updatePassword(req, res, next) { - req.body.account = await Services.Account.updatePassword( - req.body.decodedToken.accountId, - req.body.password - ); - return next(); -} - -/** - * @async - * @function getById - * @param {{body: {id: string}}} req - * @param {*} res - * @description Retrieves an account's information from mongoId specified in req.body.id, and places it in req.body.account - */ -async function getById(req, res, next) { - const acc = await Services.Account.findById(req.body.identifier); - - if (!acc) { - return next({ - status: 404, - message: Constants.Error.ACCOUNT_404_MESSAGE - }); - } - - req.body.account = acc; - return next(); -} - -/** - * @async - * @function getByEmail - * @param {{user: {email: string}}} req - * @param {*} res - * @description Gets an account by user email, and sets req.body.acc to the retrived account object if successful. - */ -async function getByEmail(req, res, next) { - const acc = await Services.Account.findByEmail(req.user.email); - - if (!acc) { - return next({ - status: 404, - message: Constants.Error.ACCOUNT_404_MESSAGE - }); - } - - req.body.account = acc; - next(); -} - -/** - * @function addAccount - * @param {{body: {accountDetails: object}}} req - * @param {*} res - * @param {(err?)=>void} next - * @return {void} - * @description - * Creates account document after checking if it exists first - */ -async function addAccount(req, res, next) { - const accountDetails = req.body.accountDetails; - //Check duplicate - const exists = await Services.Account.findByEmail(accountDetails.email); - if (exists) { - return next({ - status: 422, - message: Constants.Error.ACCOUNT_DUPLICATE_422_MESSAGE, - error: { - route: req.path - } - }); - } - const account = await Services.Account.addOneAccount(accountDetails); - req.body.account = account; - return next(); -} - -/** - * Updates an account that is specified by req.params.id - * @param {{params:{id: string}, body: *}} req - * @param {*} res - * @param {*} next - */ -async function updateAccount(req, res, next) { - var account = await Services.Account.findById(req.params.id); - - // If we are changing the email, and there is a difference between the two, set back to unconfirmed status. - // TODO: When pull request for parse patch refactor #546 hits, req.body.email will not be present. - if (req.body.email && account.email != req.body.email) { - const existingAccount = await Services.Account.findByEmail( - req.body.email - ); - if (existingAccount) { - return next({ - status: 409, - message: Constants.Error.ACCOUNT_EMAIL_409_MESSAGE - }); - } else { - req.body.confirmed = false; - } - } - - req.body.account = await Services.Account.updateOne( - req.params.id, - req.body - ); - - if (req.body.account) { - return next(); - } else { - return next({ - status: 404, - message: Constants.Error.ACCOUNT_404_MESSAGE, - data: { - id: req.params.id - } - }); - } -} - -/** - * @function inviteAccount - * @param {{body: {email: string, accountType: string}}} req - * @param {*} res - * @param {(err?)=>void} next - * @return {void} - * Creates email to provide a link for the user to create an account - */ -async function inviteAccount(req, res, next) { - const email = req.body.email; - const accountType = req.body.accountType; - const confirmationObj = await Services.AccountConfirmation.create( - accountType, - email, - Constants.General.CONFIRMATION_TYPE_INVITE - ); - const confirmationToken = Services.AccountConfirmation.generateToken( - confirmationObj.id - ); - const address = Services.Env.isProduction() - ? process.env.FRONTEND_ADDRESS_DEPLOY - : process.env.FRONTEND_ADDRESS_DEV; - - const mailData = Services.AccountConfirmation.generateAccountInvitationEmail( - address, - email, - accountType, - confirmationToken - ); - if (mailData !== undefined) { - Services.Email.send(mailData, (err) => { - if (err) { - next(err); - } else { - next(); - } - }); - } else { - return next({ - message: Constants.Error.EMAIL_500_MESSAGE - }); - } -} -/** - * Gets all of the invites in the database and adds it to req.body. - * @param {{}} req - * @param {*} res - * @param {(err?)=>void} next - */ -async function getInvites(req, res, next) { - const invites = await Services.AccountConfirmation.find({ - confirmationType: Constants.General.CONFIRMATION_TYPE_INVITE - }); - req.body.invites = invites; - next(); -} - -module.exports = { - parsePatch: parsePatch, - parseAccount: parseAccount, - // untested - getInvites: Middleware.Util.asyncMiddleware(getInvites), - getByEmail: Middleware.Util.asyncMiddleware(getByEmail), - getById: Middleware.Util.asyncMiddleware(getById), - // untested - updatePassword: Middleware.Util.asyncMiddleware(updatePassword), - addAccount: Middleware.Util.asyncMiddleware(addAccount), - updateAccount: Middleware.Util.asyncMiddleware(updateAccount), - inviteAccount: Middleware.Util.asyncMiddleware(inviteAccount) -}; diff --git a/middlewares/auth.middleware.js b/middlewares/auth.middleware.js deleted file mode 100644 index 3231a0f2..00000000 --- a/middlewares/auth.middleware.js +++ /dev/null @@ -1,574 +0,0 @@ -"use strict"; -const jwt = require("jsonwebtoken"); -const passport = require("passport"); - -const Services = { - Auth: require("../services/auth.service"), - ResetPasswordToken: require("../services/resetPassword.service"), - Account: require("../services/account.service"), - Email: require("../services/email.service"), - AccountConfirmation: require("../services/accountConfirmation.service"), - Role: require("../services/role.service"), - RoleBinding: require("../services/roleBinding.service"), - Env: require("../services/env.service") -}; - -const Middleware = { - Util: require("./util.middleware") -}; - -const Constants = { - General: require("../constants/general.constant"), - Error: require("../constants/error.constant"), - Role: require("../constants/role.constant") -}; - -/** - * @param {*} req - * @param {*} res - * @param {(err?)=>void} next - * Calls passport.authenticate with a custom error handler. Errors during authentication will return res with a generic 500 error, - * Failed authentication returns a AUTH 401 error, and errors during login will return res with a LOGIN 500 error. - */ -function login(req, res, next) { - passport.authenticate(Services.Auth.emailAndPassStrategy, function(err, user) { - if (err) { - return next({ - status: 500, - message: Constants.Error.GENERIC_500_MESSAGE, - error: {} - }); - } - if (!user) { - return next({ - status: 401, - message: Constants.Error.AUTH_401_MESSAGE, - error: {} - }); - } - req.login(user, (loginErr) => { - if (loginErr) { - return next({ - status: 500, - message: Constants.Error.LOGIN_500_MESSAGE, - error: {} - }); - } - return next(); - }); - })(req, res, next); -} - -/** - * @returns {Fn} the middleware that will check that the user is properly authenticated. - * Calls next() if the user is properly authenticated. - */ -function ensureAuthenticated() { - return function(req, res, next) { - if (req.isUnauthenticated()) { - return next({ - status: 401, - message: Constants.Error.AUTH_401_MESSAGE, - error: { - route: req.path - } - }); - } else { - return next(); - } - }; -} - -/** - * @param {((paramId) => {Account})[]} findByIdFns the request object - * @returns {Fn} the middleware that will check that the user is properly authorized. - * Calls next() if the user is properly authorized. - */ -function ensureAuthorized(findByIdFns) { - return function(req, res, next) { - Services.Auth.ensureAuthorized(req, findByIdFns).then( - (auth) => { - if (!auth) { - return next({ - status: 403, - message: Constants.Error.AUTH_403_MESSAGE, - error: { - route: req.path - } - }); - } else { - return next(); - } - }, - (err) => { - return next(err); - } - ); - }; -} - -/** - * Middleware which retrieves the rolebindings for an account - * @param {{body: {param: {id:string}}}} req - * @param {*} res - * @param {(err?)=>void} next - */ -async function retrieveRoleBindings(req, res, next) { - const roleBindings = await Services.RoleBinding.getRoleBindingForAcct( - req.params.id - ); - if (!roleBindings) { - return next({ - status: 404, - message: "Role Bindings not found" - }); - } - req.roleBindings = roleBindings; - return next(); -} - -/** - * Checks that the oldPassword is the current password for the logged in user. If the password is correct, - * then updates the password to the string in newPassword. - * @param {{user: {email: string}, body: {oldPassword: string, newPassword: string}} req - * @param {*} res - * @param {*} next - */ -async function changePassword(req, res, next) { - const acc = await Services.Account.getAccountIfValid( - req.user.email, - req.body.oldPassword - ); - // user's old password is correct - if (!!acc) { - req.body.account = await Services.Account.updatePassword( - req.user.id, - req.body.newPassword - ); - return next(); - } else { - return next({ - status: 401, - message: Constants.Error.AUTH_401_MESSAGE - }); - } -} - -/** - * Middleware that sends an email to reset the password for the inputted email address. - * @param {{body: {email:String}}} req the request object - * @param {*} res - * @param {(err?)=>void} next - */ -async function sendResetPasswordEmailMiddleware(req, res, next) { - const user = await Services.Account.findByEmail(req.body.email); - if (user) { - //create the reset password token - await Services.ResetPasswordToken.create(user.id); - //find the thing we just created - const ResetPasswordTokenModel = await Services.ResetPasswordToken.findByAccountId( - user.id - ); - //generate email - const token = Services.ResetPasswordToken.generateToken( - ResetPasswordTokenModel.id, - user.id - ); - const address = Services.Env.isProduction() - ? process.env.FRONTEND_ADDRESS_DEPLOY - : process.env.FRONTEND_ADDRESS_DEV; - const mailData = Services.ResetPasswordToken.generateResetPasswordEmail( - address, - req.body.email, - token - ); - if (mailData !== undefined) { - Services.Email.send(mailData, (err) => { - if (err) { - return next(err); - } else { - return next(); - } - }); - } else { - return next({ - message: Constants.Error.EMAIL_500_MESSAGE - }); - } - } else { - //Didn't find the user, but we don't want to throw an error because someone might be trying to see who has an account. - return next(); - } -} - -/** - * Middleware that sends an email to confirm the account for the inputted email address. - * This is only sent on account creation for HACKERS as other users are sent an invite email - * which confirms their account, if a user is another type they should be confirmed so an email is not - * @param {{body: {email:String}}} req the request object - * @param {*} res - * @param {(err?)=>void} next - */ -async function sendConfirmAccountEmail(req, res, next) { - const account = req.body.account; - if (account.confirmed) { - return next(); - } - await Services.AccountConfirmation.create( - Constants.General.HACKER, - account.email, - Constants.General.CONFIRMATION_TYPE_ORGANIC, - account.id - ); - const accountConfirmationToken = await Services.AccountConfirmation.findByAccountId( - account.id - ); - const token = Services.AccountConfirmation.generateToken( - accountConfirmationToken.id, - account.id - ); - const address = Services.Env.isProduction() - ? process.env.FRONTEND_ADDRESS_DEPLOY - : process.env.FRONTEND_ADDRESS_DEV; - const mailData = Services.AccountConfirmation.generateAccountConfirmationEmail( - address, - account.email, - Constants.General.HACKER, - token - ); - if (mailData !== undefined) { - Services.Email.send(mailData, (err) => { - if (err) { - return next(err); - } else { - return next(); - } - }); - } else { - return next({ - message: Constants.Error.EMAIL_500_MESSAGE - }); - } -} - -/** - * Middleware that resends an email to confirm the account for the inputted email address. - * @param {{user {id : String}}} req the request object - * @param {*} res - * @param {(err?)=>void} next - */ -async function resendConfirmAccountEmail(req, res, next) { - const account = await Services.Account.findById(req.user.id); - if (account.confirmed) { - return next({ - status: 422, - message: "Account already confirmed" - }); - } - const accountConfirmationToken = await Services.AccountConfirmation.findByAccountId( - account.id - ); - if (!accountConfirmationToken) { - return next({ - status: 428, - message: "Account confirmation token does not exist" - }); - } - const token = Services.AccountConfirmation.generateToken( - accountConfirmationToken.id, - account.id - ); - const address = Services.Env.isProduction() - ? process.env.FRONTEND_ADDRESS_DEPLOY - : process.env.FRONTEND_ADDRESS_DEV; - const mailData = Services.AccountConfirmation.generateAccountConfirmationEmail( - address, - account.email, - accountConfirmationToken.accountType, - token - ); - if (mailData !== undefined) { - Services.Email.send(mailData, (err) => { - if (err) { - return next(err); - } else { - return next(); - } - }); - } else { - return next({ - message: "Error while generating email" - }); - } -} - -/** - * Attempts to parse the jwt token that is found in req.body.token using process.env.JWT_RESET_PWD_SECRET as the key. - * Places the parsed object into req.body.decodedToken. - * @param {{body:{token:string}}} req - * @param {any} res - * @param {(err?)=>void} next - */ -function parseResetToken(req, res, next) { - jwt.verify( - req.body["x-reset-token"], - process.env.JWT_RESET_PWD_SECRET, - function(err, decoded) { - if (err) { - return next(err); - } else { - req.body.decodedToken = decoded; - return next(); - } - } - ); -} - -/** - * Attempts to parse the jwt token that is found in req.body.token using process.env.JWT_CONFIRM_ACC_SECRET as the key. - * Places the parsed object into req.body.decodedToken - * If the token does not exist it just continues flow - * @param {{body:{token:string}}} req - * @param {any} res - * @param {(err?)=>void} next - */ -function parseAccountConfirmationToken(req, res, next) { - if (!!req.body.token) { - jwt.verify(req.body.token, process.env.JWT_CONFIRM_ACC_SECRET, function( - err, - decoded - ) { - if (err) { - return next(err); - } else { - req.body.decodedToken = decoded; - } - }); - } - return next(); -} - -/** - * Returns the type of account based on the confirmation token - * @param {{body:{decodedToken:{accountConfirmationId:string, accountId:string}}}} req - * @param {any} res - * @param {(err?)=>void} next - */ -async function getAccountTypeFromConfirmationToken(req, res, next) { - const confirmationObj = await Services.AccountConfirmation.findById( - req.body.decodedToken.accountConfirmationId - ); - if (confirmationObj) { - req.body.accountType = confirmationObj.accountType; - return next(); - } else { - //Either the token was already used, it's invalid, or user does not exist. - return next({ - status: 401, - message: Constants.Error.ACCOUNT_TOKEN_401_MESSAGE, - error: {} - }); - } -} - -/** - * Verifies that the resetId exists, and that the accountId exists. - * @param {{body:{decodedToken:{resetId:string, accountId:string}}}} req - * @param {any} res - * @param {(err?)=>void} next - */ -async function validateResetToken(req, res, next) { - const resetObj = await Services.ResetPasswordToken.findById( - req.body.decodedToken.resetId - ); - const userObj = await Services.Account.findById( - req.body.decodedToken.accountId - ); - if (resetObj && userObj) { - req.body.user = userObj; - return next(); - } else { - //Either the token was already used, it's invalid, or user does not exist. - return next({ - status: 401, - message: Constants.Error.ACCOUNT_TOKEN_401_MESSAGE, - error: {} - }); - } -} - -/** - * Verifies that the confirm account exists, and that the accountId exists. - * @param {{body:{decodedToken:{accountConfirmationId: String, accountId: String}}}} req - * @param {any} res - * @param {(err?)=>void} next - */ -async function validateConfirmationToken(req, res, next) { - const confirmationObj = await Services.AccountConfirmation.findById( - req.body.decodedToken.accountConfirmationId - ); - const userObj = await Services.Account.findById( - req.body.decodedToken.accountId - ); - if (confirmationObj && userObj && confirmationObj.accountId == userObj.id) { - userObj.confirmed = true; - userObj.accountType = confirmationObj.accountType; - await Services.Account.updateOne(confirmationObj.accountId, userObj); - req.body.user = userObj; - return next(); - } else { - //Either the token was already used, it's invalid, or user does not exist. - return next({ - status: 401, - message: Constants.Error.ACCOUNT_TOKEN_401_MESSAGE, - error: {} - }); - } -} - -/** - * Finds the confirmation token for this account. If there is no account ID associated with this - * confirmation token, then the user was invited. Therefore, we should set the confirmation bit to - * true by default (since they were invited). - * @param {body: {decodedToken:{accountConfirmationId: String}}} req - * @param {*} res - * @param {*} next - */ -async function validateConfirmationTokenWithoutAccount(req, res, next) { - if (req.body.decodedToken) { - const confirmationObj = await Services.AccountConfirmation.findById( - req.body.decodedToken.accountConfirmationId - ); - if (!confirmationObj.accountId) { - req.body.accountDetails.confirmed = true; - req.body.accountDetails.accountType = confirmationObj.accountType; - } - } - return next(); -} - -/** - * Middleware that deletes the reset token in the db - * @param {{body: {decodedToken:{resetId:String}}}} req the request object - * @param {*} res - * @param {(err?)=>void} next - */ -function deleteResetToken(req, res, next) { - Services.ResetPasswordToken.deleteToken(req.body.decodedToken.resetId).then( - () => { - return next(); - }, - (err) => { - return next(err); - } - ); -} - -/** - * Middleware that creates rolebinding to access POST route for respective account - * @param {{body: {account:{accountType:String, id: ObjectId}}}} req the request object - * @param {*} res - * @param {(err?)=>void} next - */ -async function addCreationRoleBindings(req, res, next) { - if (req.body.account.accountType === Constants.General.STAFF) { - // Staff do not have to create a STAFF object, so give them the full permissions immediately. - await Services.RoleBinding.createRoleBindingByRoleName( - req.body.account.id, - Constants.Role.adminRole.name - ); - } else { - // Get the default role for the account type given - const roleName = - Constants.General.POST_ROLES[req.body.account.accountType]; - await Services.RoleBinding.createRoleBindingByRoleName( - req.body.account.id, - roleName - ); - // Add default account role bindings - await Services.RoleBinding.createRoleBindingByRoleName( - req.body.account.id, - Constants.Role.accountRole.name - ); - } - return next(); -} - -/** - * Adds proper account rolebindings on account creation - * @param {string} roleName name of the role to be added to account - */ -function createRoleBindings(roleName = undefined) { - return Middleware.Util.asyncMiddleware(async (req, res, next) => { - await Services.RoleBinding.createRoleBindingByRoleName( - req.user.id, - roleName - ); - return next(); - }); -} - -/** - * Adds a rolebinding between the user and the role with the name stored in 'accountType'. - * @param {{user: {id: ObjectId, accountType: string}}} req - * @param {*} res - * @param {(err?) => void} next - */ -async function addAccountTypeRoleBinding(req, res, next) { - await Services.RoleBinding.createRoleBindingByRoleName( - req.user.id, - req.user.accountType - ); - return next(); -} - -/** - * Middleware to retrieve all the roles in the database - * @param {*} req - * @param {*} res - * @param {(err?) => void } next - */ -async function retrieveRoles(req, res, next) { - const roles = await Services.Role.getAll(); - req.roles = roles; - return next(); -} - -module.exports = { - //for each route, set up an authentication middleware for that route - login: login, - ensureAuthenticated: ensureAuthenticated, - ensureAuthorized: ensureAuthorized, - sendResetPasswordEmailMiddleware: Middleware.Util.asyncMiddleware( - sendResetPasswordEmailMiddleware - ), - parseResetToken: parseResetToken, - validateResetToken: Middleware.Util.asyncMiddleware(validateResetToken), - deleteResetToken: deleteResetToken, - sendConfirmAccountEmail: Middleware.Util.asyncMiddleware( - sendConfirmAccountEmail - ), - parseAccountConfirmationToken: parseAccountConfirmationToken, - validateConfirmationToken: Middleware.Util.asyncMiddleware( - validateConfirmationToken - ), - getAccountTypeFromConfirmationToken: Middleware.Util.asyncMiddleware( - getAccountTypeFromConfirmationToken - ), - validateConfirmationTokenWithoutAccount: Middleware.Util.asyncMiddleware( - validateConfirmationTokenWithoutAccount - ), - createRoleBindings: createRoleBindings, - addAccountTypeRoleBinding: Middleware.Util.asyncMiddleware( - addAccountTypeRoleBinding - ), - addCreationRoleBindings: Middleware.Util.asyncMiddleware( - addCreationRoleBindings - ), - resendConfirmAccountEmail: Middleware.Util.asyncMiddleware( - resendConfirmAccountEmail - ), - retrieveRoleBindings: Middleware.Util.asyncMiddleware(retrieveRoleBindings), - retrieveRoles: Middleware.Util.asyncMiddleware(retrieveRoles), - changePassword: Middleware.Util.asyncMiddleware(changePassword) -}; diff --git a/routes/api/account.js b/routes/api/account.js deleted file mode 100644 index 7a41dbea..00000000 --- a/routes/api/account.js +++ /dev/null @@ -1,305 +0,0 @@ -"use strict"; - -const express = require("express"); -const Controllers = { - Account: require("../../controllers/account.controller") -}; -const Middleware = { - Validator: { - /* Insert the require statement to the validator file here */ - Account: require("../../middlewares/validators/account.validator"), - RouteParam: require("../../middlewares/validators/routeParam.validator"), - Auth: require("../../middlewares/validators/auth.validator") - }, - /* Insert all of ther middleware require statements here */ - parseBody: require("../../middlewares/parse-body.middleware"), - Account: require("../../middlewares/account.middleware"), - Auth: require("../../middlewares/auth.middleware") -}; -const Services = { - Account: require("../../services/account.service") -}; - -module.exports = { - activate: function(apiRouter) { - const accountRouter = express.Router(); - - /** - * @api {get} /account/self get information about own account - * @apiName self - * @apiGroup Account - * @apiVersion 0.0.8 - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data Account object - * @apiSuccessExample {object} Success-Response: - * { - "message": "Account found by user email", - "data": { - "id": ObjectId("5bff8b9f3274cf001bc71048"), - "firstName": "Theo", - "lastName":"Klein", - "pronoun":"he/him", - "email":"theo@klein.com", - "phoneNumber":1234567890, - "gender":"Male", - "birthDate":Date("10/30/1997") - } - } - * @apiError {string} message Error message - * @apiError {object} data empty object - * @apiErrorExample {object} Error-Response: - * {"message": "Account not found", "data": {}} - */ - accountRouter.route("/self").get( - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized(), - - Middleware.Account.getByEmail, - Controllers.Account.showAccount - ); - - /** - * @api {post} /account/ create a new account - * @apiName create - * @apiGroup Account - * @apiVersion 0.0.8 - * - * @apiParam (body) {String} firstName First name of the account creator. - * @apiParam (body) {String} lastName Last name of the account creator. - * @apiParam (body) {String} pronoun the pronoun of the account creator. - * @apiParam (body) {String} email Email of the account. - * @apiParam (body) {String} gender Gender of the account creator. - * @apiParam (body) {String[]} dietaryRestrictions Any dietary restrictions for the user. 'None' if there are no restrictions - * @apiParam (body) {String} password The password of the account. - * @apiParam (body) {String} birthDate a Date parsable string. - * @apiParam (body) {Number} [phoneNumber] the user's phone number, represented as a string. - * @apiParam (header) {JWT} [token] the user's invite token. - * - * @apiParamExample {json} Request-Example: - * { - "firstName": "Theo", - "lastName":"Klein", - "pronoun":"he/him", - "email":"theo@klein.com", - "password":"hunter2", - "phoneNumber":1234567890, - "gender":"Male", - "birthDate":"10/30/1997" - * } - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data Account object - * @apiSuccessExample {object} Success-Response: - * { - "message": "Account creation successful", - "data": { - "id": ObjectId("5bff8b9f3274cf001bc71048"), - "firstName": "Theo", - "lastName":"Klein", - "pronoun":"he/him", - "email":"theo@klein.com", - "phoneNumber":1234567890, - "gender":"Male", - "birthDate":Date("10/30/1997") - } - } - - * @apiError {string} message Error message - * @apiError {object} data empty - * @apiErrorExample {object} Error-Response: - * { - * "message": "Account already exists", - * "data": { - * "route": "/" - * } - * } - */ - accountRouter.route("/").post( - // validators - Middleware.Validator.Account.newAccountValidator, - - Middleware.parseBody.middleware, - - // middlewares to parse body/organize body - Middleware.Account.parseAccount, - - // Parses account token if it exists - Middleware.Auth.parseAccountConfirmationToken, - Middleware.Auth.validateConfirmationTokenWithoutAccount, - - // middleware to create hacker object in database - Middleware.Account.addAccount, - Middleware.Auth.addCreationRoleBindings, - - // middleware to create a hacker token - // and send a confirmation message - Middleware.Auth.sendConfirmAccountEmail, - // should return status in this function - Controllers.Account.addUser - ); - - /** - * @api {post} /account/invite invites a user to create an account with the specified accountType - * @apiName inviteAccount - * @apiGroup Account - * @apiVersion 0.0.8 - * @apiDescription sends link with token to be used with the account/create route - * - * @apiParam (body) {String} [email] email of the account to be created and where to send the link - * @apiParam (body) {String} [accountType] the type of the account which the user can create, for sponsor this should specify tier as well - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data Account object - * @apiSuccessExample {object} Success-Response: - * { - "message": "Successfully invited user", - "data": {} - } - * @apiError {string} message Error message - * @apiError {object} data Error object - * @apiErrorExample {object} Error-Response: - * { - "message": "Invalid Authentication", - "data": { - "route": "/invite" - } - } - */ - accountRouter - .route("/invite") - .post( - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized(), - Middleware.Validator.Account.inviteAccountValidator, - Middleware.parseBody.middleware, - Middleware.Account.inviteAccount, - Controllers.Account.invitedAccount - ); - /** - * @api {get} /account/invite Get all of the invites. - * @apiName getAllInvites - * @apiGroup Account - * @apiVersion 0.0.8 - * @apiDescription Get all of the invites that currently exist in the database. - * @apiSuccessExample {object} Success-Response: - * { - "message": "Invite retrieval successful.", - "data": [{ - "email":"abc@def.com", - "accountType":"Hacker" - }] - } - */ - accountRouter - .route("/invite") - .get( - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized(), - Middleware.parseBody.middleware, - Middleware.Account.getInvites, - Controllers.Account.gotInvites - ); - - /** - * @api {patch} /account/:id update an account's information - * @apiName updateOneUser - * @apiGroup Account - * @apiVersion 0.0.8 - * - * @apiParam (body) {String} [firstName] First name of the account creator. - * @apiParam (body) {String} [lastName] Last name of the account creator. - * @apiParam (body) {String} [pronoun] The pronoun of the account creator. - * @apiParam (body) {String} [email] Email of the account. - * @apiParam (body) {String} [gender] Gender of the account creator. - * @apiParam (body) {String} [birthDate] A Date parsable string. - * @apiParam (body) {Number} [phoneNumber] The user's phone number, represented as a string. - * @apiParam (body) {String} [birthDate] a Date parsable string. - * @apiParam (body) {String[]} [dietaryRestrictions] Any dietary restrictions for the user. 'None' if there are no restrictions - * @apiParamExample {json} Request-Example: - * { "gender": "Male" } - * - - * @apiSuccess {string} message Success message - * @apiSuccess {object} data Account object - * @apiSuccessExample {object} Success-Response: - * { - "message": "Account update successful.", - "data": { - "id": ObjectId("5bff8b9f3274cf001bc71048"), - "firstName": "Theo", - "lastName":"Klein", - "pronoun":"he/him", - "email":"theo@klein.com", - "phoneNumber":1234567890, - "gender": "Male", - "birthDate":Date("10/30/1997") - } - } - - * @apiError {string} message Error message - * @apiError {object} data empty - * @apiErrorExample {object} Error-Response: - * {"message": "Error while updating account", "data": {}} - */ - accountRouter.route("/:id").patch( - Middleware.Validator.RouteParam.idValidator, - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized([Services.Account.findById]), - // validators - Middleware.Validator.Account.updateAccountValidator, - - Middleware.parseBody.middleware, - Middleware.Account.parsePatch, - - Middleware.Account.updateAccount, - Middleware.Auth.sendConfirmAccountEmail, - // no parse account because will use req.body as information - // because the number of fields will be variable - Controllers.Account.updatedAccount - ); - - /** - * @api {get} /account/:id gets information from an account with mongoid ':id' - * @apiName getAccount - * @apiGroup Account - * @apiVersion 0.0.8 - * - * @apiParam (param) {ObjectId} id MongoId of an account - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data Account object - * @apiSuccessExample {object} Success-Response: - * { - "message": "Account found by user id", - "data": { - "id": ObjectId("5bff8b9f3274cf001bc71048"), - "firstName": "Theo", - "lastName":"Klein", - "pronoun":"he/him", - "email":"theo@klein.com", - "phoneNumber":1234567890, - "gender":"Male", - "birthDate":Date("10/30/1997") - } - } - - * @apiError {string} message Error message - * @apiError {object} data empty - * @apiErrorExample {object} Error-Response: - * {"message": "Account not found", "data": {}} - */ - accountRouter.route("/:id").get( - Middleware.Validator.RouteParam.idValidator, - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized([Services.Account.findById]), - - Middleware.parseBody.middleware, - - Middleware.Account.getById, - Controllers.Account.showAccount - ); - - apiRouter.use("/account", accountRouter); - } -}; diff --git a/routes/api/auth.js b/routes/api/auth.js deleted file mode 100644 index d81ee311..00000000 --- a/routes/api/auth.js +++ /dev/null @@ -1,311 +0,0 @@ -"use strict"; -const express = require("express"); -const passport = require("passport"); -const Services = { - Account: require("../../services/account.service"), - Auth: require("../../services/auth.service"), - ResetPasswordToken: require("../../services/resetPassword.service") -}; -const Middleware = { - Validator: { - Auth: require("../../middlewares/validators/auth.validator"), - RouteParam: require("../../middlewares/validators/routeParam.validator") - }, - parseBody: require("../../middlewares/parse-body.middleware"), - Auth: require("../../middlewares/auth.middleware"), - Account: require("../../middlewares/account.middleware") -}; -const Controllers = { - Auth: require("../../controllers/auth.controller") -}; - -module.exports = { - activate: function(apiRouter) { - passport.serializeUser(Services.Auth.serializeUser); - passport.deserializeUser(Services.Auth.deserializeUser); - const authRouter = express.Router(); - /** - * @api {post} /auth/login login to the service - * @apiName login - * @apiGroup Authentication - * @apiVersion 0.0.8 - * - * @apiParam {string} email Account email - * @apiParam {string} password Account password - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data empty - * @apiSuccessExample {object} Success-Response: - * {"message": "Successfully logged in", "data": {}} - - * @apiError {string} message Error message - * @apiError {object} data empty - * @apiErrorExample {object} Error-Response: - * {"message": "Invalid Authentication", "data": {}} - * - * @apiPermission: public - */ - authRouter - .route("/login") - .post(Middleware.Auth.login, Controllers.Auth.onSuccessfulLogin); - - /** - * @api {get} /auth/logout logout of service - * @apiName logout - * @apiGroup Authentication - * @apiVersion 0.0.8 - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data empty - * @apiSuccessExample {object} Success-Response: - * {"message": "Successfully logged out", "data": {}} - * - * @apiPermission: public - */ - authRouter.route("/logout").get(Controllers.Auth.logout); - - /** - * @api {post} /auth/password/forgot forgot password route - * @apiName forgotPassword - * @apiGroup Authentication - * @apiVersion 0.0.8 - * - * @apiParam {String} email the email address of the account - * - * @apiParamExample {json} Request-Example: - * { "email": "myemail@mchacks.ca" } - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data empty - * @apiSuccessExample {json} Success-Response: - * {"message": "Sent reset email", "data": {}} - * - * @apiPermission: public - */ - authRouter.route("/password/forgot").post( - Middleware.Validator.Auth.ForgotPasswordValidator, - Middleware.parseBody.middleware, - //create resetPassword jwt - //send user an email to reset the password - //create new entity in reset model - //create reset token with entity id - //send email to reset password route - Middleware.Auth.sendResetPasswordEmailMiddleware, - Controllers.Auth.sentResetEmail - ); - - /** - * @api {patch} /auth/password/change change password for logged in user - * @apiName changePassword - * @apiGroup Authentication - * @apiVersion 0.0.8 - * - * @apiParam {String} oldPassword The current password of the user - * @apiParam {String} newPassword The new password of the user - * - * @apiParamExample {json} Request-Example: - * { - * "oldPassword": "password12345", - * "newPassword": "password123456" - * } - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data empty - * @apiSuccessExample {json} Success-Response: - * {"message": "Successfully reset password", "data": {}} - * - * @apiPermission: Must be logged in - */ - authRouter.route("/password/change").patch( - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized(), - Middleware.Validator.Auth.ChangePasswordValidator, - Middleware.parseBody.middleware, - - Middleware.Auth.changePassword, - Controllers.Auth.resetPassword - ); - - //untested - /** - * @api {post} /auth/password/reset reset password - * @apiName resetPassword - * @apiGroup Authentication - * @apiVersion 0.0.8 - * - * @apiParam {String} password the password of the account - * @apiHeader {String} Authentication the token that was provided in the reset password email - * @apiHeaderExample {json} Header-Example: - * { - * "X-Reset-Token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" - * } - * - * @apiParamExample {json} Request-Example: - * { "password": "hunter2" } - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data empty - * @apiSuccessExample {json} Success-Response: - * {"message": "Successfully reset password", "data": {}} - * - * @apiPermission: must have authentication token - */ - authRouter.route("/password/reset").post( - //post new password, validate token also - Middleware.Validator.Auth.ResetPasswordValidator, - Middleware.parseBody.middleware, - Middleware.Auth.parseResetToken, - /** - * Check to make sure that the token: - * 1) exists in the db - * 2) not expired - */ - Middleware.Auth.validateResetToken, - //update the password in the db - Middleware.Account.updatePassword, - //delete the token that was used - Middleware.Auth.deleteResetToken, - //send the response - Controllers.Auth.resetPassword - ); - - /** - * @api {post} /auth/confirm/:token confirm account using the JWT in :token - * @apiName confirmAccount - * @apiGroup Authentication - * @apiVersion 0.0.8 - * - * @apiParam {String} JWT for confirming the account - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data empty - * @apiSuccessExample {json} Success-Response: - * {"message": "Successfully confirmed account", "data": {}} - * - * @apiError {string} message Error message - * @apiError {object} data empty - * @apiErrorExample {object} Error-Response: - * {"message": "Invalid token for confirming account, "data": {}} - * - */ - authRouter - .route("/confirm/:token") - .post( - Middleware.Validator.Auth.accountConfirmationValidator, - Middleware.parseBody.middleware, - Middleware.Auth.parseAccountConfirmationToken, - Middleware.Auth.validateConfirmationToken, - Controllers.Auth.confirmAccount - ); - - /** - * @api {get} /auth/rolebindings/:id retrieve rolebindings for a user given by their user id :id - * @apiName getRoleBindings - * @apiGroup Authentication - * @apiVersion 0.0.8 - * - * @apiParam (param) {ObjectId} id MongoId of an account - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data Rolebindings object - * @apiSuccessExample {object} Success-Response: - * { - "message": "Successfully retrieved role bindings", - "data": { - accountId:"5beca4ab2e069a34f91697b2" - id:"5beca4ae2e069a34f91698b1" - roles: [ - { - _id:"5beca4ab2e069a34f91697d9", - name:"hacker", - routes: [ - {_id: "5beca4ae2e069a34f9169852", requestType: "POST", uri: "/api/auth/login"}, - {_id: "5beca4ae2e069a34f9169851", requestType: "POST", uri: "/api/auth/logout"}, - {_id: "5beca4ae2e069a34f9169850", requestType: "GET", uri: "/api/auth/rolebindings/:self"}, - {_id: "5beca4ae2e069a34f916984f", requestType: "GET", uri: "/api/account/self"}, - {_id: "5beca4ae2e069a34f916984e", requestType: "GET", uri: "/api/account/:self"}, - {_id: "5beca4ae2e069a34f916984d", requestType: "PATCH", uri: "/api/account/:self"}, - {_id: "5beca4ae2e069a34f916984c", requestType: "POST", uri: "/api/hacker/"}, - {_id: "5beca4ae2e069a34f916984b", requestType: "GET", uri: "/api/hacker/:self"}, - {_id: "5beca4ae2e069a34f916984a", requestType: "GET", uri: "/api/hacker/:self/resume"}, - {_id: "5beca4ae2e069a34f9169849", requestType: "PATCH", uri: "/api/hacker/:self"} - ] - } - ] - } - } - * @apiError {string} message Error message - * @apiError {object} data empty - * @apiErrorExample {object} Error-Response: - * {"message": "Role Bindings not found", "data": {}} - * - */ - authRouter - .route("/rolebindings/:id") - .get( - Middleware.Validator.RouteParam.idValidator, - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized([Services.Account.findById]), - Middleware.parseBody.middleware, - Middleware.Auth.retrieveRoleBindings, - Controllers.Auth.retrieveRoleBindings - ); - - /** - * @api {get} /auth/confirm/resend resend confirmation token - * @apiName resendConfirmAccount - * @apiGroup Authentication - * @apiVersion 0.0.8 - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data empty - * @apiSuccessExample {json} Success-Response: - * {"message": "Successfully resent confirmation email", "data": {}} - * - * @apiError {string} message Error message - * @apiError {object} data empty - * @apiErrorExample {json} Error-Response: - * HTTP/1.1 422 - * {"message": "Account already confirmed", "data": {}} - * - * @apiError {string} message Error message - * @apiError {object} data empty - * @apiErrorExample {json} Error-Response: - * HTTP/1.1 428 - * {"message": "Account confirmation token does not exist", "data": {}} - * - */ - authRouter - .route("/confirm/resend") - .get( - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.resendConfirmAccountEmail, - Controllers.Auth.sentConfirmationEmail - ); - - /** - * @api {get} /auth/roles get roles - * @apiName getRoles - * @apiDescription get all roles that exist in the database - * @apiGroup Authentication - * @apiVersion 0.0.8 - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data empty - * @apiSuccessExample {json} Success-Response: - * {"message": "Sucessfully retrieved all roles", "data": - * [{name: "GodStaff", routes: Array(27), id: "5bee20ef3ca9dd4754382880"}, - * {name: "Hacker", routes: Array(10), id: "5bee20ef3ca9dd4754382881"}, - * {name: "Volunteer", routes: Array(4), id: "5bee20ef3ca9dd4754382882"}] - * - */ - authRouter - .route("/roles") - .get( - Middleware.Auth.retrieveRoles, - Controllers.Auth.retrievedRoles - ); - - apiRouter.use("/auth", authRouter); - } -}; diff --git a/services/account-confirmation.service.ts b/services/account-confirmation.service.ts new file mode 100644 index 00000000..ba5bc6c1 --- /dev/null +++ b/services/account-confirmation.service.ts @@ -0,0 +1,73 @@ +import { autoInjectable, singleton } from "tsyringe"; +import { getRepository, Repository } from "typeorm"; +import AccountConfirmation from "../models/accountConfirmationToken.model"; +import jwt from "jsonwebtoken"; +import { EnvService } from "./env.service"; + +@autoInjectable() +@singleton() +export class AccountConfirmationService { + private readonly accountConfirmationRepository: Repository< + AccountConfirmation + >; + + constructor(private readonly envService: EnvService) { + this.accountConfirmationRepository = getRepository(AccountConfirmation); + } + + public async findByIdentifier( + identifier: number + ): Promise { + return await this.accountConfirmationRepository.findOne(identifier); + } + + // TODO - Verify if this functionality works. + // https://github.com/typeorm/typeorm/issues/4396 + // https://github.com/typeorm/typeorm/issues/2707 + public async findByAccount( + identifier: number + ): Promise { + return await this.accountConfirmationRepository.findOne({ + where: { account: { identifier: identifier } } + }); + } + + public async save( + confirmation: Partial + ): Promise { + return await this.accountConfirmationRepository.save(confirmation); + } + + public async delete(identifier: number) { + return await this.accountConfirmationRepository.delete({ + identifier: identifier + }); + } + + public generateLink(route: string, token: string): string { + const domain = this.getDomain()!; + const protocol = domain.includes("localhost") ? "http" : "https"; + return `${protocol}://${domain}/${route}?token=${token}`; + } + + private getDomain() { + return this.envService.isDevelopment() + ? this.envService.get(`FRONTEND_ADDRESS_DEV`) + : this.envService.isProduction() + ? this.envService.get(`FRONTEND_ADDRESS_DEPLOY`) + : this.envService.get(`FRONTEND_ADDRESS_DEV`); + } + + public generateToken(identifier: number, account: number): string { + return jwt.sign( + { + identifier: identifier, + account: account + }, + process.env.JWT_CONFIRM_ACC_SECRET ?? "default", + { expiresIn: "1 week" } + ); + } +} + +// TODO - Implement account invite confirmation policy in the old accountConfirmation.service.ts file. diff --git a/services/accountConfirmation.service.ts b/services/accountConfirmation.service.ts deleted file mode 100644 index 7700c315..00000000 --- a/services/accountConfirmation.service.ts +++ /dev/null @@ -1,235 +0,0 @@ -const logger = require("./logger.service"); -import AccountConfirmation from "../models/accountConfirmationToken.model"; -import { findById as findByIdAccountService } from "./account.service"; -const Constants = require("../constants/general.constant"); -const jwt = require("jsonwebtoken"); -const path = require("path"); -const Services = { - Email: require("./email.service") -}; - -/** - * @function findByAccountId - * @param {number} identifier - * @return {Promise} The document query will resolve to either account confirmation or null. - * @description Finds an account confirmation document by accountId. - */ -async function findByAccountId( - identifier: number -): Promise { - const TAG = `[ AccountConfirmation Reset Service # findByAccountId ]`; - - return await AccountConfirmation.findOne({ - where: { account: identifier } - }).then((accountConfirmation) => { - logger.queryCallbackFactory(TAG, "AccountConfirmation", "accountId"); - return accountConfirmation; - }); -} - -/** - * @function findById - * @param {number} identifier - * @return {Promise} The document query will resolve to either account confirmation or null. - * @description Finds an account by mongoID. - */ -async function findById( - identifier: number -): Promise { - const TAG = `[ AccountConfirmation Service # findById ]`; - return await AccountConfirmation.findOne({ - where: { identifier: identifier } - }).then((accountConfirmation) => { - logger.queryCallbackFactory(TAG, "AccountConfirmation", "identifier"); - return accountConfirmation; - }); -} - -/** - * @function find - * @param {*} query the query to search the database by. - * @return {Promise} The document query will resolve to either account confirmations or null. - * @description Finds an account by query. - */ -async function find(query: Object): Promise { - const TAG = `[ AccountConfirmation Service # find ]`; - - return await AccountConfirmation.find(query).then((accountConfirmation) => { - logger.queryCallbackFactory(TAG, "AccountConfirmation", query); - return accountConfirmation; - }); -} - -/** - * Creates Account Confirmation document in the database - * @param {String} type the type of user which to create the token for - * @param {String} email - * @param {"Invite"|"Organic"} confirmationType whether this confirmation token is for an organic acct creation, or an invited account - * @param {number} accountId optional accountId parameter to link to account, optional when token is being made for not a hacker - * @returns {Promise.<*>} - */ -async function create( - type: string, - email: string, - confirmationType: string, - accountId: number -): Promise { - const newAccountToken = await AccountConfirmation.create({ - accountType: type, - email: email, - confirmationType: confirmationType, - account: await findByIdAccountService(accountId) - }); - return newAccountToken.save(); -} - -/** - * Generates JWT for Confirming account - * @param {number} accountConfirmationId - * @param {number} accountId - * @returns {string} JWT Token containing accountId and accountConfirmationId - */ -function generateToken(accountConfirmationId: number, accountId = null) { - const token = jwt.sign( - { - accountConfirmationId: accountConfirmationId, - accountId: accountId - }, - process.env.JWT_CONFIRM_ACC_SECRET, - { - expiresIn: "7 day" - } - ); - return token; -} - -/** - * Generates the link that the user will use to access the page to begin account creationg - * @param {'http'|'https'} httpOrHttps - * @param {string} domain the domain of the current - * @param {string} type the model that the - * @param {string} token the reset token - * @returns {string} the string, of form: [http|https]://{domain}/{model}/create?token={token} - */ -function generateCreateAccountTokenLink( - httpOrHttps: string, - domain: string, - type: string, - token: string -): string { - const link = `${httpOrHttps}://${domain}/account/create?token=${token}&accountType=${type}`; - return link; -} - -/** - * Generates the link that the user will use to confirm account and proceed with account creationg - * @param {'http'|'https'} httpOrHttps - * @param {string} domain the domain of the current - * @param {string} type the model that the - * @param {string} token the reset token - * @returns {string} the string, of form: [http|https]://{domain}/{model}/create?token={token} - */ -function generateConfirmTokenLink( - httpOrHttps: string, - domain: string, - token: string -): string { - const link = `${httpOrHttps}://${domain}/account/confirm?token=${token}`; - return link; -} -/** - * Generates the mailData for the account confirmation Email. This really only applies to - * hackers as all other accounts are intrinsically confirmed via the email they recieve to invite them - * @param {string} address The hostname that this service is running on - * @param {string} receiverEmail The receiver of the email - * @param {string} type the user type - * @param {string} token The account confirmation token - */ -function generateAccountConfirmationEmail( - address: string, - receiverEmail: string, - type: string, - token: string -): Object | undefined { - const httpOrHttps = address.includes("localhost") ? "http" : "https"; - const tokenLink = generateConfirmTokenLink(httpOrHttps, address, token); - var emailSubject = ""; - if (token === undefined || tokenLink === undefined) { - return undefined; - } - if (type === Constants.HACKER) { - emailSubject = Constants.CONFIRM_ACC_EMAIL_SUBJECT; - } - const handlebarPath = path.join( - __dirname, - `../assets/email/AccountConfirmation.hbs` - ); - - const mailData = { - from: process.env.NO_REPLY_EMAIL, - to: receiverEmail, - subject: emailSubject, - html: Services.Email.renderEmail(handlebarPath, { - link: tokenLink - }) - }; - return mailData; -} - -/* - * Generates the mailData for the account invitation Email. - * @param {string} address The hostname that this service is running on - * @param {string} receiverEmail The receiver of the email - * @param {string} type The user type - * @param {string} token The account confirmation token - */ -function generateAccountInvitationEmail( - address: string, - receiverEmail: string, - type: string, - token: string -) { - const httpOrHttps = address.includes("localhost") ? "http" : "https"; - const tokenLink = generateCreateAccountTokenLink( - httpOrHttps, - address, - type, - token - ); - var emailSubject = ""; - if (token === undefined || tokenLink === undefined) { - return undefined; - } - if (type === Constants.HACKER) { - emailSubject = Constants.CREATE_ACC_EMAIL_SUBJECTS[Constants.HACKER]; - } else if (type === Constants.VOLUNTEER) { - emailSubject = Constants.CREATE_ACC_EMAIL_SUBJECTS[Constants.VOLUNTEER]; - } else if (Constants.SPONSOR_TIERS.includes(type)) { - emailSubject = Constants.CREATE_ACC_EMAIL_SUBJECTS[Constants.SPONSOR]; - } else if (type === Constants.STAFF) { - emailSubject = Constants.CREATE_ACC_EMAIL_SUBJECTS[Constants.STAFF]; - } - const handlebarPath = path.join( - __dirname, - `../assets/email/AccountInvitation.hbs` - ); - const mailData = { - from: process.env.NO_REPLY_EMAIL, - to: receiverEmail, - subject: emailSubject, - html: Services.Email.renderEmail(handlebarPath, { - link: tokenLink - }) - }; - return mailData; -} - -export { - find, - findById, - findByAccountId, - create, - generateToken, - generateAccountConfirmationEmail, - generateAccountInvitationEmail -}; From dacc2d7b5c89d32ea33e040c6ab221a3d921fa16 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Wed, 22 Dec 2021 21:45:09 -0500 Subject: [PATCH 10/72] feat: add password-reset service (forgot to add to previous commit). --- services/password-reset.service.ts | 68 +++++++++++++++ services/resetPassword.service.ts | 136 ----------------------------- 2 files changed, 68 insertions(+), 136 deletions(-) create mode 100644 services/password-reset.service.ts delete mode 100644 services/resetPassword.service.ts diff --git a/services/password-reset.service.ts b/services/password-reset.service.ts new file mode 100644 index 00000000..a2fffb03 --- /dev/null +++ b/services/password-reset.service.ts @@ -0,0 +1,68 @@ +import { autoInjectable } from "tsyringe"; +import { DeleteResult, getRepository, Repository } from "typeorm"; +import Account from "../models/account.model"; +import PasswordReset from "../models/passwordResetToken.model"; +import jwt from "jsonwebtoken"; +import { EnvService } from "./env.service"; + +@autoInjectable() +export class PasswordResetService { + private readonly passwordResetRepository: Repository; + constructor(private readonly envService: EnvService) { + this.passwordResetRepository = getRepository(PasswordReset); + } + + public async findByIdentifier( + identifier: number + ): Promise { + return await this.passwordResetRepository.findOne(identifier); + } + + public async save(account: Account): Promise { + this.invalidatePreviousRequests(account); + + return await this.passwordResetRepository.save({ + account: account, + createdAt: new Date() + }); + } + + public async delete(identifier: number): Promise { + return await this.passwordResetRepository.delete({ + identifier: identifier + }); + } + + private async invalidatePreviousRequests( + account: Account + ): Promise { + return await this.passwordResetRepository.delete({ + account: { identifier: account.identifier } + }); + } + + public generateLink(route: string, token: string): string { + const domain = this.getDomain()!; + const protocol = domain.includes("localhost") ? "http" : "https"; + return `${protocol}://${domain}/${route}?token=${token}`; + } + + private getDomain() { + return this.envService.isDevelopment() + ? this.envService.get(`FRONTEND_ADDRESS_DEV`) + : this.envService.isProduction() + ? this.envService.get(`FRONTEND_ADDRESS_DEPLOY`) + : this.envService.get(`FRONTEND_ADDRESS_DEV`); + } + + public generateToken(identifier: number, account: number): string { + return jwt.sign( + { + identifier: identifier, + account: account + }, + process.env.JWT_CONFIRM_ACC_SECRET ?? "default", + { expiresIn: "1 day" } + ); + } +} diff --git a/services/resetPassword.service.ts b/services/resetPassword.service.ts deleted file mode 100644 index 33330bb0..00000000 --- a/services/resetPassword.service.ts +++ /dev/null @@ -1,136 +0,0 @@ -const logger = require("./logger.service"); -import PasswordReset from "../models/passwordResetToken.model"; -const jwt = require("jsonwebtoken"); -const path = require("path"); -const Services = { - Email: require("./email.service"), - Account: require("./account.service") -}; - -async function findByAccountId( - identifier: number -): Promise { - const TAG = `[ PasswordReset Service # findByAccountId ]`; - return await PasswordReset.findOne({ where: { account: identifier } }).then( - (account) => { - logger.queryCallbackFactory(TAG, "passwordReset", "accountId"); - return account; - } - ); -} - -function findById(identifier: number): Promise { - const TAG = `[ PasswordReset Service # findById ]`; - - return PasswordReset.findOne(identifier).then( - (passwordReset: PasswordReset) => { - logger.queryCallbackFactory(TAG, "passwordReset", "identifier"); - return passwordReset; - } - ); -} - -async function create(accountId: number) { - const TAG = `[ PasswordReset Service # create]:`; - //Create new instance of password reset token - const newResetToken = PasswordReset.create({ - account: await Services.Account.findOne(accountId), - createdAt: new Date() - }); - - // TODO - Previous behaviour was to mark reset tokens as used in "wasUsed" field. - - //invalidate all of the previous reset tokens such that they do not work anymore - await PasswordReset.delete({ - account: await Services.Account.findOne(accountId) - }) - .then(() => { - logger.info( - `${TAG} invalidated all previous password reset tokens ${accountId}` - ); - }) - .catch((error: Object) => { - logger.error( - `${TAG} could not invalidate all previous password reset tokens`, - error - ); - }); - - return newResetToken.save(); -} - -function deleteToken(identifier: number) { - const TAG = `[ PasswordReset Service # deleteToken]:`; - - //Create new instance of password reset token - return PasswordReset.delete(identifier).catch((error: Object) => { - logger.error(`${TAG} could not delete token id: ${identifier}`); - }); -} - -function generateToken(resetId: number, accountId: number) { - const token = jwt.sign( - { - resetId: resetId, - accountId: accountId - }, - process.env.JWT_RESET_PWD_SECRET, - { - expiresIn: "1 day" - } - ); - return token; -} - -/** - * Generates the link that the user will use to access the reset password page - * @param {'http'|'https'} httpOrHttps - * @param {string} domain the domain of the current - * @param {string} token the reset token - * @returns {string} the string, of form: [http|https]://{domain}/password/reset?token={token} - */ -function generateTokenLink(httpOrHttps: string, domain: string, token: string) { - const link = `${httpOrHttps}://${domain}/password/reset?token=${token}`; - return link; -} - -/** - * Generates the mailData for the resetPassword Email. - * @param {string} address The web address that the front-end service is running on - * @param {string} receiverEmail The receiver of the email - * @param {string} token The resetPassword token - */ -function generateResetPasswordEmail( - address: string, - receiverEmail: string, - token: string -) { - const httpOrHttps = address.includes("localhost") ? "http" : "https"; - const tokenLink = generateTokenLink(httpOrHttps, address, token); - if (token === undefined || tokenLink === undefined) { - return undefined; - } - const handlebarPath = path.join( - __dirname, - `../assets/email/ResetPassword.hbs` - ); - const mailData = { - from: process.env.NO_REPLY_EMAIL, - to: receiverEmail, - subject: "Password Reset Instructions", - html: Services.Email.renderEmail(handlebarPath, { - link: tokenLink - }) - }; - return mailData; -} - -module.exports = { - findByAccountId: findByAccountId, - findById: findById, - create: create, - generateToken: generateToken, - deleteToken: deleteToken, - generateTokenLink: generateTokenLink, - generateResetPasswordEmail: generateResetPasswordEmail -}; From 6ae3332ab75a40beae33ae6cc1b3b70fd5f30256 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Wed, 22 Dec 2021 23:10:56 -0500 Subject: [PATCH 11/72] refactor: remove unnecessary routing files, models, related controllers, and seed files. - remove old routing files. - we use decorator based routing so these centralized files are no longer necessary. - some files are for models that we no longer need as RBAC is based on decorators as well - roles, role-bindings. - remove seed files. - these were used for role-bindings and RBAC. - as we have moved to decorator-based routing and authorization info is stored in the codebase itself instead of the database this is no longer required. - the settings seed file is also not required. - remove old role and role binding service. - same reason as mentioned above for RBAC / authorization. - remove parse-patch service as we use decorator based routing. - remove email-template model. - future plans to implement CRUD interface for sending out e-mails. - never got implemented. - delete route constants file as we have moved to decorator based routing. --- constants/routes.constant.js | 441 -------------------------------- controllers/role.controller.js | 21 -- middlewares/role.middleware.js | 65 ----- routes/api/role.js | 74 ------ routes/index.js | 22 -- seed/index.js | 51 ---- seed/roles.seed.js | 28 -- seed/settings.seed.js | 22 -- services/parsePatch.service.ts | 20 -- services/role.service.ts | 66 ----- services/roleBinding.service.ts | 130 ---------- 11 files changed, 940 deletions(-) delete mode 100644 constants/routes.constant.js delete mode 100644 controllers/role.controller.js delete mode 100644 middlewares/role.middleware.js delete mode 100644 routes/api/role.js delete mode 100755 routes/index.js delete mode 100644 seed/index.js delete mode 100644 seed/roles.seed.js delete mode 100644 seed/settings.seed.js delete mode 100644 services/parsePatch.service.ts delete mode 100644 services/role.service.ts delete mode 100644 services/roleBinding.service.ts diff --git a/constants/routes.constant.js b/constants/routes.constant.js deleted file mode 100644 index 031d72f6..00000000 --- a/constants/routes.constant.js +++ /dev/null @@ -1,441 +0,0 @@ -"use strict"; - -/** - * ===***===***===***===***===***===***===***===***=== - * ===***=== PLEASE READ BEFORE EDITING ===***=== - * ===***===***===***===***===***===***===***===***=== - * - * If you are adding a route to this list, update this number - * next avaiable createFromTime value: 166 - * - * If you are deleting a route from this list, please add the ID to the list of 'reserved' IDs, - * so that we don't accidentally assign someone to a given ID. - * reserved createFromTime values: - */ - -const Constants = require("./general.constant"); - -const authRoutes = { - login: { - requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/auth/login", - _id: 100 - }, - logout: { - requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/auth/logout", - _id: 101 - }, - getSelfRoleBindindings: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/auth/rolebindings/" + Constants.ROLE_CATEGORIES.SELF, - _id: 102 - }, - getAnyRoleBindings: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/auth/rolebindings/" + Constants.ROLE_CATEGORIES.ALL, - _id: 103 - }, - changePassword: { - requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/auth/password/change", - _id: 104 - } -}; - -const accountRoutes = { - getSelf: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/account/self", - _id: 105 - }, - getSelfById: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/account/" + Constants.ROLE_CATEGORIES.SELF, - _id: 106 - }, - getAnyById: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/account/" + Constants.ROLE_CATEGORIES.ALL, - _id: 107 - }, - post: { - requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/account/", - _id: 108 - }, - patchSelfById: { - requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/account/" + Constants.ROLE_CATEGORIES.SELF, - _id: 109 - }, - patchAnyById: { - requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/account/" + Constants.ROLE_CATEGORIES.ALL, - _id: 110 - }, - inviteAccount: { - requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/account/invite", - _id: 111 - } -}; - -const hackerRoutes = { - getSelf: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/hacker/self/", - _id: 112 - }, - getSelfById: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/hacker/" + Constants.ROLE_CATEGORIES.SELF, - _id: 113 - }, - getAnyById: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/hacker/" + Constants.ROLE_CATEGORIES.ALL, - _id: 114 - }, - getSelfByEmail: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/hacker/email/" + Constants.ROLE_CATEGORIES.SELF, - _id: 115 - }, - getAnyByEmail: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/hacker/email/" + Constants.ROLE_CATEGORIES.ALL, - _id: 116 - }, - getSelfResumeById: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/hacker/resume/" + Constants.ROLE_CATEGORIES.SELF, - _id: 117 - }, - getAnyResumeById: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/hacker/resume/" + Constants.ROLE_CATEGORIES.ALL, - _id: 118 - }, - post: { - requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/hacker/", - _id: 119 - }, - postSelfResumeById: { - requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/hacker/resume/" + Constants.ROLE_CATEGORIES.SELF, - _id: 120 - }, - postAnyResumeById: { - requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/hacker/resume/" + Constants.ROLE_CATEGORIES.ALL, - _id: 121 - }, - patchSelfById: { - requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/hacker/" + Constants.ROLE_CATEGORIES.SELF, - _id: 122 - }, - patchAnyById: { - requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/hacker/" + Constants.ROLE_CATEGORIES.ALL, - _id: 123 - }, - patchAnyStatusById: { - requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/hacker/status/" + Constants.ROLE_CATEGORIES.ALL, - _id: 124 - }, - patchSelfStatusById: { - requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/hacker/status/" + Constants.ROLE_CATEGORIES.SELF, - _id: 125 - }, - patchSelfCheckInById: { - requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/hacker/checkin/" + Constants.ROLE_CATEGORIES.SELF, - _id: 126 - }, - patchAnyCheckInById: { - requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/hacker/checkin/" + Constants.ROLE_CATEGORIES.ALL, - _id: 127 - }, - patchSelfConfirmationById: { - requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/hacker/confirmation/" + Constants.ROLE_CATEGORIES.SELF, - _id: 128 - }, - patchAcceptHackerById: { - requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/hacker/accept/" + Constants.ROLE_CATEGORIES.ALL, - _id: 129 - }, - patchAcceptHackerByEmail: { - requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/hacker/acceptEmail/" + Constants.ROLE_CATEGORIES.ALL, - _id: 130 - }, - patchAcceptHackerByArrayOfIds: { - requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/hacker/batchAccept", - _id: 165 - }, - postAnySendWeekOfEmail: { - requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/hacker/email/weekOf/" + Constants.ROLE_CATEGORIES.ALL, - _id: 131 - }, - postSelfSendWeekOfEmail: { - requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/hacker/email/weekOf/" + Constants.ROLE_CATEGORIES.SELF, - _id: 132 - }, - postAnySendDayOfEmail: { - requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/hacker/email/dayOf/" + Constants.ROLE_CATEGORIES.ALL, - _id: 133 - }, - postSelfSendDayOfEmail: { - requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/hacker/email/dayOf/" + Constants.ROLE_CATEGORIES.SELF, - _id: 134 - } -}; - -const travelRoutes = { - getSelf: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/travel/self/", - _id: 135 - }, - getSelfById: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/travel/" + Constants.ROLE_CATEGORIES.SELF, - _id: 136 - }, - getAnyById: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/travel/" + Constants.ROLE_CATEGORIES.ALL, - _id: 137 - }, - getSelfByEmail: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/travel/email/" + Constants.ROLE_CATEGORIES.SELF, - _id: 138 - }, - getAnyByEmail: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/travel/email/" + Constants.ROLE_CATEGORIES.ALL, - _id: 139 - }, - post: { - requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/travel/", - _id: 140 - }, - patchAnyStatusById: { - requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/travel/status/" + Constants.ROLE_CATEGORIES.ALL, - _id: 141 - }, - patchAnyOfferById: { - requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/travel/offer/" + Constants.ROLE_CATEGORIES.ALL, - _id: 142 - } -}; - -const sponsorRoutes = { - getSelf: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/sponsor/self/", - _id: 143 - }, - getSelfById: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/sponsor/" + Constants.ROLE_CATEGORIES.SELF, - _id: 144 - }, - getAnyById: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/sponsor/" + Constants.ROLE_CATEGORIES.ALL, - _id: 145 - }, - post: { - requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/sponsor/", - _id: 146 - }, - patchSelfById: { - requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/sponsor/" + Constants.ROLE_CATEGORIES.SELF, - _id: 147 - }, - patchAnyById: { - requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/sponsor/" + Constants.ROLE_CATEGORIES.ALL, - _id: 148 - } -}; - -const teamRoutes = { - get: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/team/" + Constants.ROLE_CATEGORIES.ALL, - _id: 149 - }, - post: { - requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/team/", - _id: 150 - }, - join: { - requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/team/join/", - _id: 151 - }, - patchSelfById: { - requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/team/" + Constants.ROLE_CATEGORIES.SELF, - _id: 152 - }, - patchAnyById: { - requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/team/" + Constants.ROLE_CATEGORIES.ALL, - _id: 153 - }, - leave: { - requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/team/leave/", - _id: 154 - } -}; - -const volunteerRoutes = { - getSelfById: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/volunteer/" + Constants.ROLE_CATEGORIES.SELF, - _id: 155 - }, - getAnyById: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/volunteer/" + Constants.ROLE_CATEGORIES.ALL, - _id: 156 - }, - post: { - requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/volunteer/", - _id: 157 - } -}; - -const roleRoutes = { - post: { - requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/role/", - _id: 158 - } -}; - -const searchRoutes = { - get: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/search/", - _id: 159 - } -}; - -const staffRoutes = { - hackerStats: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/hacker/stats", - _id: 160 - }, - postInvite: { - requestType: Constants.REQUEST_TYPES.POST, - uri: "/api/account/invite", - _id: 161 - }, - getInvite: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/account/invite", - _id: 162 - } -}; - -const settingsRoutes = { - getSettings: { - requestType: Constants.REQUEST_TYPES.GET, - uri: "/api/settings", - _id: 163 - }, - patchSettings: { - requestType: Constants.REQUEST_TYPES.PATCH, - uri: "/api/settings", - _id: 164 - } -}; - -const allRoutes = { - Auth: authRoutes, - Account: accountRoutes, - Hacker: hackerRoutes, - Travel: travelRoutes, - Sponsor: sponsorRoutes, - Team: teamRoutes, - Volunteer: volunteerRoutes, - Role: roleRoutes, - Search: searchRoutes, - Settings: settingsRoutes, - Staff: staffRoutes -}; - -/** - * returns all the routes as a list - * @param {boolean} includeId whether to include _id in the returned route object. - * @return {{requestType: string, uri: string, id?: ObjectId}[]} - */ -function listAllRoutes(includeId = true) { - let routes = []; - - for (let routeGroupKey in allRoutes) { - if (!Object.prototype.hasOwnProperty.call(allRoutes, routeGroupKey)) { - continue; - } - - const routeGroup = allRoutes[routeGroupKey]; - for (let routeKey in routeGroup) { - if (!Object.prototype.hasOwnProperty.call(routeGroup, routeKey)) { - continue; - } - - const route = {}; - // copy only over the attributes that we care about - route.requestType = routeGroup[routeKey].requestType; - route.uri = routeGroup[routeKey].uri; - if (includeId) route._id = routeGroup[routeKey]._id; - - routes.push(route); - } - } - - return routes; -} - -module.exports = { - authRoutes: authRoutes, - accountRoutes: accountRoutes, - hackerRoutes: hackerRoutes, - travelRoutes: travelRoutes, - sponsorRoutes: sponsorRoutes, - teamRoutes: teamRoutes, - volunteerRoutes: volunteerRoutes, - roleRoutes: roleRoutes, - searchRoutes: searchRoutes, - settingsRoutes: settingsRoutes, - staffRoutes: staffRoutes, - allRoutes: allRoutes, - listAllRoutes: listAllRoutes -}; diff --git a/controllers/role.controller.js b/controllers/role.controller.js deleted file mode 100644 index 8a928a7b..00000000 --- a/controllers/role.controller.js +++ /dev/null @@ -1,21 +0,0 @@ -"use strict"; - -const Success = require("../constants/success.constant"); - -/** - * @function createdRole - * @param {{body: {role: Object}}} req - * @param {*} res - * @return {JSON} Success status and role object - * @description Returns the JSON of role object located in req.body.role - */ -function createdRole(req, res) { - return res.status(200).json({ - message: Success.ROLE_CREATE, - data: req.body.role.toJSON() - }); -} - -module.exports = { - createdRole: createdRole -}; diff --git a/middlewares/role.middleware.js b/middlewares/role.middleware.js deleted file mode 100644 index 18a7875e..00000000 --- a/middlewares/role.middleware.js +++ /dev/null @@ -1,65 +0,0 @@ -"use strict"; -const mongoose = require("mongoose"); -const Services = { - Role: require("../services/role.service") -}; -const Constants = { - Error: require("../constants/error.constant") -}; - -/** - * @function parseRole - * @param {{body: name: String, routes: route[]}}} req - * @param {*} res - * @param {(err?)=>void} next - * @return {void} - * @description - * Moves name and routes from req.body to req.body.roleDetails. - * Adds _id to roleDetails. - */ -function parseRole(req, res, next) { - const roleDetails = { - _id: mongoose.Types.ObjectId(), - name: req.body.name, - routes: req.body.routes - }; - - delete req.body.name; - delete req.body.routes; - - req.body.roleDetails = roleDetails; - - return next(); -} - -/** - * @function createRole - * @param {{body: {roleDetails: object}}} req - * @param {*} res - * @param {(err?)=>void} next - * @return {void} - * @description - * Creates role document - */ -async function createRole(req, res, next) { - const roleDetails = req.body.roleDetails; - - const role = await Services.Role.createRole(roleDetails); - - if (role) { - delete req.body.roleDetails; - req.body.role = role; - return next(); - } else { - return next({ - status: 500, - message: Constants.Error.ROLE_CREATE_500_MESSAGE, - data: {} - }); - } -} - -module.exports = { - parseRole: parseRole, - createRole: createRole -}; diff --git a/routes/api/role.js b/routes/api/role.js deleted file mode 100644 index 0860d10e..00000000 --- a/routes/api/role.js +++ /dev/null @@ -1,74 +0,0 @@ -"use strict"; - -const express = require("express"); -const Controllers = { - Role: require("../../controllers/role.controller") -}; -const Middleware = { - Auth: require("../../middlewares/auth.middleware"), - Validator: { - Role: require("../../middlewares/validators/role.validator") - }, - parseBody: require("../../middlewares/parse-body.middleware"), - Role: require("../../middlewares/role.middleware") -}; - -module.exports = { - activate: function(apiRouter) { - const roleRouter = express.Router(); - - /** - * @api {post} /api/role/ create a new role - * @apiName createRole - * @apiGroup Role - * @apiVersion 1.1.1 - * - * @apiParam (body) {String} name Name of the route - * @apiParam (body) {Route[]} routes The routes that this role gives access to - * @apiParamExample {Json} application: - * { - "name": "routename", - "routes": [ - { - uri: "/api/hacker/" - requestType: "POST" - } - ] - * } - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data Role object - * @apiSuccessExample {object} Success-Response: - * { - * "message": "Role creation successful", - * "data": { - "name": "routename", - "routes": [ - { - uri: "/api/hacker/" - requestType: "POST" - } - ] - * } - * } - - * @apiError {string} message Error message - * @apiError {object} data empty - * @apiErrorExample {object} Error-Response: - * {"message": "Error while creating role", "data": {}} - */ - roleRouter.route("/").post( - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized(), - - Middleware.Validator.Role.newRoleValidator, - Middleware.parseBody.middleware, - Middleware.Role.parseRole, - - Middleware.Role.createRole, - Controllers.Role.createdRole - ); - - apiRouter.use("/role", roleRouter); - } -}; diff --git a/routes/index.js b/routes/index.js deleted file mode 100755 index 7c95a392..00000000 --- a/routes/index.js +++ /dev/null @@ -1,22 +0,0 @@ -"use strict"; -const express = require("express"); -const versionService = require("../services/version.service"); -const router = new express.Router(); - -/* GET home page. */ -/** - * @api {get} / version - * @apiVersion 0.0.8 - * @apiName index - * @apiGroup Index - * @apiPermission public - */ -router.get("/", function(req, res) { - const VERSION = versionService.get(); - res.status(200).send({ - name: "hackerAPI", - version: VERSION - }); -}); - -module.exports = router; diff --git a/seed/index.js b/seed/index.js deleted file mode 100644 index eb41bcab..00000000 --- a/seed/index.js +++ /dev/null @@ -1,51 +0,0 @@ -"use strict"; -const Constants = { - Role: require("../constants/role.constant"), - Settings: require("../constants/settings.constant") -}; - -const Seed = { - Roles: require("./roles.seed"), - Settings: require("./settings.seed") -}; - -const Services = { - env: require("../services/env.service") -}; -const path = require("path"); - -const envLoadResult = Services.env.load(path.join(__dirname, "../.env")); -if (envLoadResult.error) { - Services.log.error(envLoadResult.error); -} - -const db = require("../services/database.service"); -//connect to db -db.connect(undefined, () => { - onConnected() - .catch((reason) => { - console.error(reason); - process.exit(1); - }) - .then(() => { - process.exit(0); - }); -}); - -//called when the db is connected -async function onConnected() { - await dropAll(); - console.log("Finished dropping"); - await storeAll(); - console.log("Finished seeding"); -} - -async function dropAll() { - await Seed.Roles.dropAll(); - await Seed.Settings.drop(); -} - -async function storeAll() { - await Seed.Roles.storeAll(Constants.Role.allRolesArray); - await Seed.Settings.store(); -} diff --git a/seed/roles.seed.js b/seed/roles.seed.js deleted file mode 100644 index 2e5eb80e..00000000 --- a/seed/roles.seed.js +++ /dev/null @@ -1,28 +0,0 @@ -"use strict"; -const Role = require("../models/role.model"); - -/** - * Drops all elements in Role - */ -function dropAll() { - return Role.deleteMany({}); -} - -/** - * Stores all of the roles in the db - * @param {role[]} attributes all attributes - */ -function storeAll(attributes) { - const roleDocs = []; - const roleNames = []; - attributes.forEach((attribute) => { - roleDocs.push(new Role(attribute)); - roleNames.push(attribute.name); - }); - return Role.collection.insertMany(roleDocs); -} - -module.exports = { - storeAll: storeAll, - dropAll: dropAll -}; diff --git a/seed/settings.seed.js b/seed/settings.seed.js deleted file mode 100644 index 83f0dd9b..00000000 --- a/seed/settings.seed.js +++ /dev/null @@ -1,22 +0,0 @@ -"use strict"; -const Settings = require("../models/settings.model"); - -/** - * Drops all elements in Role - */ -function drop() { - return Settings.deleteMany({}); -} - -/** - * Stores all of the roles in the db - * @param {Settings} setting the setting that we want to seed - */ -function store(setting) { - return Settings.collection.insertOne(new Settings(setting)); -} - -module.exports = { - store: store, - drop: drop -}; diff --git a/services/parsePatch.service.ts b/services/parsePatch.service.ts deleted file mode 100644 index 0a5e3ce1..00000000 --- a/services/parsePatch.service.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Request } from "express"; - -function parsePatch(req: Request, model: Object, done: () => {}) { - setMatchingAttributes(req, model).then(() => { - done(); - }); -} - -async function setMatchingAttributes(req: Request, model: Object) { - let modelDetails: any = {}; - for (const val in req.body) { - if (model.hasOwnProperty(val)) { - modelDetails[val] = req.body[val]; - delete req.body[val]; - } - } - req.body.modelDetails = modelDetails; -} - -export { parsePatch }; diff --git a/services/role.service.ts b/services/role.service.ts deleted file mode 100644 index dc8af54a..00000000 --- a/services/role.service.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { BaseEntity } from "typeorm"; -import Role from "../models/role.model"; -import * as logger from "./logger.service"; - -/** - * @function createRole - * @param {{_id: ObjectId, name: String, routes: route[]}} roleDetails - * @return {Promise} The promise will resolve to a role object if save was successful. - * @description Adds a new role to database. - */ -async function createRole(roleDetails: Object): Promise { - const role = Role.create(roleDetails); - - return await role.save(); -} - -/** - * @function getRole - * @param {string} roleName The name of the role that you're looking for. - * @description - * Returns the role defined by the role name - */ -async function getRole(roleName: string): Promise { - const TAG = "[Role Service # getRole]:"; - - const query = { name: roleName }; - - //get the roleBinding for account - //Populate roles for roleBinding - return await Role.findOne({ where: query }).then((role: Role) => { - logger.queryCallbackFactory(TAG, "role", query); - return role; - }); -} - -/** - * @function getById - * @param {number} identifier The role id - * @description - * Returns the role specified by the id. - */ -async function getById(identifier: number): Promise { - const TAG = "[Role Service # getById]:"; - - //get the roleBinding for account - //Populate roles for roleBinding - return await Role.findOne(identifier).then((role: Role) => { - logger.queryCallbackFactory(TAG, "role", identifier); - return role; - }); -} - -/** - * @function getAll - * @description - * Returns all the roles in the database - */ -async function getAll(): Promise { - const TAG = "[Role Service # getAll]:"; - return Role.find().then((roles) => { - logger.queryCallbackFactory(TAG, "role", {}); - return roles; - }); -} - -export { createRole, getRole, getById, getAll }; diff --git a/services/roleBinding.service.ts b/services/roleBinding.service.ts deleted file mode 100644 index d6c767c0..00000000 --- a/services/roleBinding.service.ts +++ /dev/null @@ -1,130 +0,0 @@ -import RoleBinding from "../models/roleBinding.model"; -import { getById as getRoleById, getRole } from "./role.service"; -import { findById as findAccountById } from "./account.service"; -import { UpdateResult } from "typeorm"; -import Role from "../models/role.model"; -const logger = require("./logger.service"); - -/** - * Creates a rolebinding between an account and a role. Appends to an existing rolebinding if one already exists - * @param {number} accountId the id of the account that you want to add a rolebinding to - * @param {number} roleId the id of the role that you want to add - */ -async function createRoleBinding(accountId: number, roleId?: any) { - const TAG = "[RoleBinding Service # createRoleBinding]:"; - const query = { - accountId: accountId - }; - const roleBindingModel = await getRoleBindingForAcct(accountId); - if (!roleBindingModel) { - const roleArray = roleId ? [roleId] : []; - const newRb = RoleBinding.create({ - account: await findAccountById(accountId), - roles: roleArray - }); - return newRb.save(); - } else { - // This code is terrible. - if (roleId == undefined) return undefined; - const role = await getRoleById(roleId); - if (role == undefined) return undefined; - roleBindingModel.roles.push(); - return RoleBinding.update( - roleBindingModel.identifier, - roleBindingModel - ).then((value: UpdateResult) => { - logger.queryCallbackFactory(TAG, "roleBinding", query); - return value; - }); - } -} - -/** - * Attempts to find a rolebinding given the role name and adds it to the account - * @param {ObjectId} accountId the id of the account that you want to add a rolebinding to - * @param {String} roleName the name of the role that you want to add - */ -async function createRoleBindingByRoleName( - accountId: number, - roleName: string -) { - const role = await getRole(roleName); - if (role === undefined) return undefined; - await createRoleBinding(accountId, role.identifier); -} - -/** - * Removes a role from a rolebinding for a given account. - * @param {ObjectId} accountId the id of the account that you want to remove a rolebinding from - * @param {ObjectId} roleId the id of the role that you want to remove - */ -async function removeRoleBinding(accountId: number, roleId: number) { - const TAG = "[RoleBinding Service # removeRoleBinding]:"; - const roleBindingModel = await getRoleBindingForAcct(accountId); - const role = await getRoleById(roleId); - if ( - roleBindingModel === undefined || - role === undefined || - roleId == undefined - ) - return undefined; - delete roleBindingModel.roles[roleBindingModel.roles.indexOf(role)]; - return RoleBinding.update( - roleBindingModel.identifier, - roleBindingModel - ).then((value: UpdateResult) => { - logger.queryCallbackFactory( - TAG, - "roleBinding", - roleBindingModel.identifier - ); - return value; - }); -} - -/** - * @async - * @function getRoleBindingForAcct - * @param {string} accountId The id of the account that you want the role bindings for. - * @returns {Promise} - * @description - * Gets the roleBinding for a given account. Populates the role array as well with the Roles. - */ -async function getRoleBindingForAcct(accountId: number) { - const TAG = "[RoleBinding Service # getRoleBindings]:"; - const query = {}; - //get the roleBinding for account - //Populate roles for roleBinding - - return RoleBinding.findOne({ - where: { account: await findAccountById(accountId) } - }).then((roleBinding) => { - logger.queryCallbackFactory(TAG, "roleBinding", "accountId"); - return roleBinding; - }); -} - -/** - * @async - * @function getById - * @param {ObjectId} id The rolebinding id - * @description - * Returns the roleBinding specified by the id. - */ -async function getById(identifier: number) { - const TAG = "[RoleBinding Service # getById]:"; - //get the roleBinding for account - //Populate roles for roleBinding - return await RoleBinding.findOne(identifier).then((roleBinding) => { - logger.queryCallbackFactory(TAG, "roleBinding", identifier); - return roleBinding; - }); -} - -module.exports = { - getRoleBindingForAcct: getRoleBindingForAcct, - getById: getById, - createRoleBinding: createRoleBinding, - createRoleBindingByRoleName: createRoleBindingByRoleName, - removeRoleBinding: removeRoleBinding -}; From 49c9c87a0af0c5fe51ece78fb6d3fe7ab07f0b86 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Wed, 22 Dec 2021 23:22:16 -0500 Subject: [PATCH 12/72] refactor: remove models for the deleted services in the previous commit. --- models/emailTemplate.model.ts | 19 ------------------- models/role.model.ts | 33 --------------------------------- models/roleBinding.model.ts | 33 --------------------------------- 3 files changed, 85 deletions(-) delete mode 100644 models/emailTemplate.model.ts delete mode 100644 models/role.model.ts delete mode 100644 models/roleBinding.model.ts diff --git a/models/emailTemplate.model.ts b/models/emailTemplate.model.ts deleted file mode 100644 index 21dcf67b..00000000 --- a/models/emailTemplate.model.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Entity, BaseEntity, Column, PrimaryGeneratedColumn } from "typeorm"; - -@Entity() -class EmailTemplate extends BaseEntity { - @PrimaryGeneratedColumn() - identifier: number; - - @Column({ nullable: false }) - name: string; - - @Column({ nullable: false }) - content: string; - - toJSON() { - return this; - } -} - -export default EmailTemplate; diff --git a/models/role.model.ts b/models/role.model.ts deleted file mode 100644 index cc8346fb..00000000 --- a/models/role.model.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Entity, BaseEntity, Column, PrimaryGeneratedColumn } from "typeorm"; -const Constants = require("../constants/general.constant"); - -export interface RouteSchema { - uri: string; - requestType: string; - // TODO: Above type is a enum: Object.values(Constants.REQUEST_TYPES)} -} - -/** - * The name is descriptive of the role - * Each role may have different routes, where route parameters in the uri are replaced with :self or :all - */ -@Entity() -class Role extends BaseEntity { - @PrimaryGeneratedColumn() - identifier: number; - - // The name should be something like "hacker", or "sponsor". - // For roles with singular routes, the name of the role will be the name of the route plus the api route - // For example, "getSelfAccount" - @Column({ unique: true, nullable: false }) - name: string; - - @Column("jsonb", { nullable: false }) - routes: RouteSchema[]; - - toJSON() { - return this; - } -} - -export default Role; diff --git a/models/roleBinding.model.ts b/models/roleBinding.model.ts deleted file mode 100644 index abcf685e..00000000 --- a/models/roleBinding.model.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { - Entity, - BaseEntity, - OneToOne, - ManyToOne, - JoinColumn, - Column, - PrimaryGeneratedColumn -} from "typeorm"; -import Account from "./account.model"; -import Role from "./role.model"; - -@Entity() -class RoleBinding extends BaseEntity { - @PrimaryGeneratedColumn() - identifier: number; - - @OneToOne(() => Account) - @JoinColumn() - //@Column({ nullable: false, unique: true }) - account: Account; - - //TODO: This might be broken. (OneToMany?) - @ManyToOne(() => Role) - @JoinColumn() - roles: Role[]; - - toJSON() { - return this; - } -} - -export default RoleBinding; From fd2d47b00106cd48ad66b693356e09328e788d1f Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Wed, 22 Dec 2021 23:26:41 -0500 Subject: [PATCH 13/72] refactor: remove .idea files from .gitignore. --- .gitignore | 56 +----------------------------------------------------- 1 file changed, 1 insertion(+), 55 deletions(-) diff --git a/.gitignore b/.gitignore index 8910be12..69842024 100755 --- a/.gitignore +++ b/.gitignore @@ -1,57 +1,3 @@ -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff -.idea/**/workspace.xml -.idea/**/tasks.xml -.idea/**/dictionaries -.idea/**/shelf - -# Sensitive or high-churn files -.idea/**/dataSources/ -.idea/**/dataSources.ids -.idea/**/dataSources.local.xml -.idea/**/sqlDataSources.xml -.idea/**/dynamic.xml -.idea/**/uiDesigner.xml - -# Gradle -.idea/**/gradle.xml -.idea/**/libraries - -# CMake -cmake-build-debug/ -cmake-build-release/ - -# Mongo Explorer plugin -.idea/**/mongoSettings.xml - -# File-based project format -*.iws - -# IntelliJ -out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Cursive Clojure plugin -.idea/replstate.xml - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties - -# Editor-based Rest Client -.idea/httpRequests - -# Root Idea Folder - # Node JS node_modules @@ -64,7 +10,7 @@ gcp_creds.json #certbot certbot/ -assets/.DS_Store +.DS_Store #secrets secret.yaml From f2efdaf8b289911db0fdc0dc773fe281ce041e21 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Wed, 22 Dec 2021 23:31:57 -0500 Subject: [PATCH 14/72] refactor: change e-mail service to use nodemailer. - BENEFITS: - prevent's vendor lock-in as before we were using sendgrid's proprietary library. - this will help prevent incidents such as what occurred on december 1st - 7th. - in essence allow's us to use any smtp mailing service as long as we swap the information in the .env file. - allow's developers to catch mail using mailcatcher, mailtrap, etc... - (no longer having to distribute sendgrid key to devs) - no longer have to go to the database to get account confirmation tokens, or password reset tokens. - TODO: - implement a *.mailer.ts pattern. - authentication.mailer.ts - send forgot password, account confirmation, etc... - BENEFITS: - will clean up the code in the controller layer. - will establish clean boundaries between the mailing layer and controller layer, improving the codebase overall. --- services/email.service.ts | 185 ++++++++------------------------------ 1 file changed, 39 insertions(+), 146 deletions(-) diff --git a/services/email.service.ts b/services/email.service.ts index 473f5394..351ed9d5 100644 --- a/services/email.service.ts +++ b/services/email.service.ts @@ -1,162 +1,55 @@ -import client from "@sendgrid/mail"; import { readFileSync } from "fs"; -import { join } from "path"; -const Constants = require("../constants/general.constant"); -import * as Handlebars from "handlebars"; import { autoInjectable } from "tsyringe"; import { EnvService } from "./env.service"; +import { createTransport } from "nodemailer"; +import { compile } from "handlebars"; +import mjml2html from "mjml"; +import { LoggerService } from "./logger.service"; @autoInjectable() export class EmailService { - constructor(private readonly envService: EnvService) { - client.setApiKey(this.envService.get("SENDGRID_API_KEY") ?? ""); - } + protected readonly mailer; - /** - * Send one email - * @param {*} mailData - * @param {(err?)=>void} callback - */ - send(mailData: any, callback = (error?: Object) => {}) { - if (this.envService.isTest()) { - //Silence all actual emails if we're testing - mailData.mailSettings = { - sandboxMode: { - enable: true - } - }; - } - return client - .send(mailData, false) - .then((response) => { - callback(); - return response; - }) - .catch((error) => { - callback(error); - }); - } - /** - * Send separate emails to the list of users in mailData - * @param {*} mailData - * @param {(err?)=>void} callback - */ - sendMultiple(mailData: any, callback = (error?: Object) => {}) { - return client - .sendMultiple(mailData) - .then((response) => { - callback(); - return response; - }) - .catch((error) => { - callback(error); - }); - } - /** - * Send email with ticket. - * @param {string} firstName the recipient's first name - * @param {string} recipient the recipient's email address - * @param {string} ticket the ticket image (must be base-64 string) - * @param {(err?)=>void} callback - */ - sendWeekOfEmail( - firstName: string, - recipient: string, - ticket: string, - callback = (error?: Object) => {} + constructor( + private readonly envService: EnvService, + private readonly loggerService: LoggerService ) { - const handlebarsPath = join(__dirname, `../assets/email/Ticket.hbs`); - const html = this.renderEmail(handlebarsPath, { - firstName: firstName, - ticket: ticket - }); - const mailData = { - to: recipient, - from: this.envService.get("NO_REPLY_EMAIL"), - subject: Constants.EMAIL_SUBJECTS[Constants.WEEK_OF], - html: html - }; - this.send(mailData).then((response) => { - if ( - !response || - (response[0].statusCode >= 200 && response[0].statusCode < 300) - ) { - callback(); - } else { - callback(response[0]); + this.mailer = createTransport({ + host: this.getEmailAttribute("HOST"), + port: parseInt(this.getEmailAttribute("PORT")!), + auth: { + user: this.getEmailAttribute("USERNAME"), + pass: this.getEmailAttribute("PASSWORD") } - }, callback); - } - /** - * Send email with ticket. - * @param {string} firstName the recipient's first name - * @param {string} recipient the recipient's email address - * @param {(err?)=>void} callback - */ - sendDayOfEmail( - firstName: string, - recipient: string, - callback = (error?: Object) => {} - ) { - const handlebarsPath = join(__dirname, `../assets/email/Welcome.hbs`); - const html = this.renderEmail(handlebarsPath, { - firstName: firstName }); - const mailData = { - to: recipient, - from: this.envService.get("NO_REPLY_EMAIL"), - subject: Constants.EMAIL_SUBJECTS[Constants.WEEK_OF], - html: html - }; - this.send(mailData).then((response) => { - if ( - !response || - (response[0].statusCode >= 200 && response[0].statusCode < 300) - ) { - callback(); - } else { - callback(response[0]); - } - }, callback); + this.mailer + .verify() + .catch((error) => + this.loggerService + .getLogger() + .error(`Failed to connect to SMTP server. Error: ${error}`) + ); } - sendStatusUpdate( - firstName: string, - recipient: string, - status: string, - callback = (error?: Object) => {} - ) { - const handlebarsPath = join( - __dirname, - `../assets/email/statusEmail/${status}.hbs` - ); - const mailData = { - to: recipient, - from: this.envService.get("NO_REPLY_EMAIL"), - subject: Constants.EMAIL_SUBJECTS[status], - html: this.renderEmail(handlebarsPath, { - firstName: firstName + public async send({ ...args }: any, { ...context }: any, callback?: any) { + args.from = this.envService.get("NO_REPLY_EMAIL"); + if (args.html) + args.html = compile( + mjml2html(readFileSync(args.html, "utf-8")).html + )(context); + await this.mailer + .sendMail({ + ...args, + from: this.envService.get("NO_REPLY_EMAIL") }) - }; - this.send(mailData).then((response) => { - if ( - !response || - (response[0].statusCode >= 200 && response[0].statusCode < 300) - ) { - callback(); - } else { - callback(response[0]); - } - }, callback); + .catch((error) => callback(error)); } - /** - * Generates the HTML from the handlebars template file found at the given path. - * @param {string} path the absolute path to the handlebars template file - * @param {*} context any variables that need to be replaced in the template file - */ - renderEmail(path: string, context: Object) { - const templateStr = readFileSync(path).toString(); - const template = Handlebars.compile(templateStr); - return template(context); + + private getEmailAttribute(name: string) { + return this.envService.isDevelopment() + ? this.envService.get(`EMAIL_${name}_DEV`) + : this.envService.isProduction() + ? this.envService.get(`EMAIL_${name}_DEPLOY`) + : this.envService.get(`EMAIL_${name}_TEST`); } } From ff0da1635e0990d2c43c31cc6a941f7fe60f59b7 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Wed, 22 Dec 2021 23:41:43 -0500 Subject: [PATCH 15/72] fix: spelling error in function to retrieve database information. --- services/database.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/database.service.ts b/services/database.service.ts index 9235ca83..afac54ad 100644 --- a/services/database.service.ts +++ b/services/database.service.ts @@ -23,7 +23,7 @@ export class DatabaseService { private getDatabaseAttribute(name: string) { return this.envService.isDevelopment() - ? this.envService.get(`DB_${name}_ENV`) + ? this.envService.get(`DB_${name}_DEV`) : this.envService.isProduction() ? this.envService.get(`DB_${name}_DEPLOY`) : this.envService.get(`DB_${name}_TEST`); From a8d661cb960bf1e34a605cb4092b30f27640c49e Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Wed, 22 Dec 2021 23:49:48 -0500 Subject: [PATCH 16/72] refactor: update environment setup file. - remove unnecessary dependencies. - mongo - kube-ctl - docker - gcloud-sdk - remove npm version & install (node comes packaged with npm). - add postgresql --- setupEnv.sh | 62 +++++------------------------------------------------ 1 file changed, 5 insertions(+), 57 deletions(-) diff --git a/setupEnv.sh b/setupEnv.sh index 689ef4aa..1e0a36c7 100644 --- a/setupEnv.sh +++ b/setupEnv.sh @@ -2,7 +2,6 @@ # Some of this was taken from https://gist.github.com/phatblat/1713458 -NPM_VERSION=6.4.0 NODE_VERSION=`cat .nvmrc` # Save script's current directory DIR="$( cd -P "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" @@ -41,70 +40,19 @@ fi curDir=$PWD cd /tmp -# -# Check if Node Package Manager is installed and at the right version -# -echo "Checking for NPM version ${NPM_VERSION}" -npm --version || grep ${NPM_VERSION} -if [[ $? != 0 ]] ; then - echo "Downloading npm" - git clone git://github.com/isaacs/npm.git && cd npm - git checkout v${NPM_VERSION} - make install -fi - cd $curDir # # MongoDB # -if brew ls --versions mongo > /dev/null; then - # The package is installed! - echo "Mongo already installed." -else - # The package is not installed - brew install mongodb - echo 'Creating a folder for mongodb at /data/db. Please enter password.' - sudo mkdir -p /data/db - echo 'Setting up proper permissions for /data/db. Please enter password.' - sudo chown -R `id -un` /data/db -fi - -if brew ls --versions docker > /dev/null; then - # The package is installed! - echo "Docker already installed." -else - # The package is not installed - echo "Installing Docker..." - curl -fsSL get.docker.com -o ${DIR}/get-docker.sh - sh get-docker.sh -fi - -# -# Kubectl -# -if brew ls --versions kubernetes-cli > /dev/null; then +if brew ls --versions postgres > /dev/null; then # The package is installed! - echo "kubernetes-cli already installed." + echo "PostgreSQL already installed." else # The package is not installed - echo "Installing kubernetes-cli..." - brew install kubernetes-cli -fi - -# -# gcloud -# -which -s gcloud -if [[ $? != 0 ]]; then - # The package is not installed - echo "Installing gcloud..." - brew tap caskroom/cask - brew cask install google-cloud-sdk -else - # The package is installed! - echo "gcloud already installed." + echo "Installing PostgreSQL..." + brew install postgres fi # @@ -121,4 +69,4 @@ fi # NPM install # echo "installing npm modules." -npm install \ No newline at end of file +npm install From 2d6c0739f2b66b4590bf64632ddeb4239aff58e4 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Sat, 25 Dec 2021 12:48:31 -0500 Subject: [PATCH 17/72] feat: add MIT license. --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..6ed545f9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 HackMcGill + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 6170f471d618cdca09412704dc65f236d4422bc0 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Sat, 25 Dec 2021 21:52:32 -0500 Subject: [PATCH 18/72] refactor: remove unnecessary models, controllers, and services. - remove settings functionality and figure out how to implement it better later. - remove volunteer & staff models as we do not store any special fields. --- constants/role.constant.js | 223 ---------------------------- constants/settings.constant.js | 39 ----- constants/testMongoId.constant.js | 30 ---- controllers/settings.controller.js | 36 ----- controllers/sponsor.controller.js | 58 -------- controllers/travel.controller.js | 66 -------- controllers/volunteer.controller.js | 43 ------ middlewares/settings.middleware.js | 135 ----------------- middlewares/volunteer.middleware.js | 151 ------------------- models/staff.model.ts | 7 - models/volunteer.model.ts | 7 - routes/api/settings.js | 91 ------------ routes/api/volunteer.js | 104 ------------- scripts/migrate_email_templates.js | 68 --------- services/auth.service.ts | 209 -------------------------- services/settings.service.ts | 43 ------ services/version.service.ts | 7 - services/volunteer.service.ts | 45 ------ 18 files changed, 1362 deletions(-) delete mode 100644 constants/role.constant.js delete mode 100644 constants/settings.constant.js delete mode 100644 constants/testMongoId.constant.js delete mode 100644 controllers/settings.controller.js delete mode 100644 controllers/sponsor.controller.js delete mode 100644 controllers/travel.controller.js delete mode 100644 controllers/volunteer.controller.js delete mode 100644 middlewares/settings.middleware.js delete mode 100644 middlewares/volunteer.middleware.js delete mode 100644 models/staff.model.ts delete mode 100644 models/volunteer.model.ts delete mode 100644 routes/api/settings.js delete mode 100644 routes/api/volunteer.js delete mode 100644 scripts/migrate_email_templates.js delete mode 100644 services/auth.service.ts delete mode 100644 services/settings.service.ts delete mode 100644 services/version.service.ts delete mode 100644 services/volunteer.service.ts diff --git a/constants/role.constant.js b/constants/role.constant.js deleted file mode 100644 index 55d59205..00000000 --- a/constants/role.constant.js +++ /dev/null @@ -1,223 +0,0 @@ -"use strict"; -const Constants = { - General: require("./general.constant"), - Routes: require("./routes.constant") -}; - -const accountRole = { - identifier: 0, - name: "account", - routes: [ - Constants.Routes.authRoutes.login, - Constants.Routes.authRoutes.logout, - Constants.Routes.authRoutes.changePassword, - Constants.Routes.authRoutes.getSelfRoleBindindings, - Constants.Routes.accountRoutes.getSelf, - Constants.Routes.accountRoutes.getSelfById, - Constants.Routes.accountRoutes.patchSelfById, - Constants.Routes.settingsRoutes.getSettings - ] -}; - -const adminRole = { - identifier: 1, - name: Constants.General.STAFF, - routes: Constants.Routes.listAllRoutes() -}; - -const hackerRole = { - identifier: 2, - name: Constants.General.HACKER, - routes: [ - Constants.Routes.hackerRoutes.post, - Constants.Routes.hackerRoutes.getSelfById, - Constants.Routes.hackerRoutes.getSelfByEmail, - Constants.Routes.hackerRoutes.getSelfResumeById, - Constants.Routes.hackerRoutes.patchSelfById, - Constants.Routes.hackerRoutes.patchSelfConfirmationById, - Constants.Routes.hackerRoutes.getSelf, - - Constants.Routes.travelRoutes.getSelf, - Constants.Routes.travelRoutes.getSelfById, - Constants.Routes.travelRoutes.getSelfByEmail, - - Constants.Routes.teamRoutes.join, - Constants.Routes.teamRoutes.patchSelfById, - Constants.Routes.teamRoutes.post, - Constants.Routes.teamRoutes.get, - Constants.Routes.teamRoutes.leave - ] -}; - -const volunteerRole = { - identifier: 3, - name: Constants.General.VOLUNTEER, - routes: [ - Constants.Routes.volunteerRoutes.getSelfById, - Constants.Routes.volunteerRoutes.post, - - Constants.Routes.hackerRoutes.patchAnyCheckInById, - Constants.Routes.hackerRoutes.patchSelfCheckInById, - - Constants.Routes.teamRoutes.get - ] -}; - -const sponsorT1Role = { - identifier: 4, - name: Constants.General.SPONSOR_T1, - routes: [ - Constants.Routes.sponsorRoutes.post, - Constants.Routes.sponsorRoutes.getSelfById, - Constants.Routes.sponsorRoutes.getSelf, - Constants.Routes.sponsorRoutes.patchSelfById, - - Constants.Routes.searchRoutes.get, - Constants.Routes.accountRoutes.getAnyById, - Constants.Routes.hackerRoutes.getAnyById - ] -}; - -const sponsorT2Role = { - identifier: 5, - name: Constants.General.SPONSOR_T2, - routes: [ - Constants.Routes.sponsorRoutes.post, - Constants.Routes.sponsorRoutes.getSelfById, - Constants.Routes.sponsorRoutes.getSelf, - Constants.Routes.sponsorRoutes.patchSelfById, - - Constants.Routes.searchRoutes.get, - Constants.Routes.accountRoutes.getAnyById, - Constants.Routes.hackerRoutes.getAnyById - ] -}; - -const sponsorT3Role = { - identifier: 6, - name: Constants.General.SPONSOR_T3, - routes: [ - Constants.Routes.sponsorRoutes.post, - Constants.Routes.sponsorRoutes.getSelfById, - Constants.Routes.sponsorRoutes.getSelf, - Constants.Routes.sponsorRoutes.patchSelfById, - - Constants.Routes.searchRoutes.get, - Constants.Routes.accountRoutes.getAnyById, - Constants.Routes.hackerRoutes.getAnyById - ] -}; - -const sponsorT4Role = { - identifier: 7, - name: Constants.General.SPONSOR_T4, - routes: [ - Constants.Routes.sponsorRoutes.post, - Constants.Routes.sponsorRoutes.getSelfById, - Constants.Routes.sponsorRoutes.getSelf, - Constants.Routes.sponsorRoutes.patchSelfById, - - Constants.Routes.searchRoutes.get, - Constants.Routes.accountRoutes.getAnyById, - Constants.Routes.hackerRoutes.getAnyById - ] -}; - -const sponsorT5Role = { - identifier: 8, - name: Constants.General.SPONSOR_T5, - routes: [ - Constants.Routes.sponsorRoutes.post, - Constants.Routes.sponsorRoutes.getSelfById, - Constants.Routes.sponsorRoutes.getSelf, - Constants.Routes.sponsorRoutes.patchSelfById, - - Constants.Routes.searchRoutes.get, - Constants.Routes.accountRoutes.getAnyById, - Constants.Routes.hackerRoutes.getAnyById - ] -}; - -const singularRoles = createAllSingularRoles(); -const allRolesObject = createAllRoles(); -const allRolesArray = Object.values(allRolesObject); - -/** - * Creates all the roles that are of a specific uri and request type - * @return {Role[]} - */ -function createAllSingularRoles() { - const allRoutes = Constants.Routes.allRoutes; - let roles = []; - - for (let routeGroupKey in allRoutes) { - if (!Object.prototype.hasOwnProperty.call(allRoutes, routeGroupKey)) { - continue; - } - - const routeGroup = allRoutes[routeGroupKey]; - for (let routeKey in routeGroup) { - // Iterating through the attributes in the routeGroup object - if (!Object.prototype.hasOwnProperty.call(routeGroup, routeKey)) { - // Avoid all prototype attributes - continue; - } - - let role = { - _id: routeGroup[routeKey]._id, - name: routeKey + routeGroupKey, - routes: routeGroup[routeKey] - }; - let roleName = role.name; - roles[roleName] = role; - } - } - - return roles; -} - -/** - * creates object with all the roles, both singular and of a type (ex hacker) - * @return {*} - */ -function createAllRoles() { - let allRolesObject = { - accountRole: accountRole, - adminRole: adminRole, - hackerRole: hackerRole, - volunteerRole: volunteerRole, - sponsorT1Role: sponsorT1Role, - sponsorT2Role: sponsorT2Role, - sponsorT3Role: sponsorT3Role, - sponsorT4Role: sponsorT4Role, - sponsorT5Role: sponsorT5Role - }; - - const singularRoles = createAllSingularRoles(); - for (let role in singularRoles) { - if (!Object.prototype.hasOwnProperty.call(singularRoles, role)) { - continue; - } - allRolesObject[role] = singularRoles[role]; - } - - return allRolesObject; -} - -module.exports = { - accountRole: accountRole, - adminRole: adminRole, - hackerRole: hackerRole, - volunteerRole: volunteerRole, - sponsorT1Role: sponsorT1Role, - sponsorT2Role: sponsorT2Role, - sponsorT3Role: sponsorT3Role, - sponsorT4Role: sponsorT4Role, - sponsorT5Role: sponsorT5Role, - - singularRoles: singularRoles, - allRolesObject: allRolesObject, - allRolesArray: allRolesArray, - createAllSingularRoles: createAllSingularRoles, - createAllRoles: createAllRoles -}; diff --git a/constants/settings.constant.js b/constants/settings.constant.js deleted file mode 100644 index ee0df49b..00000000 --- a/constants/settings.constant.js +++ /dev/null @@ -1,39 +0,0 @@ -const APP_NOT_YET_OPEN = { - openTime: new Date(Date.now() + 100000000000), - closeTime: new Date(Date.now() + 10000000000000000), - confirmTime: new Date(Date.now() + 100000000000000000) -}; - -const APP_OPEN = { - openTime: new Date(Date.now() - 100), - closeTime: new Date(Date.now() + 10000000000), - confirmTime: new Date(Date.now() + 100000000000000) -}; - -const APP_CLOSED = { - openTime: new Date(Date.now() - 100), - closeTime: new Date(Date.now() - 1000), - confirmTime: new Date(Date.now() + 100000000000000) -}; - -const CONFIRM_CLOSED = { - openTime: new Date(Date.now() - 10000), - closeTime: new Date(Date.now() - 1000), - confirmTime: new Date(Date.now() - 100) -}; - -const REMOTE_HACKATHON = { - openTime: new Date(Date.now() - 100), - closeTime: new Date(Date.now() + 10000000000), - confirmTime: new Date(Date.now() + 100000000000000), - isRemote: true -}; - -// Some utility dates that are used in tests and seed script -module.exports = { - APP_NOT_YET_OPEN: APP_NOT_YET_OPEN, - APP_OPEN: APP_OPEN, - APP_CLOSED: APP_CLOSED, - CONFIRM_CLOSED: CONFIRM_CLOSED, - REMOTE_HACKATHON: REMOTE_HACKATHON -}; diff --git a/constants/testMongoId.constant.js b/constants/testMongoId.constant.js deleted file mode 100644 index 78cd4258..00000000 --- a/constants/testMongoId.constant.js +++ /dev/null @@ -1,30 +0,0 @@ -"use strict"; - -const mongoose = require("mongoose"); - -const team1Id = mongoose.Types.ObjectId(); -const team2Id = mongoose.Types.ObjectId(); -const team3Id = mongoose.Types.ObjectId(); - -const hackerAId = mongoose.Types.ObjectId(); -const hackerBId = mongoose.Types.ObjectId(); -const hackerCId = mongoose.Types.ObjectId(); -const hackerDId = mongoose.Types.ObjectId(); -const hackerEId = mongoose.Types.ObjectId(); -const hackerFId = mongoose.Types.ObjectId(); -const hackerGId = mongoose.Types.ObjectId(); -const hackerHId = mongoose.Types.ObjectId(); - -module.exports = { - team1Id: team1Id, - team2Id: team2Id, - team3Id: team3Id, - hackerAId: hackerAId, - hackerBId: hackerBId, - hackerCId: hackerCId, - hackerDId: hackerDId, - hackerEId: hackerEId, - hackerFId: hackerFId, - hackerGId: hackerGId, - hackerHId: hackerHId -}; diff --git a/controllers/settings.controller.js b/controllers/settings.controller.js deleted file mode 100644 index dce3e5e7..00000000 --- a/controllers/settings.controller.js +++ /dev/null @@ -1,36 +0,0 @@ -"use strict"; - -const Success = require("../constants/success.constant"); - -/** - * @function gotSettings - * @param {{body: {settingsDetails: Object}}} req - * @param {*} res - * @return {JSON} Success status and settings object - * @description Returns the JSON of settings object located in req.body.settingsDetails - */ -function gotSettings(req, res) { - return res.status(200).json({ - message: Success.SETTINGS_GET, - data: req.body.settingsDetails.toJSON() - }); -} - -/** - * @function patchedSettings - * @param {{body: {settingsDetails: Object}}} req - * @param {*} res - * @return {JSON} Success status and settings object - * @description Returns the JSON of settings object located in req.body.settingsDetails - */ -function patchedSettings(req, res) { - return res.status(200).json({ - message: Success.SETTINGS_PATCH, - data: req.body.settingsDetails - }); -} - -module.exports = { - gotSettings: gotSettings, - patchedSettings: patchedSettings -}; diff --git a/controllers/sponsor.controller.js b/controllers/sponsor.controller.js deleted file mode 100644 index fb0d2199..00000000 --- a/controllers/sponsor.controller.js +++ /dev/null @@ -1,58 +0,0 @@ -"use strict"; -const Services = { - Sponsor: require("../services/sponsor.service"), - Logger: require("../services/logger.service") -}; -const Util = require("../middlewares/util.middleware"); -const Constants = { - Success: require("../constants/success.constant"), - Error: require("../constants/error.constant") -}; - -/** - * @function showSponsor - * @param {{body: {sponsor: Object}}} req - * @param {*} res - * @return {JSON} Success status and sponsor object - * @description Returns the JSON of sponsor object located in req.body.sponsor - */ -function showSponsor(req, res) { - return res.status(200).json({ - message: Constants.Success.SPONSOR_READ, - data: req.body.sponsor.toJSON() - }); -} - -/** - * @function createdSponsor - * @param {{body: {sponsor: {_id: ObjectId, accountId: ObjectId, tier: number, company: string, contractURL: string, nominees: ObjectId[]}}}} req - * @param {*} res - * @return {JSON} Success status - * @description returns success message - */ -function createdSponsor(req, res) { - return res.status(200).json({ - message: Constants.Success.SPONSOR_CREATE, - data: req.body.sponsor.toJSON() - }); -} - -/** - * @function updatedSponsor - * @param {{body: {sponsor: {_id: ObjectId, accountId: ObjectId, tier: number, company: string, contractURL: string, nominees: ObjectId[]}}}} req - * @param {*} res - * @return {JSON} Success status - * @description returns success message - */ -function updatedSponsor(req, res) { - return res.status(200).json({ - message: Constants.Success.SPONSOR_UPDATE, - data: req.body.sponsor.toJSON() - }); -} - -module.exports = { - createdSponsor: createdSponsor, - showSponsor: showSponsor, - updatedSponsor: updatedSponsor -}; diff --git a/controllers/travel.controller.js b/controllers/travel.controller.js deleted file mode 100644 index d69a50a7..00000000 --- a/controllers/travel.controller.js +++ /dev/null @@ -1,66 +0,0 @@ -"use strict"; -const Constants = { - Success: require("../constants/success.constant"), - Error: require("../constants/error.constant") -}; - -function okay(req, res) { - return res.status(200).json({ - message: "good" - }); -} - -/** - * @function showTravel - * @param {{body: {travel: Object}}} req - * @param {*} res - * @return {JSON} Success status and travel object - * @description Returns the JSON of travel object located in req.body.travel - */ -function showTravel(req, res) { - return res.status(200).json({ - message: Constants.Success.TRAVEL_READ, - data: req.body.travel.toJSON() - }); -} - -/** - * @function createTravel - * @param {{body: {travel: {_id: ObjectId, accountId: ObjectId, hackerId: objectId, status: string, request: number, offer: number}}}} req - * @param {*} res - * @return {JSON} Success status - * @description - * Create a travel's record based off information stored in req.body.travel - * Returns a 200 status for the created travel. - */ -function createdTravel(req, res) { - return res.status(200).json({ - message: Constants.Success.TRAVEL_CREATE, - data: req.body.travel.toJSON() - }); -} - -/** - * @function updatedTravel - * @param {{params: {id: ObjectId}, body: {Object}}} req - * @param {*} res - * @return {JSON} Success or error status - * @description - * Change a travel's information based on the trave;'s mongoID specified in req.params.id. - * The id is moved to req.body.id from req.params.id by validation. - * Returns a 200 status for an updated travel. - * The new information is located in req.body. - */ -function updatedTravel(req, res) { - return res.status(200).json({ - message: Constants.Success.TRAVEL_UPDATE, - data: req.body - }); -} - -module.exports = { - okay: okay, - showTravel: showTravel, - updatedTravel: updatedTravel, - createdTravel: createdTravel -}; diff --git a/controllers/volunteer.controller.js b/controllers/volunteer.controller.js deleted file mode 100644 index 316c0a00..00000000 --- a/controllers/volunteer.controller.js +++ /dev/null @@ -1,43 +0,0 @@ -"use strict"; -const Services = { - Volunteer: require("../services/volunteer.service"), - Logger: require("../services/logger.service") -}; -const Util = require("../middlewares/util.middleware"); -const Constants = { - Success: require("../constants/success.constant"), - Error: require("../constants/error.constant") -}; - -/** - * @function createdVolunteer - * @param {{body: {volunteer: {_id: ObjectId, accountId: ObjectId}}}} req - * @param {*} res - * @return {JSON} Success status - * @description Show the success message and the created volunteer - */ -function createdVolunteer(req, res) { - return res.status(200).json({ - message: Constants.Success.VOLUNTEER_CREATE, - data: req.body.volunteer - }); -} - -/** - * @function showVolunteer - * @param {{body: {volunteer: {_id: ObjectId, accountId: ObjectId}}}} req - * @param {*} res - * @return {JSON} Success status - * @description Show the success message and retrieved volunteer - */ -function showVolunteer(req, res) { - return res.status(200).json({ - message: Constants.Success.VOLUNTEER_GET_BY_ID, - data: req.body.volunteer.toJSON() - }); -} - -module.exports = { - createdVolunteer: createdVolunteer, - showVolunteer: showVolunteer -}; diff --git a/middlewares/settings.middleware.js b/middlewares/settings.middleware.js deleted file mode 100644 index 4dcc11b4..00000000 --- a/middlewares/settings.middleware.js +++ /dev/null @@ -1,135 +0,0 @@ -const Services = { - Settings: require("../services/settings.service"), - Account: require("../services/account.service") -}; -const Middleware = { - Util: require("./util.middleware") -}; -const Constants = { - Error: require("../constants/error.constant") -}; -const Settings = require("../models/settings.model"); - -/** - * @function parsePatch - * @param {body: *} req - * @param {*} res - * @param {(err?) => void} next - * @return {void} - * @description Put relevent settings attributes into settingsDetails - */ -function parsePatch(req, res, next) { - let settingsDetails = {}; - - for (const val in req.body) { - // use .hasOwnProperty instead of 'in' to get rid of inherited properties such as 'should' - if (Settings.schema.paths.hasOwnProperty(val)) { - settingsDetails[val] = req.body[val]; - delete req.body[val]; - } - } - - req.body.settingsDetails = settingsDetails; - return next(); -} - -/** - * @function updateSettings - * @param {body: *} req - * @param {*} res - * @param {(err?) => void} next - * @return {void} - * @description Update settings object - */ -async function updateSettings(req, res, next) { - const settings = await Services.Settings.updateSettings( - req.body.settingsDetails - ); - if (!settings) { - return next({ - status: 500, - message: Constants.Error.GENERIC_500_MESSAGE - }); - } else { - next(); - } -} - -/** - * @function confirmValidPatch - * @param {{body:{settingsDetails:{openTime:Date, closeTime:Date, confirmTime:Date, isRemote: Boolean}}}} req - * @param {*} res - * @param {*} next - * @return {void} - * @description Confirms that openTime < closeTime < confirmTime - */ -function confirmValidPatch(req, res, next) { - const openTime = new Date(req.body.settingsDetails.openTime); - const closeTime = new Date(req.body.settingsDetails.closeTime); - const confirmTime = new Date(req.body.settingsDetails.confirmTime); - if (openTime < closeTime && closeTime < confirmTime) { - return next(); - } - return next({ - status: 422, - message: Constants.Error.SETTINGS_422_MESSAGE, - error: req.body.settingsDetails - }); -} - -/** - * @function updateSettings - * @param {*} req - * @param {*} res - * @param {(err?) => void} next - * @return {void} - * @description get the settings object and puts it in the settingsDetails. - */ -async function getSettings(req, res, next) { - const settings = await Services.Settings.getSettings(); - if (!settings) { - return next({ - status: 404, - message: Constants.Error.SETTINGS_404_MESSAGE - }); - } else { - req.body.settingsDetails = settings; - next(); - } -} - -/** - * @function confirmAppsOpen - * @param {*} req - * @param {*} res - * @param {*} next - * @description Only succeeds if the currentTime > openTime, and currentTime < closeTime - */ -async function confirmAppsOpen(req, res, next) { - const settings = await Services.Settings.getSettings(); - if (!settings) { - return next({ - status: 500, - message: Constants.Error.GENERIC_500_MESSAGE - }); - } else { - const now = Date.now(); - const openTime = new Date(settings.openTime); - const closeTime = new Date(settings.closeTime); - if (openTime < now && closeTime > now) { - return next(); - } - return next({ - status: 403, - message: Constants.Error.SETTINGS_403_MESSAGE - }); - } -} - -module.exports = { - parsePatch: parsePatch, - confirmValidPatch: confirmValidPatch, - confirmAppsOpen: Middleware.Util.asyncMiddleware(confirmAppsOpen), - updateSettings: Middleware.Util.asyncMiddleware(updateSettings), - getSettings: Middleware.Util.asyncMiddleware(getSettings) -}; diff --git a/middlewares/volunteer.middleware.js b/middlewares/volunteer.middleware.js deleted file mode 100644 index af95647e..00000000 --- a/middlewares/volunteer.middleware.js +++ /dev/null @@ -1,151 +0,0 @@ -"use strict"; -const mongoose = require("mongoose"); -const Middleware = { - Util: require("./util.middleware") -}; -const Services = { - Volunteer: require("../services/volunteer.service"), - Account: require("../services/account.service") -}; -const Constants = { - General: require("../constants/general.constant"), - Error: require("../constants/error.constant") -}; - -/** - * @function parseVolunteer - * @param {body: {accountId: ObjectId}} req - * @param {*} res - * @param {(err?)=>void} next - * @return {void} - * @description - * Moves accountId from req.body to req.body.volunteerDetails. - * Adds _id to volunteerDetails. - */ -function parseVolunteer(req, res, next) { - const volunteerDetails = { - _id: mongoose.Types.ObjectId(), - accountId: req.body.accountId - }; - - delete req.body.accountId; - - req.body.volunteerDetails = volunteerDetails; - - return next(); -} - -/** - * Checks that there are no other volunteers with the same account id as the one passed into req.body.accountId - * @param {{body:{accountId: ObjectId}}} req - * @param {*} res - * @param {*} next - */ -async function checkDuplicateAccountLinks(req, res, next) { - const volunteer = await Services.Volunteer.findByAccountId( - req.body.accountId - ); - if (!volunteer) { - return next(); - } else { - return next({ - status: 409, - message: Constants.Error.VOLUNTEER_ID_409_MESSAGE, - data: { - id: req.body.accountId - } - }); - } -} - -/** - * @async - * @function createdVolunteer - * @param {{body: {volunteerDetails: {_id: ObjectId, accountId: ObjectId}}}} req - * @param {*} res - * @description create a volunteer from information in req.body.volunteerDetails - */ -async function createVolunteer(req, res, next) { - const volunteerDetails = req.body.volunteerDetails; - - const volunteer = await Services.Volunteer.createVolunteer( - volunteerDetails - ); - - if (!volunteer) { - return next({ - status: 500, - message: Constants.Error.VOLUNTEER_CREATE_500_MESSAGE, - data: {} - }); - } - - req.body.volunteer = volunteer; - next(); -} - -/** - * Verifies that account is confirmed and of proper type from the account ID passed in req.body.accountId - * @param {{body: {accountId: ObjectId}}} req - * @param {*} res - * @param {(err?) => void} next - */ -async function validateConfirmedStatus(req, res, next) { - const account = await Services.Account.findById(req.body.accountId); - if (!account) { - return next({ - status: 404, - message: Constants.Error.ACCOUNT_404_MESSAGE, - error: {} - }); - } else if (!account.confirmed) { - return next({ - status: 403, - message: Constants.Error.ACCOUNT_403_MESSAGE, - error: {} - }); - } else if (account.accountType !== Constants.General.VOLUNTEER) { - return next({ - status: 409, - message: Constants.Error.ACCOUNT_TYPE_409_MESSAGE - }); - } else { - return next(); - } -} - -/** - * @async - * @function findById - * @param {{body: {id: ObjectId}}} req - * @param {*} res - * @description Retrieves a volunteer's information via req.body.id, moving result to req.body.volunteer if succesful. - */ -async function findById(req, res, next) { - const volunteer = await Services.Volunteer.findById(req.body.id); - - if (!volunteer) { - return next({ - status: 404, - message: Constants.Error.VOLUNTEER_404_MESSAGE, - data: { - id: req.body.id - } - }); - } - - req.body.volunteer = volunteer; - next(); -} - -module.exports = { - parseVolunteer: parseVolunteer, - createVolunteer: Middleware.Util.asyncMiddleware(createVolunteer), - checkDuplicateAccountLinks: Middleware.Util.asyncMiddleware( - checkDuplicateAccountLinks - ), - validateConfirmedStatus: Middleware.Util.asyncMiddleware( - validateConfirmedStatus - ), - findById: Middleware.Util.asyncMiddleware(findById) -}; diff --git a/models/staff.model.ts b/models/staff.model.ts deleted file mode 100644 index a54c6904..00000000 --- a/models/staff.model.ts +++ /dev/null @@ -1,7 +0,0 @@ -import Account from "./account.model"; -import { Entity } from "typeorm"; - -@Entity() -class Staff extends Account {} - -export default Staff; diff --git a/models/volunteer.model.ts b/models/volunteer.model.ts deleted file mode 100644 index d6016b8c..00000000 --- a/models/volunteer.model.ts +++ /dev/null @@ -1,7 +0,0 @@ -import Account from "./account.model"; -import { Entity } from "typeorm"; - -@Entity() -class Volunteer extends Account {} - -export default Volunteer; diff --git a/routes/api/settings.js b/routes/api/settings.js deleted file mode 100644 index f0f19b29..00000000 --- a/routes/api/settings.js +++ /dev/null @@ -1,91 +0,0 @@ -"use strict"; - -const express = require("express"); -const Controllers = { - Settings: require("../../controllers/settings.controller") -}; -const Middleware = { - Validator: { - /* Insert the require statement to the validator file here */ - Settings: require("../../middlewares/validators/settings.validator") - }, - /* Insert all of ther middleware require statements here */ - parseBody: require("../../middlewares/parse-body.middleware"), - Settings: require("../../middlewares/settings.middleware"), - Auth: require("../../middlewares/auth.middleware") -}; - -module.exports = { - activate: function(apiRouter) { - const settingsRouter = express.Router(); - - /** - * @api {get} /settings/ Get the settings for the current hackathon - * @apiName getSettings - * @apiGroup Settings - * @apiVersion 1.1.1 - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data Settings Object - * @apiSuccessExample {object} Success-Response: - * { - * "message": "Settings creation successful.", - * "data": { - * "settings": { - * openTime: "Wed Feb 06 2019 00:00:00 GMT-0500 (GMT-05:00)", - * closeTime: "Sat Feb 01 2020 00:00:00 GMT-0500 (GMT-05:00)", - * confirmTime: "Sat Feb 20 2020 00:00:00 GMT-0500 (GMT-05:00)", - * isRemote: false - * } - * } - * } - * @apiPermission public - */ - settingsRouter.get( - "/", - Middleware.Settings.getSettings, - Controllers.Settings.gotSettings - ); - - /** - * @api {patch} /settings/ Patch the settings for the current hackathon - * @apiName patchSettings - * @apiGroup Settings - * @apiVersion 1.1.1 - * - * @apiParam (body) {Date} [openTime] The opening time for the hackathon. - * @apiParam (body) {Date} [closeTime] The closing time for the hackathon. - * @apiParam (body) {Date} [confirmTime] The deadline for confirmation for the hackathon. - * @apiParam (body) {Boolean} [isRemote] Whether this hackathon is remote or not. - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data Settings Object - * @apiSuccessExample {object} Success-Response: - * { - * "message": "Settings patch successful.", - * "data": { - * "settings": { - * openTime: "Wed Feb 06 2019 00:00:00 GMT-0500 (GMT-05:00)", - * closeTime: "Sat Feb 01 2020 00:00:00 GMT-0500 (GMT-05:00)", - * confirmTime: "Sat Feb 20 2020 00:00:00 GMT-0500 (GMT-05:00)", - * isRemote: true - * } - * } - * } - * @apiPermission Administrators - */ - settingsRouter.patch( - "/", - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized([]), - Middleware.Validator.Settings.createSettingsValidator, - Middleware.parseBody.middleware, - Middleware.Settings.parsePatch, - Middleware.Settings.confirmValidPatch, - Middleware.Settings.updateSettings, - Controllers.Settings.patchedSettings - ); - - apiRouter.use("/settings", settingsRouter); - } -}; diff --git a/routes/api/volunteer.js b/routes/api/volunteer.js deleted file mode 100644 index 8bf065e0..00000000 --- a/routes/api/volunteer.js +++ /dev/null @@ -1,104 +0,0 @@ -"use strict"; - -const express = require("express"); -const Controllers = { - Volunteer: require("../../controllers/volunteer.controller") -}; -const Middleware = { - Validator: { - /* Insert the require statement to the validator file here */ - Volunteer: require("../../middlewares/validators/volunteer.validator"), - RouteParam: require("../../middlewares/validators/routeParam.validator") - }, - /* Insert all of ther middleware require statements here */ - parseBody: require("../../middlewares/parse-body.middleware"), - Volunteer: require("../../middlewares/volunteer.middleware"), - Auth: require("../../middlewares/auth.middleware") -}; -const Services = { - Volunteer: require("../../services/volunteer.service") -}; - -const CONSTANTS = require("../../constants/general.constant"); - -module.exports = { - activate: function(apiRouter) { - const volunteerRouter = express.Router(); - - /** - * @api {get} /volunteer/:id get a volunteer's information - * @apiName getVolunteer - * @apiGroup Volunteer - * @apiVersion 1.3.0 - * - * @apiParam (param) {ObjectId} id a volunteer's unique mongoID - * - * @apiSuccess {String} message Success message - * @apiSuccess {Object} data Volunteer object - * @apiSuccessExample {object} Success-Response: - * { - "message": "Successfully retrieved volunteer information", - "data": {...} - } - - * @apiError {String} message Error message - * @apiError {Object} data empty - * @apiErrorExample {object} Error-Response: - * {"message": "Volunteer not found", "data": {}} - */ - volunteerRouter.route("/:id").get( - Middleware.Validator.RouteParam.idValidator, - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized([Services.Volunteer.findById]), - - Middleware.parseBody.middleware, - - Middleware.Volunteer.findById, - Controllers.Volunteer.showVolunteer - ); - - /** - * @api {post} /volunteer/ create a new volunteer - * @apiName createVolunteer - * @apiGroup Volunteer - * @apiVersion 0.0.8 - * - * @apiParam (body) {MongoID} accountId MongoID of the account of the volunteer - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data Volunteer object - * @apiSuccessExample {object} Success-Response: - * { - "message": "Volunteer creation successful", - "data": {...} - } - - * @apiError {string} message Error message - * @apiError {object} data empty - * @apiErrorExample {object} Error-Response: - * {"message": "Error while creating volunteer", "data": {}} - */ - volunteerRouter.route("/").post( - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized(), - - Middleware.Validator.Volunteer.newVolunteerValidator, - - Middleware.parseBody.middleware, - - // validate type - Middleware.Volunteer.validateConfirmedStatus, - // validate that the accountId is not being used for any other thing - Middleware.Volunteer.checkDuplicateAccountLinks, - - Middleware.Volunteer.parseVolunteer, - - Middleware.Auth.createRoleBindings(CONSTANTS.VOLUNTEER), - - Middleware.Volunteer.createVolunteer, - Controllers.Volunteer.createdVolunteer - ); - - apiRouter.use("/volunteer", volunteerRouter); - } -}; diff --git a/scripts/migrate_email_templates.js b/scripts/migrate_email_templates.js deleted file mode 100644 index 4c5dfd88..00000000 --- a/scripts/migrate_email_templates.js +++ /dev/null @@ -1,68 +0,0 @@ -"use strict"; -const env = require("../services/env.service"); -const db = require("../services/database.service"); - -const fs = require("fs").promises; -const path = require("path"); -const templatesDirPath = path.join(__dirname, "../assets/email/marketingEmail/"); - -const EmailTemplate = require("../models/emailTemplate.model"); - -// load env -const envLoadResult = env.load(path.join(__dirname, "../.env")); -if (envLoadResult.error) { - console.error(envLoadResult.error); -} - -// connect to db -db.connect(undefined, () => { - onConnected() - .catch((reason) => { - console.error(reason); - process.exit(1); - }) - .then(() => { - process.exit(0); - }); -}); - -/** - * Called when the db is connected. - */ -async function onConnected() { - await migrateAll(); - console.log("Finished migrating."); -} - -/** - * Inserts all email templates in assets to the db. - */ -async function migrateAll() { - const filenames = await fs.readdir(templatesDirPath); - for (const filename of filenames) { - const filepath = path.join(templatesDirPath, filename); - const data = await fs.readFile(filepath, 'utf-8'); - const emailTemplateDoc = new EmailTemplate( - { - name: filename, - content: data - } - ); - await insertOne(emailTemplateDoc); - } -} - - -/** - * Inserts an EmailTemplate document to the db. Prevents duplicate name. - * @param {EmailTemplate} emailTemplateDoc - */ -async function insertOne(emailTemplateDoc) { - const dup = await EmailTemplate.collection.findOne({ name: emailTemplateDoc.name }); - if (!dup) { - await EmailTemplate.collection.insertOne(emailTemplateDoc); - console.log(`${emailTemplateDoc.name} is migrated.`); - } else { - console.error(`${emailTemplateDoc.name} already in database.`); - } -} diff --git a/services/auth.service.ts b/services/auth.service.ts deleted file mode 100644 index 0be8b9ff..00000000 --- a/services/auth.service.ts +++ /dev/null @@ -1,209 +0,0 @@ -import { Request } from "express"; -import Account from "../models/account.model"; -import Role, { RouteSchema } from "../models/role.model"; - -import { Strategy as LocalStrategy } from "passport-local"; -const { getAccountIfValid, findById } = require("../services/account.service"); -const RoleBinding = require("../services/roleBinding.service"); -import * as logger from "./logger.service"; - -const emailAndPassStrategy = new LocalStrategy( - { - usernameField: "email", - passwordField: "password" - }, - (email: string, password: string, done: any) => { - email = email.toLowerCase(); - getAccountIfValid(email, password).then( - (account: Account) => { - if (account) { - done(null, account); - } else { - done(null, false); - } - }, - (reason: Object) => { - done(reason, false); - } - ); - } -); - -function deserializeUser(identifier: number, done: any) { - findById(identifier).then( - (user: Account) => { - done(null, user); - }, - (reason: Object) => { - done(reason); - } - ); -} - -/** - * Takes as input the id of the user. If the user id exists, it passes the user object to the callback - * (done). The two arguments of the callback must be (failureReason, userObject). If there is no user, - * then the userObject will be undefined. - */ -function serializeUser(user: Account, done: any) { - done(null, user.identifier); -} - -export { emailAndPassStrategy, deserializeUser, serializeUser }; - -/** - * @param {{params: string[], baseUrl: string, path: string, user: {id: string}}} req request object passed in by Express.js - * @param {((param: string) => object)[]} findByIdFns Functions that will return accounts given ids from route parameters. - * @return {boolean} Whether the user has permission to access the route - */ - -// assuming that routes are strings, not objects -// assuming that the route subtypes are :self and :all -// assuming that the route params (resource ids) are in -// size of findByIdFns needs to match the number of route parameters - -// to check for :all, just replace :all with the paramID (AKA resource ID) -export async function ensureAuthorized(req: Request, findByIdFns: any) { - // if number of params doesn't match number of findById functions, fail - //TODO - req.params is a ParamDictionary not string[] - //@ts-ignore - if (!verifyParamsFunctions(req.params, findByIdFns)) { - return false; - } - - // the requested route is given by req.baseUrl+req.path, to remove ? and other params - let path = req.baseUrl + req.path; - // Make sure all paths end in '/'. This is important as we split the path by "/" and check the array length. - if (path.slice(-1) !== "/") { - path += "/"; - } - // splitPath[0] will be '', but assuming that routes will also start with '/', splitRoles will start with '' as well - const splitPath = path.split("/"); - - // if account doesn't have a role binding, then not authenticated - const roleBinding = await RoleBinding.getRoleBindingForAcct( - //@ts-ignore TODO - User has no identifier field in express.User - req.user?.identifier - ); - if (!roleBinding) { - return false; - } - - // get the route ids - const twoDRoutes = roleBinding.roles.map((role: Role) => { - return role.routes; - }); - const routes: RouteSchema[] = [].concat(...twoDRoutes); - - // each route is an object with an uri and a request type - // for each uri, separate by '/', check each section to see if it's the same as requested uri - // if the uri at a section has ':all', mark it as valid - // if the uri at a section has ':self', use the findByIdFns at particular index to check if accId matches - // the request type of the incoming request and the matching request type of the route must be the same - for (const route of routes) { - // if the request types are different, go to next - // the incoming request type is in req.method according to node v10.12.0 api - if (route.requestType !== req.method) { - continue; - } - - let routeUri = route.uri; - // Make sure all paths end in '/'. This is important as we split the path by "/" and check the array length. - if (routeUri.slice(-1) !== "/") { - routeUri += "/"; - } - const splitRoute = routeUri.split("/"); - - // keeps track of which function to use in findByIdFns - let findByParamCount = 0; - let currentlyValid = true; - for (let i = 0; i < splitPath.length; i++) { - // checks whether the current chunk in the route path is a parameter - const isParam = - Object.values(req.params).indexOf(splitPath[i]) > -1; - - // if current chunk isn't a parameter, then check whether auth route and request path are the same - if (!isParam) { - currentlyValid = splitRoute[i] === splitPath[i]; - } else { - switch (splitRoute[i]) { - case ":all": - currentlyValid = true; - break; - case ":self": - currentlyValid = await verifySelfCase( - findByIdFns[findByParamCount], - splitPath[i], - //@ts-ignore TODO - User has no identifier field in express.User - req.user?.identifier - ); - findByParamCount += 1; - break; - default: - currentlyValid = false; - break; - } - } - - // if current route isn't valid, move on to next - if (!currentlyValid) { - break; - } - } - - if (currentlyValid) { - return currentlyValid; - } - } - return false; -} - -/** - * Makes sure that the number of params matches the number of id functions. If there are no route params, idFns should be null or an empty array. - * @param {((param: string) => object)[]} idFns An array of functions that take as input a parameter, and return an object - * @param {string[]} params List of route parameters - * @return {boolean} Whether the number of route parameters matches with the number of idFns - */ -function verifyParamsFunctions( - params: string[], - idFns: ((param: string) => object)[] -) { - let numParams = Object.values(params).length; - let validRoute = true; - - if (numParams === 0) { - validRoute = !idFns || idFns.length === 0; - } else { - validRoute = numParams === idFns.length; - } - - return validRoute; -} - -/** - * Uses param with idFunction to check whether the returned object is the user account, or is linked to the user's account - * @param {(string) => object} idFunction A function that will take a string and return an object - * @param {string} param The route parameter - * @param {number} userId The id of the user - * @return {boolean} Whether the object found by the idFunction is the user's account or linked to the user's account - */ -async function verifySelfCase( - idFunction: (value: string) => object, - param: string, - userId: number -) { - const object: any = await idFunction(param); - if (!object) { - return false; - } - - // if the accountId exists (all cases except when object is an account) - if (object.accountId) { - //TODO - Check if this code is correct, we changed to identifier from accountId. - return object.identifier.toString() === userId; - } - // no accountId so object is an account - else { - return object.identifier.toString() === userId; - } -} diff --git a/services/settings.service.ts b/services/settings.service.ts deleted file mode 100644 index 45c4a62b..00000000 --- a/services/settings.service.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { UpdateResult } from "typeorm"; -import Settings from "../models/settings.model"; -const logger = require("./logger.service"); - -/** - * @function updateSettings - * @param {{_id: ObjectId, openTime: Date, closeTime: Date, confirmTime: Date}} settingsDetails - * @return {Promise} The promise will resolve to a Settings object if save was successful. - * @description Adds a new setting to database. - */ -async function updateSettings(settingsDetails: Object) { - const TAG = "[Setting service # updateSettings]:"; - const existingSetting = await getSettings(); - if (existingSetting) { - return Settings.update({}, settingsDetails).then( - (value: UpdateResult) => { - logger.queryCallbackFactory(TAG, "settings", {}); - return value; - } - ); - } else { - const setting = Settings.create(settingsDetails); - return await setting.save(); - } -} - -/** - * @function getSettings - * @return {Promise} The promise will resolve to a Settings object if retrieval was successful. - * @description Returns the setting item - */ -function getSettings() { - const TAG = "[Setting service # getSettings]:"; - return Settings.findOne( - {}, - logger.queryCallbackFactory(TAG, "settings", {}) - ); -} - -module.exports = { - updateSettings: updateSettings, - getSettings: getSettings -}; diff --git a/services/version.service.ts b/services/version.service.ts deleted file mode 100644 index 9809b867..00000000 --- a/services/version.service.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { version } from "../package.json"; - -const get = function() { - return version; -}; - -export { get }; diff --git a/services/volunteer.service.ts b/services/volunteer.service.ts deleted file mode 100644 index bab8e16c..00000000 --- a/services/volunteer.service.ts +++ /dev/null @@ -1,45 +0,0 @@ -import Volunteer from "../models/volunteer.model"; -const logger = require("./logger.service"); - -/** - * @function createVolunteer - * @param {{_id: ObjectId, accountId: ObjectId}} volunteerDetails - * @return {Promise} The promise will resolve to a volunteer object if save was successful. - * @description Adds a new volunteer to database. - */ -async function createVolunteer(volunteerDetails: Object): Promise { - const TAG = `[Volunteer Service # createTeam]:`; - - const volunteer = Volunteer.create(volunteerDetails); - return await volunteer.save(); -} - -/** - * @function findById - * @param {number} identifier - * @return {Promise} The document query will resolve to volunteer or null. - * @description Finds an volunteer by the id, which is the mongoId. - */ -async function findById(identifier: number): Promise { - const TAG = `[Volunteer Service # findById ]:`; - - return await Volunteer.findOne(identifier).then((volunteer) => { - logger.queryCallbackFactory(TAG, "volunteer", identifier); - return volunteer; - }); -} - -// TODO: Deprecrate / remove this function. -/** - * @function findByAccountId - * @param {number} accountId - * @return {Promise} A volunteer document queried by accountId - */ -async function findByAccountId( - accountId: number -): Promise { - const TAG = `[ Volunteer Service # findByAccountId ]:`; - return this.findById(accountId); -} - -export { createVolunteer, findById, findByAccountId }; From b02e3e4f6f69a442802763d9ad2e662bd83f91d0 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Sat, 25 Dec 2021 22:00:43 -0500 Subject: [PATCH 19/72] refactor: team, travel, and sponsor services & controllers, hacker controller. - TODO: - hacker controller: - invites, stats --- app.ts | 10 +- controllers/hacker.controller.ts | 94 +++++ controllers/sponsor.controller.ts | 98 ++++++ controllers/team.controller.js | 96 ------ controllers/team.controller.ts | 204 +++++++++++ controllers/travel.controller.ts | 129 +++++++ middlewares/sponsor.middleware.js | 246 ------------- middlewares/team.middleware.js | 552 ------------------------------ middlewares/travel.middleware.js | 247 ------------- models/application.model.ts | 12 +- models/hacker.model.ts | 44 ++- models/sponsor.model.ts | 15 +- models/team.model.ts | 4 - models/travel.model.ts | 9 +- package-lock.json | 19 + package.json | 1 + routes/api/sponsor.js | 189 ---------- routes/api/team.js | 219 ------------ routes/api/travel.js | 249 -------------- services/hacker.service.ts | 180 +++------- services/sponsor.service.ts | 96 ++---- services/team.service.ts | 288 ++++------------ services/travel.service.ts | 113 ++---- 23 files changed, 767 insertions(+), 2347 deletions(-) create mode 100644 controllers/hacker.controller.ts create mode 100644 controllers/sponsor.controller.ts delete mode 100644 controllers/team.controller.js create mode 100644 controllers/team.controller.ts create mode 100644 controllers/travel.controller.ts delete mode 100644 middlewares/sponsor.middleware.js delete mode 100644 middlewares/team.middleware.js delete mode 100644 middlewares/travel.middleware.js delete mode 100644 routes/api/sponsor.js delete mode 100644 routes/api/team.js delete mode 100644 routes/api/travel.js diff --git a/app.ts b/app.ts index 8e4df2ad..1dc12109 100755 --- a/app.ts +++ b/app.ts @@ -5,6 +5,10 @@ import { join } from "path"; import { container } from "tsyringe"; import { AccountController } from "./controllers/account.controller"; import { AuthenticationController } from "./controllers/authentication.controller"; +import { HackerController } from "./controllers/hacker.controller"; +import { SponsorController } from "./controllers/sponsor.controller"; +import { TeamController } from "./controllers/team.controller"; +import { TravelController } from "./controllers/travel.controller"; import { DatabaseService } from "./services/database.service"; import { EnvService } from "./services/env.service"; import { LoggerService } from "./services/logger.service"; @@ -71,7 +75,11 @@ const cors = require("cors"); const router = express.Router(); attachControllerInstances(router, [ container.resolve(AccountController), - container.resolve(AuthenticationController) + container.resolve(AuthenticationController), + container.resolve(HackerController), + container.resolve(TeamController), + container.resolve(SponsorController), + container.resolve(TravelController) ]); application.use("/api", router); diff --git a/controllers/hacker.controller.ts b/controllers/hacker.controller.ts new file mode 100644 index 00000000..da90046f --- /dev/null +++ b/controllers/hacker.controller.ts @@ -0,0 +1,94 @@ +import { + Body, + Controller, + Get, + Params, + Patch, + Post, + Response +} from "@decorators/express"; +import { autoInjectable } from "tsyringe"; +import { AuthorizationLevel } from "../constants/authorization-level.constant"; +import { EnsureAuthenticated } from "../middlewares/authenticated.middleware"; +import { EnsureAuthorization } from "../middlewares/authorization.middleware"; +import Hacker from "../models/hacker.model"; +import { HackerService } from "../services/hacker.service"; +import * as SuccessConstants from "../constants/success.constant"; +import * as ErrorConstants from "../constants/error.constant"; +import { request, Response as ExpressResponse } from "express"; + +@autoInjectable() +@Controller("/hacker") +export class HackerController { + constructor(private readonly hackerService: HackerService) {} + + @Get("/:identifier", [ + EnsureAuthenticated, + EnsureAuthorization([ + AuthorizationLevel.Staff, + AuthorizationLevel.Hacker + ]) + ]) + async getByIdentifier( + @Response() response: ExpressResponse, + @Params("identifier") identifier: number + ) { + const hacker: + | Hacker + | undefined = await this.hackerService.findByIdentifier(identifier); + + return hacker + ? response.status(200).json({ + message: SuccessConstants.HACKER_READ, + data: hacker + }) + : response.status(404).json({ + message: ErrorConstants.HACKER_404_MESSAGE + }); + } + + @Post("/", [EnsureAuthenticated]) + async create( + @Response() response: ExpressResponse, + @Body() hacker: Hacker + ) { + //TODO - Check if applications are open when hacker is created. + const result: Hacker = await this.hackerService.save(hacker); + + return result + ? response.status(200).send({ + message: SuccessConstants.HACKER_CREATE, + data: result + }) + : response.status(422).send({ + message: ErrorConstants.ACCOUNT_DUPLICATE_422_MESSAGE + }); + } + + @Patch("/:identifier", [ + EnsureAuthenticated, + EnsureAuthorization([ + AuthorizationLevel.Staff, + AuthorizationLevel.Hacker + ]) + ]) + async update( + @Response() response: ExpressResponse, + @Params("identifier") identifier: number, + @Body() update: Partial + ) { + const result = await this.hackerService.update(identifier, update); + + return result + ? response.status(200).json({ + message: SuccessConstants.HACKER_UPDATE, + data: result + }) + : response.status(404).json({ + message: ErrorConstants.HACKER_404_MESSAGE, + data: { + identifier: identifier + } + }); + } +} diff --git a/controllers/sponsor.controller.ts b/controllers/sponsor.controller.ts new file mode 100644 index 00000000..c9f50879 --- /dev/null +++ b/controllers/sponsor.controller.ts @@ -0,0 +1,98 @@ +import { + Body, + Controller, + Get, + Params, + Patch, + Post, + Response +} from "@decorators/express"; +import { autoInjectable } from "tsyringe"; +import { AuthorizationLevel } from "../constants/authorization-level.constant"; +import { EnsureAuthenticated } from "../middlewares/authenticated.middleware"; +import { EnsureAuthorization } from "../middlewares/authorization.middleware"; +import Sponsor from "../models/sponsor.model"; +import { SponsorService } from "../services/sponsor.service"; +import { Response as ExpressResponse } from "express"; +import * as SuccessConstants from "../constants/success.constant"; +import * as ErrorConstants from "../constants/error.constant"; + +@autoInjectable() +@Controller("/sponsor") +export class SponsorController { + constructor(private readonly sponsorService: SponsorService) {} + + @Get("/:identifier", [ + EnsureAuthenticated, + EnsureAuthorization([ + AuthorizationLevel.Staff, + AuthorizationLevel.Sponsor + ]) + ]) + async getByIdentifier( + @Response() response: ExpressResponse, + @Params("identifier") identifier: number + ) { + const sponsor: + | Sponsor + | undefined = await this.sponsorService.findByIdentifier( + identifier + ); + + return sponsor + ? response.status(200).json({ + message: SuccessConstants.SPONSOR_READ, + data: sponsor + }) + : response.status(404).json({ + message: ErrorConstants.SPONSOR_404_MESSAGE + }); + } + + @Post("/", [ + EnsureAuthenticated, + EnsureAuthorization([AuthorizationLevel.Staff]) + ]) + async create( + @Response() response: ExpressResponse, + @Body() sponsor: Sponsor + ) { + const result = await this.sponsorService.save(sponsor); + + return result + ? response.status(200).send({ + message: SuccessConstants.SPONSOR_CREATE, + data: result + }) + : response.status(422).send({ + message: ErrorConstants.ACCOUNT_DUPLICATE_422_MESSAGE + }); + } + + @Patch("/:identifier", [ + EnsureAuthenticated, + EnsureAuthorization([ + AuthorizationLevel.Staff, + AuthorizationLevel.Sponsor + ]) + ]) + async update( + @Response() response: ExpressResponse, + @Params("identifier") identifier: number, + @Body() update: Partial + ) { + const result = await this.sponsorService.update(identifier, update); + + return result + ? response.status(200).json({ + message: SuccessConstants.SPONSOR_UPDATE, + data: result + }) + : response.status(404).json({ + message: ErrorConstants.SPONSOR_404_MESSAGE, + data: { + identifier: identifier + } + }); + } +} diff --git a/controllers/team.controller.js b/controllers/team.controller.js deleted file mode 100644 index 3f3a9b48..00000000 --- a/controllers/team.controller.js +++ /dev/null @@ -1,96 +0,0 @@ -"use strict"; -const mongoose = require("mongoose"); - -const Services = { - Team: require("../services/team.service"), - Logger: require("../services/logger.service") -}; -const Util = require("../middlewares/util.middleware"); -const Constants = { - Success: require("../constants/success.constant"), - Error: require("../constants/error.constant") -}; - -/** - * @function showTeam - * @param {{body: {team: Object}}} req - * @param {*} res - * @return {JSON} Success status and team object - * @description Returns the JSON of team object located in req.body.team - */ -function showTeam(req, res) { - const teamData = req.body.team.toJSON(); - - return res.status(200).json({ - message: Constants.Success.TEAM_READ, - data: { - team: teamData, - members: req.body.teamMembers - } - }); -} - -/** - * @function joinedTeam - * @param {*} req - * @param {*} res - * @return {JSON} Success status of joining team - * @description return success message of joining team - */ -function joinedTeam(req, res) { - return res.status(200).json({ - message: Constants.Success.TEAM_JOIN, - data: {} - }); -} - -/** - * @function updatedTeam - * @param {{body: {team: {_id: ObjectId, name: string, members: ObjectId[], devpostURL: string, projectName: string}}}} req - * @param {*} res - * @return {JSON} Success status - * @description Display team information and update success status - */ -function updatedTeam(req, res) { - return res.status(200).json({ - message: Constants.Success.TEAM_UPDATE, - data: req.body.team.toJSON() - }); -} - -/** - * @function createdTeam - * @param {{body: {team: {_id: ObjectId, name: string, members: ObjectId[], devpostURL: string, projectName: string}}}} req - * @param {*} res - * @return {JSON} Success or error status - * @description Display team information and creation success status. - */ -function createdTeam(req, res) { - return res.status(200).json({ - message: Constants.Success.TEAM_CREATE, - data: req.body.team - }); -} - -/** - * @function leftTeam - * @param {*} req - * @param {*} res - * @return {JSON} Success status - * @description return success message of removing self from team. - */ - -function leftTeam(req, res) { - return res.status(200).json({ - message: Constants.Success.TEAM_HACKER_LEAVE, - data: {} - }); -} - -module.exports = { - joinedTeam: joinedTeam, - updatedTeam: updatedTeam, - createdTeam: createdTeam, - showTeam: showTeam, - leftTeam: leftTeam -}; diff --git a/controllers/team.controller.ts b/controllers/team.controller.ts new file mode 100644 index 00000000..15c8dd69 --- /dev/null +++ b/controllers/team.controller.ts @@ -0,0 +1,204 @@ +import { + Body, + Controller, + Get, + Params, + Patch, + Post, + Request, + Response +} from "@decorators/express"; +import { autoInjectable } from "tsyringe"; +import { + Request as ExpressRequest, + Response as ExpressResponse +} from "express"; +import { EnsureAuthenticated } from "../middlewares/authenticated.middleware"; +import { EnsureAuthorization } from "../middlewares/authorization.middleware"; +import { AuthorizationLevel } from "../constants/authorization-level.constant"; +import Team from "../models/team.model"; +import { TeamService } from "../services/team.service"; +import * as SuccessConstants from "../constants/success.constant"; +import * as ErrorConstants from "../constants/error.constant"; +import { HackerService } from "../services/hacker.service"; +import Hacker from "../models/hacker.model"; + +@autoInjectable() +@Controller("/team") +export class TeamController { + constructor( + private readonly teamService: TeamService, + private readonly hackerService: HackerService + ) {} + + @Get("/:identifier", [ + EnsureAuthenticated, + EnsureAuthorization([ + AuthorizationLevel.Staff, + AuthorizationLevel.Hacker + ]) + ]) + async getByIdentifier( + @Response() response: ExpressResponse, + @Params("identifier") identifier: number + ) { + const team: Team | undefined = await this.teamService.findByIdentifier( + identifier + ); + + return team + ? response.status(200).json({ + message: SuccessConstants.TEAM_READ, + data: team + }) + : response.status(404).json({ + message: ErrorConstants.TEAM_404_MESSAGE + }); + } + + @Post("/", [ + EnsureAuthenticated, + EnsureAuthorization([ + AuthorizationLevel.Staff, + AuthorizationLevel.Hacker + ]) + ]) + async create(@Response() response: ExpressResponse, @Body() team: Team) { + const result = await this.teamService.save(team); + + //TODO - Change duplicate message from Account to Team. + return result + ? response.status(200).send({ + message: SuccessConstants.TEAM_CREATE, + data: result + }) + : response.status(422).send({ + message: ErrorConstants.ACCOUNT_DUPLICATE_422_MESSAGE + }); + } + + @Patch("/:hackerIdentifier", [ + EnsureAuthenticated, + EnsureAuthorization([ + AuthorizationLevel.Staff, + AuthorizationLevel.Hacker + ]) + ]) + async update( + @Response() response: ExpressResponse, + @Params("hackerIdentifier") hackerIdentifier: number, + @Body() update: Partial> + ) { + const team: Team | undefined = ( + await this.hackerService.findByIdentifier(hackerIdentifier) + )?.team; + + if (team) { + const result = this.teamService.update(team.identifier, update); + + response.status(200).send({ + message: SuccessConstants.TEAM_UPDATE, + data: result + }); + } + + response.status(400).send({ + message: ErrorConstants.TEAM_404_MESSAGE + }); + } + + @Patch("/join", [ + EnsureAuthenticated, + EnsureAuthorization([AuthorizationLevel.Hacker]) + ]) + async joinTeam( + @Request() request: ExpressRequest, + @Response() response: ExpressResponse, + @Body("name") name: string + ) { + const hacker: + | Hacker + | undefined = await this.hackerService.findByIdentifier( + //@ts-ignore + request.user?.identifier + ); + + if (!hacker) + response.status(404).send({ + message: ErrorConstants.HACKER_404_MESSAGE, + data: { + //@ts-ignore + identifier: request.user?.identifier + } + }); + + const team: Team | undefined = await this.teamService.findByName(name); + + if (!team) + response.status(404).send({ + message: ErrorConstants.TEAM_404_MESSAGE, + data: { + name: name + } + }); + + if (hacker?.team) { + if (hacker?.team?.identifier == team?.identifier) + response.status(409).send({ + message: ErrorConstants.TEAM_JOIN_SAME_409_MESSAGE, + data: { + name: name + } + }); + await this.teamService.removeMember( + hacker?.team?.identifier, + hacker + ); + } + + if (!(await this.teamService.addMember(team?.identifier!, hacker!))) + response.status(409).send({ + message: ErrorConstants.TEAM_SIZE_409_MESSAGE + }); + + response.status(200).send({ + message: SuccessConstants.TEAM_JOIN + }); + } + + @Patch("/leave", [ + EnsureAuthenticated, + EnsureAuthorization([AuthorizationLevel.Hacker]) + ]) + async leaveTeam( + @Request() request: ExpressRequest, + @Response() response: ExpressResponse + ) { + const hacker: + | Hacker + | undefined = await this.hackerService.findByIdentifier( + //@ts-ignore + request.user?.identifier + ); + + if (!hacker) + response.status(404).send({ + message: ErrorConstants.HACKER_404_MESSAGE + }); + else { + if (hacker.team) + await this.teamService.removeMember( + hacker.team.identifier, + hacker + ); + else + response.status(404).send({ + message: ErrorConstants.TEAM_404_MESSAGE + }); + } + + response.status(200).send({ + message: SuccessConstants.TEAM_HACKER_LEAVE + }); + } +} diff --git a/controllers/travel.controller.ts b/controllers/travel.controller.ts new file mode 100644 index 00000000..ddec79cf --- /dev/null +++ b/controllers/travel.controller.ts @@ -0,0 +1,129 @@ +import { + Controller, + Get, + Params, + Patch, + Post, + Request, + Response +} from "@decorators/express"; +import { autoInjectable } from "tsyringe"; +import { AuthorizationLevel } from "../constants/authorization-level.constant"; +import { EnsureAuthenticated } from "../middlewares/authenticated.middleware"; +import { EnsureAuthorization } from "../middlewares/authorization.middleware"; +import Travel from "../models/travel.model"; +import { TravelService } from "../services/travel.service"; +import { + Request as ExpressRequest, + Response as ExpressResponse +} from "express"; +import * as SuccessConstants from "../constants/success.constant"; +import * as ErrorConstants from "../constants/error.constant"; + +@autoInjectable() +@Controller("/travel") +export class TravelController { + constructor(private readonly travelService: TravelService) {} + + @Get("/:identifier", [ + EnsureAuthenticated, + EnsureAuthorization([ + AuthorizationLevel.Staff, + AuthorizationLevel.Hacker + ]) + ]) + async getByIdentifier( + @Response() response: ExpressResponse, + @Params("identifier") identifier: number + ) { + const travel: + | Travel + | undefined = await this.travelService.findByIdentifier(identifier); + + return travel + ? response.status(200).json({ + message: SuccessConstants.TRAVEL_READ, + data: travel + }) + : response.status(404).json({ + message: ErrorConstants.TRAVEL_404_MESSAGE + }); + } + + @Post("/", [ + EnsureAuthenticated, + EnsureAuthorization([ + AuthorizationLevel.Staff, + AuthorizationLevel.Hacker + ]) + ]) + async create( + @Response() response: ExpressResponse, + travel: Omit + ) { + // TODO - Find a more elegant way to set the default values. + // We remove the user values as we don't want a hacker setting their own offer as accepted or setting a offer amount. + const result = await this.travelService.save({ + offer: 0, + status: "None", + ...travel + }); + + return result + ? response.status(200).send({ + message: SuccessConstants.TRAVEL_CREATE, + data: result + }) + : response.status(422).send({ + //TODO - Create duplicate message. + message: ErrorConstants.TRAVEL_CREATE_500_MESSAGE + }); + } + + @Patch("/:identifier", [ + EnsureAuthenticated, + EnsureAuthorization([AuthorizationLevel.Staff]) + ]) + async updateByStaff( + @Response() response: ExpressResponse, + @Params("identifier") identifier: number, + travel: Partial + ) { + const result = await this.travelService.update(identifier, travel); + + return result + ? response.status(200).send({ + message: SuccessConstants.TRAVEL_UPDATE, + data: result + }) + : response.status(404).send({ + message: ErrorConstants.TRAVEL_404_MESSAGE, + data: { + identifier: identifier + } + }); + } + + @Patch("/", [ + EnsureAuthenticated, + EnsureAuthorization([AuthorizationLevel.Hacker]) + ]) + async update( + @Request() request: ExpressRequest, + @Response() response: ExpressResponse, + travel: Omit + ) { + // We remove the user values as we don't want a hacker setting their own offer as accepted or setting a offer amount. + //TODO - Create error code for response, use rowsAffected > 0 as success metric on UpdateResult. + const result = await this.travelService.update( + //@ts-ignore + request.user?.identifier, + travel + ); + + response.status(200).send({ + message: SuccessConstants.TRAVEL_UPDATE, + data: result + }); + } +} diff --git a/middlewares/sponsor.middleware.js b/middlewares/sponsor.middleware.js deleted file mode 100644 index 931ae323..00000000 --- a/middlewares/sponsor.middleware.js +++ /dev/null @@ -1,246 +0,0 @@ -"use strict"; -const mongoose = require("mongoose"); -const Services = { - Sponsor: require("../services/sponsor.service"), - Account: require("../services/account.service") -}; -const Middleware = { - Util: require("./util.middleware") -}; -const Constants = { - General: require("../constants/general.constant"), - Error: require("../constants/error.constant") -}; -const Sponsor = require("../models/sponsor.model"); - -/** - * @function parsePatch - * @param {body: {id: ObjectId}} req - * @param {*} res - * @param {(err?) => void} next - * @return {void} - * @description Put relevent sponsor attributes into sponsorDetails - */ -function parsePatch(req, res, next) { - let sponsorDetails = {}; - - for (const val in req.body) { - // use .hasOwnProperty instead of 'in' to get rid of inherited properties such as 'should' - if (Sponsor.schema.paths.hasOwnProperty(val)) { - sponsorDetails[val] = req.body[val]; - delete req.body[val]; - } - } - - req.body.sponsorDetails = sponsorDetails; - - return next(); -} - -/** - * @function parseSponsor - * @param {{body: {accountId: ObjectId, tier: String, company: String, contractURL: String, nominees: ObjectId[]}}} req - * @param {JSON} res - * @param {(err?)=>void} next - * @return {void} - * @description - * Moves accountId, tier, company, contractURL, nominees from req.body to req.body.sponsorDetails. - * Adds _id to sponsorDetails. - */ -function parseSponsor(req, res, next) { - const sponsorDetails = { - _id: mongoose.Types.ObjectId(), - accountId: req.body.accountId, - tier: req.body.tier, - company: req.body.company, - contractURL: req.body.contractURL, - nominees: req.body.nominees - }; - - delete req.body.tier; - delete req.body.company; - delete req.body.contractURL; - delete req.body.nominees; - delete req.body.accountId; - - req.body.sponsorDetails = sponsorDetails; - - return next(); -} - -/** - * Verifies that account is confirmed and of proper type from the account ID passed in req.body.accountId - * @param {{body: {accountId: ObjectId}}} req - * @param {*} res - * @param {(err?) => void} next - */ -async function validateConfirmedStatus(req, res, next) { - const account = await Services.Account.findById(req.body.accountId); - - if (!account) { - return next({ - status: 404, - message: Constants.Error.ACCOUNT_404_MESSAGE, - error: {} - }); - } else if (!account.confirmed) { - return next({ - status: 403, - message: Constants.Error.ACCOUNT_403_MESSAGE, - error: {} - }); - } else if (!account.isSponsor()) { - return next({ - status: 409, - message: Constants.Error.ACCOUNT_TYPE_409_MESSAGE - }); - } else { - return next(); - } -} - -/** - * Finds the sponsor information of the logged in user - * @param {{user: {id: string, accountType: string}}} req - * @param {*} res - * @param {(err?)=>void} next - */ -async function findSelf(req, res, next) { - if (!Constants.General.SPONSOR_TIERS.includes(req.user.accountType)) { - return next({ - status: 409, - message: Constants.Error.ACCOUNT_TYPE_409_MESSAGE, - error: { - id: req.user.id - } - }); - } - - const sponsor = await Services.Sponsor.findByAccountId(req.user.id); - - if (sponsor) { - req.body.sponsor = sponsor; - return next(); - } else { - return next({ - status: 404, - message: Constants.Error.SPONSOR_404_MESSAGE, - error: { - id: req.user.id - } - }); - } -} - -/** - * @async - * @function findById - * @param {{body: {id: ObjectId}}} req - * @param {*} res - * @return {JSON} Success or error status - * @description Retrieves a sponsor by req.body.id, placing it in req.body.sponsor if successful. - */ -async function findById(req, res, next) { - const sponsor = await Services.Sponsor.findById(req.body.id); - - if (!sponsor) { - return next({ - status: 404, - message: Constants.Error.SPONSOR_404_MESSAGE, - error: { - id: req.user.id - } - }); - } - - req.body.sponsor = sponsor; - next(); -} - -/** - * @async - * @function createSponsor - * @param {{body: {sponsorDetails: {_id: ObjectId, accountId: ObjectId, tier: number, company: string, contractURL: string, nominees: ObjectId[]}}}} req - * @param {*} res - * @description Create a sponsor from information in req.body.sponsorDetails, place it in req.body.sponsor. - */ -async function createSponsor(req, res, next) { - const sponsorDetails = req.body.sponsorDetails; - - const sponsor = await Services.Sponsor.createSponsor(sponsorDetails); - - if (sponsor) { - req.body.sponsor = sponsor; - return next(); - } else { - return next({ - status: 500, - message: Constants.Error.SPONSOR_CREATE_500_MESSAGE, - data: {} - }); - } -} - -/** - * @async - * @function updateSponsor - * @param {{body: {id: ObjectId, sponsorDetails: {company?: string, contractURL?: string, nominees?: ObjectId[]}}}} req - * @param {*} res - * @param {(err?)=>void} next - * @description Updates a sponsor specified by req.body.id with information specified in req.body.sponsorDetails. - */ -async function updateSponsor(req, res, next) { - const sponsorDetails = req.body.sponsorDetails; - - const sponsor = await Services.Sponsor.updateOne( - req.body.id, - sponsorDetails - ); - - if (sponsor) { - req.body.sponsor = sponsor; - return next(); - } else { - return next({ - status: 500, - message: Constants.Error.SPONSOR_UPDATE_500_MESSAGE, - data: {} - }); - } -} - -/** - * Checks that there are no other sponsor with the same account id as the one passed into req.body.accountId - * @param {{body:{accountId: ObjectId}}} req - * @param {*} res - * @param {*} next - */ -async function checkDuplicateAccountLinks(req, res, next) { - const sponsor = await Services.Sponsor.findByAccountId(req.body.accountId); - if (!sponsor) { - return next(); - } else { - return next({ - status: 409, - message: Constants.Error.SPONSOR_ID_409_MESSAGE, - data: { - id: req.body.accountId - } - }); - } -} - -module.exports = { - parsePatch: parsePatch, - parseSponsor: parseSponsor, - findSelf: Middleware.Util.asyncMiddleware(findSelf), - findById: Middleware.Util.asyncMiddleware(findById), - createSponsor: Middleware.Util.asyncMiddleware(createSponsor), - checkDuplicateAccountLinks: Middleware.Util.asyncMiddleware( - checkDuplicateAccountLinks - ), - validateConfirmedStatus: Middleware.Util.asyncMiddleware( - validateConfirmedStatus - ), - updateSponsor: Middleware.Util.asyncMiddleware(updateSponsor) -}; diff --git a/middlewares/team.middleware.js b/middlewares/team.middleware.js deleted file mode 100644 index 7d60a036..00000000 --- a/middlewares/team.middleware.js +++ /dev/null @@ -1,552 +0,0 @@ -"use strict"; - -const TAG = `[ TEAM.MIDDLEWARE.js ]`; -const mongoose = require("mongoose"); -const Services = { - Logger: require("../services/logger.service"), - Team: require("../services/team.service"), - Hacker: require("../services/hacker.service"), - Account: require("../services/account.service") -}; -const Util = require("./util.middleware"); -const Constants = { - Error: require("../constants/error.constant"), - General: require("../constants/general.constant") -}; -const Team = require("../models/team.model"); - -/** - * @async - * @function ensureUniqueHackerId - * @param {{body: {teamDetails: {members: ObjectId[]}}}} req - * @param {JSON} res - * @param {(err?)=>void} next - * @return {void} - * @description Checks to see that the members in a team are not in another team, and that members are not duplicate - */ -async function ensureUniqueHackerId(req, res, next) { - let idSet = []; - - for (const member of req.body.teamDetails.members) { - // check to see if a member is entered twice in the application - if (!!idSet[member]) { - return next({ - status: 422, - message: Constants.Error.TEAM_MEMBER_422_MESSAGE, - error: member - }); - } else { - idSet[member] = true; - } - - // check to see if member is part of a another team - const team = await Services.Team.findTeamByHackerId(member); - - if (!!team) { - return next({ - status: 409, - message: Constants.Error.TEAM_MEMBER_409_MESSAGE, - error: member - }); - } - } - - return next(); -} - -/** - * @async - * @function createTeam - * @param {{body: {teamDetails: {_id: ObjectId, name: string, members: ObjectId[], devpostURL?: string, projectName: string}}}} req - * @param {*} res - * @description create a team from information in req.body.teamDetails. - */ -async function createTeam(req, res, next) { - const teamDetails = req.body.teamDetails; - - const team = await Services.Team.createTeam(teamDetails); - - if (!team) { - return next({ - status: 500, - message: Constants.Error.TEAM_CREATE_500_MESSAGE, - data: {} - }); - } - - for (const hackerId of teamDetails.members) { - const hacker = await Services.Hacker.updateOne(hackerId, { - teamId: team._id - }); - - if (!hacker) { - return next({ - status: 500, - message: Constants.Error.TEAM_CREATE_500_MESSAGE, - data: {} - }); - } - } - - req.body.team = team; - return next(); -} - -/** - * @function ensureSpace - * @param {{body: {name: string}}} req - * @param {JSON} res - * @param {(err?)=>void} next - * @return {void} - * @description Checks to see that team is not full. - */ -async function ensureSpace(req, res, next) { - Services.Logger.info(req.body.name); - const teamSize = await Services.Team.getSize(req.body.name); - Services.Logger.info(teamSize); - - if (teamSize === -1) { - return next({ - status: 404, - message: Constants.Error.TEAM_404_MESSAGE, - data: req.body.name - }); - } else if (teamSize >= Constants.General.MAX_TEAM_SIZE) { - return next({ - status: 409, - message: Constants.Error.TEAM_SIZE_409_MESSAGE, - data: teamSize - }); - } - - return next(); -} - -/** - * @function updateTeam - * @param {{body: {teamId: ObjectId, teamDetails: {name?: string, devpostURL?:string, projectName?:string}}}} req - * @param {JSON} res - * @param {(err?)=>void} next - * @return {void} - * @description Updates a team specified by teamId with information specified by teamDetails. - */ -async function updateTeam(req, res, next) { - const team = await Services.Team.updateOne( - req.body.teamId, - req.body.teamDetails - ); - - if (!team) { - return next({ - status: 500, - message: Constants.Error.TEAM_UPDATE_500_MESSAGE, - data: req.body.teamId - }); - } - - req.body.team = team; - return next(); -} - -/** - * @function getTeamIdByHackerId - * @param {{body: {hackerId: ObjectId}}} req - * @param {JSON} res - * @param {(err?)=>void} next - * @return {void} - * @description Places teamId specified by hackerId into req.body - */ -async function getTeamIdByHackerId(req, res, next) { - const hacker = await Services.Hacker.findById(req.body.hackerId); - - if (!hacker) { - return next({ - status: 404, - message: Constants.Error.HACKER_404_MESSAGE, - data: req.body.hackerId - }); - } - - req.body.teamId = hacker.teamId; - next(); -} - -/** - * @function getByHackerId - * @param {{body: {hackerId: ObjectId}}} req - * @param {JSON} res - * @param {(err?)=>void} next - * @return {void} - * @description Gets team specified by hackerId and places it within req.body - */ -async function getByHackerId(req, res, next) { - const hacker = await Services.Hacker.findById(req.body.hackerId); - - if (!hacker) { - return next({ - status: 404, - message: Constants.Error.HACKER_404_MESSAGE, - data: req.body.hackerId - }); - } - - const team = await Services.Team.findById(hacker.teamId); - - if (!team) { - return next({ - status: 500, - message: Constants.Error.TEAM_READ_500_MESSAGE, - data: hacker.teamId - }); - } - - req.body.team = team; - next(); -} - -/** - * @function getTeamIdByUser - * @param {{user: {id: ObjectId}}} req - * @param {JSON} res - * @param {(err?)=>void} next - * @return {void} - * @description gets teamId specified by the user account, and places it in req.body.teamId. - */ -async function getTeamIdByUser(req, res, next) { - const hacker = await Services.Hacker.findByAccountId(req.user.id); - - if (!hacker) { - return next({ - status: 404, - message: Constants.Error.Hacker, - data: { - id: req.user.id - } - }); - } - - req.body.teamId = hacker.teamId; - next(); -} - -/** - * @function ensureFreeTeamName - * @param {{body: {teamDetails: {name: String}}}} req - * @param {JSON} res - * @param {(err?)=>void} next - * @return {void} - * @description Checks to see that the team name is not in use. - */ -async function ensureFreeTeamName(req, res, next) { - const teamDetails = req.body.teamDetails; - - const team = await Services.Team.findByName(teamDetails.name); - - if (team) { - return next({ - status: 409, - message: Constants.Error.TEAM_NAME_409_MESSAGE, - data: teamDetails.name - }); - } - - return next(); -} - -/** - * @async - * @function findById - * @param {{body: {id: ObjectId}}} req - * @param {*} res - * @return {JSON} Success or error status - * @description Finds a team by it's mongoId that's specified in req.param.id in route parameters. The id is moved to req.body.id from req.params.id by validation. - */ -async function findById(req, res, next) { - const team = await Services.Team.findById(req.body.id); - - if (!team) { - return next({ - status: 404, - message: Constants.Error.TEAM_404_MESSAGE, - data: {} - }); - } - - req.body.team = team; - return next(); -} - -/** - * @async - * @function deleteUserFromTeam - * @param {{user: {id: ObjectId}} req - * @param {*} res - * @return {JSON} Success or error status - * @description Removes the hacker associated with req.user.id from the team under teamId. If hacker is not part of a team, it does nothing. - */ -async function deleteUserFromTeam(req, res, next) { - const hacker = await Services.Hacker.findByAccountId(req.user.id); - - if (!hacker) { - return next({ - status: 404, - message: Constants.Error.HACKER_404_MESSAGE, - data: { - id: req.user.id - } - }); - } - const oldTeamId = hacker.teamId; - if (oldTeamId) { - await Services.Team.removeMember(oldTeamId, hacker._id); - await Services.Team.removeTeamIfEmpty(oldTeamId); - } - next(); -} - -/** - * @async - * @function updateHackerTeam - * @param {{body: {name: string}}} req - * @param {JSON} res - * @param {(err?)=>void} next - * @return {void} - * @description Adds the logged in user to the team specified by name. - */ -async function updateHackerTeam(req, res, next) { - const hacker = await Services.Hacker.findByAccountId(req.user.id); - - if (!hacker) { - return next({ - status: 404, - message: Constants.Error.HACKER_404_MESSAGE, - data: { - id: req.user.id - } - }); - } - - const receivingTeam = await Services.Team.findByName(req.body.name); - - if (!receivingTeam) { - return next({ - status: 404, - message: Constants.Error.TEAM_404_MESSAGE, - data: req.body.name - }); - } - - const previousTeamId = hacker.teamId; - - if (previousTeamId == receivingTeam._id) { - return next({ - status: 409, - message: Constants.Error.TEAM_JOIN_SAME_409_MESSAGE, - data: req.body.name - }); - } - - // remove hacker from previous team - if (previousTeamId != undefined) { - await Services.Team.removeMember(previousTeamId, hacker._id); - await Services.Team.removeTeamIfEmpty(previousTeamId); - } - - // add hacker to the new team and change teamId of hacker - const update = await Services.Team.addMember(receivingTeam._id, hacker._id); - - // Services.Hacker.updateOne should return a hacker object, as the hacker exists - if (!update) { - return next({ - status: 500, - message: Constants.Error.TEAM_UPDATE_500_MESSAGE, - data: hacker._id - }); - } - - return next(); -} - -/** - * @async - * @function findById - * @param {{body: {id: ObjectId}}} req - * @param {*} res - * @return {JSON} Success or error status - * @description Finds a team by it's mongoId that's specified in req.param.id in route parameters. The id is moved to req.body.id from req.params.id by validation. - */ -async function findById(req, res, next) { - const team = await Services.Team.findById(req.body.id); - - if (!team) { - return next({ - status: 404, - message: Constants.Error.TEAM_404_MESSAGE, - data: {} - }); - } - - req.body.team = team; - next(); -} - -/** - * @async - * @function populateMemberAccountsById - * @param {{body: {id: ObjectId}}} req - * @param {*} res - * @return {JSON} Success or error status - * @description - * Find the team by id and populates the accounts of the members. - * The team information is stored in req.body.team, and the member information is stored in req.body.teamMembers - */ -async function populateMemberAccountsById(req, res, next) { - const team = await Services.Team.findById(req.body.id).populate({ - path: "members", - populate: { - path: "accountId" - } - }); - - if (!team) { - return next({ - status: 404, - message: Constants.Error.TEAM_404_MESSAGE, - data: {} - }); - } - let hackerIds = []; - let teamMembers = []; - - for (const member of team.members) { - teamMembers.push({ - school: member.application.general.school, - status: member.status, - firstName: member.accountId.firstName, - lastName: member.accountId.lastName - }); - hackerIds.push(member._id); - } - team.members = hackerIds; - req.body.team = team; - req.body.teamMembers = teamMembers; - return next(); -} - -/** - * @function parseTeam - * @param {{body: {name: string, members: Object[], devpostURL: string, projectName: string}}} req - * @param {*} res - * @param {(err?)=>void} next - * @return {void} - * @description - * Moves name, members, devpostURL, projectName from req.body to req.body.teamDetails. - * Adds _id to teamDetails. - */ -function parseTeam(req, res, next) { - const teamDetails = { - _id: mongoose.Types.ObjectId(), - name: req.body.name, - members: req.body.members, - devpostURL: req.body.devpostURL, - projectName: req.body.projectName - }; - - delete req.body.name; - delete req.body.members; - delete req.body.devpostURL; - delete req.body.projectName; - - req.body.teamDetails = teamDetails; - - return next(); -} - -/** - * @function parsePatch - * @param {body: {id: ObjectId}} req - * @param {*} res - * @param {(err?) => void} next - * @return {void} - * @description - * Delete the req.body.id that was added by the validation of route parameter. - * Move attributes belonging to the team schema to req.body.teamDetails. - */ -function parsePatch(req, res, next) { - delete req.body.id; - - let teamDetails = {}; - - for (const val in req.body) { - // use .hasOwnProperty instead of 'in' to get rid of inherited properties such as 'should' - if (Team.schema.paths.hasOwnProperty(val)) { - teamDetails[val] = req.body[val]; - delete req.body[val]; - } - } - - req.body.teamDetails = teamDetails; - - next(); -} - -async function parseNewTeam(req, res, next) { - const teamDetails = { - _id: mongoose.Types.ObjectId(), - name: req.body.name, - members: [], - devpostURL: req.body.devpostURL, - projectName: req.body.projectName - }; - - delete req.body.name; - delete req.body.members; - delete req.body.devpostURL; - delete req.body.projectName; - - // hacker should exist because of authorization - const hacker = await Services.Hacker.findByAccountId(req.user.id); - - if (!hacker) { - return next({ - status: 404, - message: Constants.Error.HACKER_404_MESSAGE, - data: { - id: req.user.id - } - }); - } - - // hacker should not be in another team - if (hacker.teamId !== undefined && hacker.teamId !== null) { - return next({ - status: 409, - message: Constants.Error.TEAM_MEMBER_409_MESSAGE - }); - } - - teamDetails.members.push(hacker._id); - - req.body.teamDetails = teamDetails; - return next(); -} - -module.exports = { - parseTeam: parseTeam, - findById: Util.asyncMiddleware(findById), - createTeam: Util.asyncMiddleware(createTeam), - ensureUniqueHackerId: Util.asyncMiddleware(ensureUniqueHackerId), - ensureSpace: Util.asyncMiddleware(ensureSpace), - updateHackerTeam: Util.asyncMiddleware(updateHackerTeam), - getTeamIdByUser: Util.asyncMiddleware(getTeamIdByUser), - updateTeam: Util.asyncMiddleware(updateTeam), - getByHackerId: Util.asyncMiddleware(getByHackerId), - parsePatch: parsePatch, - parseNewTeam: Util.asyncMiddleware(parseNewTeam), - ensureFreeTeamName: Util.asyncMiddleware(ensureFreeTeamName), - populateMemberAccountsById: Util.asyncMiddleware( - populateMemberAccountsById - ), - getTeamIdByHackerId: Util.asyncMiddleware(getTeamIdByHackerId), - deleteUserFromTeam: Util.asyncMiddleware(deleteUserFromTeam) -}; diff --git a/middlewares/travel.middleware.js b/middlewares/travel.middleware.js deleted file mode 100644 index ad268b3f..00000000 --- a/middlewares/travel.middleware.js +++ /dev/null @@ -1,247 +0,0 @@ -"use strict"; - -const TAG = `[ TRAVEL.MIDDLEWARE.js ]`; -const mongoose = require("mongoose"); -const Services = { - Travel: require("../services/travel.service"), - Hacker: require("../services/hacker.service"), - Account: require("../services/account.service"), -}; -const Middleware = { - Util: require("./util.middleware") -}; -const Constants = { - General: require("../constants/general.constant"), - Error: require("../constants/error.constant") -}; - -/** - * @function parsePatch - * @param {body: {id: ObjectId}} req - * @param {*} res - * @param {(err?) => void} next - * @return {void} - * @description Delete the req.body.id that was added by the validation of route parameter. - */ -function parsePatch(req, res, next) { - delete req.body.id; - return next(); -} - - -/** - * @function parseTravel - * @param {{body: {accountId: ObjectId, hackerId: ObjectId, authorization: string}}} req - * @param {*} res - * @param {(err?)=>void} next - * @return {void} - * @description - * Moves accountId & hackerId from req.body to req.body.travelId. - * Adds _id to hackerDetails. - */ -function parseTravel(req, res, next) { - const travelDetails = { - _id: mongoose.Types.ObjectId(), - accountId: req.body.accountId, - hackerId: req.body.hackerId - }; - req.body.token = req.body.authorization; - - delete req.body.accountId; - delete req.body.hackerId; - - req.body.travelDetails = travelDetails; - - return next(); -} - -/** - * @function addRequestFromHacker - * @param {{body: {travelDetails: {request: Number}}}} req - * @param {JSON} res - * @param {(err?)=>void} next - * @return {void} - * @description - * Load travel request from hacker application and add it to - * req.body.travelDetails - */ -async function addRequestFromHacker(req, res, next) { - const hacker = await Services.Hacker.findById(req.body.travelDetails.accountId); - if (!hacker) { - return next({ - status: 500, - message: Constants.Error.HACKER_UPDATE_500_MESSAGE, - data: { - hackerId: hacker.id, - accountId: hacker.accountId - } - }); - } - req.body.travelDetails.request = hacker.application.accommodation.travel; - return next(); -} - -/** - * @function addDefaultStatusAndOffer - * @param {{body: {travelDetails: {status: String, offer: Number}}}} req - * @param {JSON} res - * @param {(err?)=>void} next - * @return {void} - * @description Adds default status and offer to travelDetails. - */ -function addDefaultStatusAndOffer(req, res, next) { - req.body.travelDetails.status = "None"; - req.body.travelDetails.offer = 0; - return next(); -} - -/** - * @function createTravel - * @param {{body: {hackerTravel: object}}} req - * @param {*} res - * @param {(err?)=>void} next - * @return {void} - * @description - * Creates travel document after making sure there is no other hacker with the same linked accountId or hackerId - */ -async function createTravel(req, res, next) { - const travelDetails = req.body.travelDetails; - - const exists = await Services.Travel.findByAccountId( - travelDetails.accountId - ); - - if (exists) { - return next({ - status: 422, - message: Constants.Error.ACCOUNT_DUPLICATE_422_MESSAGE, - data: { - id: travelDetails.accountId - } - }); - } - const travel = await Services.Travel.createTravel(travelDetails); - if (!!travel) { - req.body.travel = travel; - return next(); - } else { - return next({ - status: 500, - message: Constants.Error.TRAVEL_CREATE_500_MESSAGE, - data: {} - }); - } -} - -/** - * Updates a travel that is specified by req.params.id - * @param {{params:{id: string}, body: *}} req - * @param {*} res - * @param {*} next - */ -async function updateTravel(req, res, next) { - const travel = await Services.Travel.updateOne(req.params.id, req.body); - if (travel) { - return next(); - } else { - return next({ - status: 404, - message: Constants.Error.TRAVEL_404_MESSAGE, - data: { - id: req.params.id - } - }); - } -} - -/** - * @async - * @function findById - * @param {{body: {id: ObjectId}}} req - * @param {*} res - * @description Retrieves a travel's information via req.body.id, moving result to req.body.travel if succesful. - */ -async function findById(req, res, next) { - const travel = await Services.Travel.findById(req.body.id); - - if (!travel) { - return next({ - status: 404, - message: Constants.Error.TRAVEL_404_MESSAGE - }); - } - - req.body.travel = travel; - next(); -} - -async function findByEmail(req, res, next) { - const account = await Services.Account.findByEmail(req.body.email); - if (!account) { - return next({ - status: 404, - message: Constants.Error.ACCOUNT_404_MESSAGE, - error: {} - }); - } - const travel = await Services.Travel.findByAccountId(account._id); - if (!travel) { - return next({ - status: 404, - message: Constants.Error.TRAVEL_404_MESSAGE, - error: {} - }); - } - - req.body.travel = travel; - next(); -} - -/** - * Finds the travel information of the logged in user - * and places that information in req.body.travel - * @param {{user: {id: string}}} req - * @param {*} res - * @param {(err?)=>void} next - */ -async function findSelf(req, res, next) { - if ( - req.user.accountType != Constants.General.HACKER || - !req.user.confirmed - ) { - return next({ - status: 409, - message: Constants.Error.ACCOUNT_TYPE_409_MESSAGE, - error: { - id: req.user.id - } - }); - } - - const travel = await Services.Travel.findByAccountId(req.user.id); - - if (!!travel) { - req.body.travel = travel; - return next(); - } else { - return next({ - status: 409, - message: Constants.Error.TRAVEL_404_MESSAGE, - error: { - id: req.user.id - } - }); - } -} - -module.exports = { - parsePatch: parsePatch, - parseTravel: parseTravel, - addDefaultStatusAndOffer: addDefaultStatusAndOffer, - addRequestFromHacker: Middleware.Util.asyncMiddleware(addRequestFromHacker), - createTravel: Middleware.Util.asyncMiddleware(createTravel), - updateTravel: Middleware.Util.asyncMiddleware(updateTravel), - findById: Middleware.Util.asyncMiddleware(findById), - findByEmail: Middleware.Util.asyncMiddleware(findByEmail), - findSelf: Middleware.Util.asyncMiddleware(findSelf) -}; diff --git a/models/application.model.ts b/models/application.model.ts index 9f4931f3..6a6bf53e 100644 --- a/models/application.model.ts +++ b/models/application.model.ts @@ -1,14 +1,15 @@ +import { IsInt, IsJSON, IsString, Max } from "class-validator"; import { Entity, BaseEntity, PrimaryGeneratedColumn, Column, - ManyToOne, - JoinColumn + JoinColumn, + OneToOne } from "typeorm"; import Hacker from "./hacker.model"; -interface ApplicationSchema { +export interface ApplicationSchema { general: { school: string; degree: string; @@ -61,14 +62,15 @@ class Application extends BaseEntity { identifier: number; @Column({ nullable: false }) + @IsInt() year: number; @Column("jsonb", { nullable: false }) data: ApplicationSchema; - @ManyToOne( + @OneToOne( () => Hacker, - (hacker: Hacker) => hacker.applications + (hacker: Hacker) => hacker.application ) @JoinColumn() hacker: Hacker; diff --git a/models/hacker.model.ts b/models/hacker.model.ts index 9727c01d..85ee345f 100644 --- a/models/hacker.model.ts +++ b/models/hacker.model.ts @@ -1,11 +1,22 @@ import * as Constants from "../constants/general.constant"; -import { Column, Entity, JoinColumn, OneToMany, ManyToOne } from "typeorm"; +import { + Column, + Entity, + JoinColumn, + OneToMany, + ManyToOne, + OneToOne +} from "typeorm"; import Account from "./account.model"; -import Application from "./application.model"; +import Application, { ApplicationSchema } from "./application.model"; import Team from "./team.model"; @Entity() -class Hacker extends Account { +class Hacker { + @OneToOne(() => Account, { primary: true }) + @JoinColumn() + account: Account; + @Column({ enum: Constants.HACKER_STATUSES, nullable: false, @@ -13,35 +24,30 @@ class Hacker extends Account { }) status: string; - @OneToMany( - () => Application, - (application) => application.hacker - ) - @JoinColumn() - applications: Application[]; + @Column("jsonb") + application: ApplicationSchema; //TODO: Implement Team One To One @ManyToOne( () => Team, (team) => team.hackers ) - team: Team; + team?: Team; toJSON() { return this; } isApplicationComplete() { - const application = this.applications[this.applications.length - 1]; - if (application == null) return false; - - const portfolioDone = !!application.data.general.URL.resume; - const jobInterestDone = !!application.data.general.jobInterest; - const questionOneDone = !!application.data.shortAnswer.question1; - const questionTwoDone = !!application.data.shortAnswer.question2; - const previousHackathonsDone = !!application.data.shortAnswer + if (this.application == null) return false; + + const portfolioDone = !!this.application.general.URL.resume; + const jobInterestDone = !!this.application.general.jobInterest; + const questionOneDone = !!this.application.shortAnswer.question1; + const questionTwoDone = !!this.application.shortAnswer.question2; + const previousHackathonsDone = !!this.application.shortAnswer .previousHackathons; - const attendancePreferenceDone = !!application.data.accommodation + const attendancePreferenceDone = !!this.application.accommodation .attendancePreference; return ( diff --git a/models/sponsor.model.ts b/models/sponsor.model.ts index c2105805..309f661d 100644 --- a/models/sponsor.model.ts +++ b/models/sponsor.model.ts @@ -1,9 +1,16 @@ +import { + Entity, + Column, + ManyToMany, + JoinTable, + OneToOne, + JoinColumn +} from "typeorm"; import Account from "./account.model"; -import { Entity, Column, ManyToMany, JoinTable } from "typeorm"; import Hacker from "./hacker.model"; @Entity() -class Sponsor extends Account { +class Sponsor { @Column({ default: 0 }) tier: number; @@ -16,6 +23,10 @@ class Sponsor extends Account { @ManyToMany(() => Hacker) @JoinTable() nominees: Hacker[]; + + @OneToOne(() => Account, { primary: true }) + @JoinColumn() + account: Account; } export default Sponsor; diff --git a/models/team.model.ts b/models/team.model.ts index 153e7fa3..dcfc2305 100644 --- a/models/team.model.ts +++ b/models/team.model.ts @@ -28,10 +28,6 @@ class Team extends BaseEntity { @Column() project: string; - - toJSON() { - return this; - } } export default Team; diff --git a/models/travel.model.ts b/models/travel.model.ts index a6ad523d..f9d2d6c3 100644 --- a/models/travel.model.ts +++ b/models/travel.model.ts @@ -11,10 +11,7 @@ import Hacker from "./hacker.model"; @Entity() class Travel extends BaseEntity { - @PrimaryGeneratedColumn() - identifier: number; - - @OneToOne(() => Hacker) + @OneToOne(() => Hacker, { primary: true }) @JoinColumn() hacker: Hacker; @@ -30,10 +27,6 @@ class Travel extends BaseEntity { @Column({ default: 0 }) offer: number; - - toJSON() { - return this; - } } export default Travel; diff --git a/package-lock.json b/package-lock.json index eda2207f..c930b3ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -56,6 +56,7 @@ "@types/nodemailer": "^6.4.4", "@types/passport": "^1.0.7", "@types/passport-local": "^1.0.34", + "@types/qrcode": "^1.4.2", "@types/superagent": "^4.1.13", "@types/validator": "^13.7.0", "apidoc": "^0.28.1", @@ -621,6 +622,15 @@ "@types/passport": "*" } }, + "node_modules/@types/qrcode": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.4.2.tgz", + "integrity": "sha512-7uNT9L4WQTNJejHTSTdaJhfBSCN73xtXaHFyBJ8TSwiLhe4PRuTue7Iph0s2nG9R/ifUaSnGhLUOZavlBEqDWQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/qs": { "version": "6.9.7", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", @@ -8488,6 +8498,15 @@ "@types/passport": "*" } }, + "@types/qrcode": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.4.2.tgz", + "integrity": "sha512-7uNT9L4WQTNJejHTSTdaJhfBSCN73xtXaHFyBJ8TSwiLhe4PRuTue7Iph0s2nG9R/ifUaSnGhLUOZavlBEqDWQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/qs": { "version": "6.9.7", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", diff --git a/package.json b/package.json index d254f527..0ed1fc7e 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "@types/nodemailer": "^6.4.4", "@types/passport": "^1.0.7", "@types/passport-local": "^1.0.34", + "@types/qrcode": "^1.4.2", "@types/superagent": "^4.1.13", "@types/validator": "^13.7.0", "apidoc": "^0.28.1", diff --git a/routes/api/sponsor.js b/routes/api/sponsor.js deleted file mode 100644 index 41fac841..00000000 --- a/routes/api/sponsor.js +++ /dev/null @@ -1,189 +0,0 @@ -"use strict"; - -const express = require("express"); - -const Controllers = { - Sponsor: require("../../controllers/sponsor.controller") -}; -const Middleware = { - Validator: { - /* Insert the require statement to the validator file here */ - Sponsor: require("../../middlewares/validators/sponsor.validator"), - RouteParam: require("../../middlewares/validators/routeParam.validator") - }, - /* Insert all of ther middleware require statements here */ - parseBody: require("../../middlewares/parse-body.middleware"), - Sponsor: require("../../middlewares/sponsor.middleware"), - Auth: require("../../middlewares/auth.middleware") -}; -const Services = { - Sponsor: require("../../services/sponsor.service") -}; -const CONSTANTS = require("../../constants/general.constant"); - -module.exports = { - activate: function(apiRouter) { - const sponsorRouter = new express.Router(); - - /** - * @api {get} /sponsor/self get information about logged in sponsor - * @apiName self - * @apiGroup Hacker - * @apiVersion 1.4.1 - * - * @apiSuccess {String} message Success message - * @apiSuccess {Object} data Sponsor object - * @apiSuccessExample {object} Success-Response: - * { - "message": "Successfully retrieved sponsor information", - "data": { - "id": "5bff4d736f86be0a41badb91", - "accountId": "5bff4d736f86be0a41badb99", - "tier": 3, - "company": "companyName", - "contractURL": "https://www.contractHere.com", - "nominees": ["5bff4d736f86be0a41badb93","5bff4d736f86be0a41badb94"] - } - } - - * @apiError {String} message Error message - * @apiError {Object} data empty - * @apiErrorExample {object} Error-Response: - * {"message": "Sponsor not found", "data": {}} - * @apiPermission: Sponsor - */ - sponsorRouter.route("/self").get( - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized(), - - Middleware.Sponsor.findSelf, - Controllers.Sponsor.showSponsor - ); - - /** - * @api {get} /sponsor/:id get a sponsor's information - * @apiName getSponsor - * @apiGroup Sponsor - * @apiVersion 0.0.8 - * - * @apiParam (param) {string} id a sponsor's unique mongoID - * - * @apiSuccess {String} message Success message - * @apiSuccess {Object} data Sponsor object - * @apiSuccessExample {object} Success-Response: - * { - "message": "Successfully retrieved sponsor information", - "data": { - "id": "5bff4d736f86be0a41badb91", - "accountId": "5bff4d736f86be0a41badb99", - "tier": 3, - "company": "companyName", - "contractURL": "https://www.contractHere.com", - "nominees": ["5bff4d736f86be0a41badb93","5bff4d736f86be0a41badb94"] - } - } - - * @apiError {String} message Error message - * @apiError {Object} data empty - * @apiErrorExample {object} Error-Response: - * {"message": "Sponsor not found", "data": {}} - */ - sponsorRouter.route("/:id").get( - Middleware.Validator.RouteParam.idValidator, - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized([Services.Sponsor.findById]), - - Middleware.parseBody.middleware, - - Middleware.Sponsor.findById, - Controllers.Sponsor.showSponsor - ); - - /** - * @api {post} /sponsor/ create a new sponsor - * @apiName createSponsor - * @apiGroup Sponsor - * @apiVersion 0.0.8 - * - * @apiParam (body) {MongoID} accountId ObjectID of the respective account. - * @apiParam (body) {Number} tier Tier of the sponsor, from 0 to 5. 0 is lowest tier, and 5 is the custom tier. - * @apiParam (body) {String} company Name of the company. - * @apiParam (body) {String} contractURL URL link to the contract with the company. - * @apiParam (body) {MongoID[]} nominees Array of accounts that the company wish to nominate as hackers. - * - * @apiSuccess {String} message Success message - * @apiSuccess {Object} data Sponsor object - * @apiSuccessExample {object} Success-Response: - * { - "message": "Sponsor creation successful", - "data": {...} - } - - * @apiError {String} message Error message - * @apiError {Object} data empty - * @apiErrorExample {object} Error-Response: - * {"message": "Error while creating sponsor", "data": {}} - */ - sponsorRouter.route("/").post( - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized(), - - // validation - Middleware.Validator.Sponsor.newSponsorValidator, - - // parsing - Middleware.parseBody.middleware, - // middleware to ensure account is a sponsor type - Middleware.Sponsor.validateConfirmedStatus, - // middleware to ensure that there is not a duplicate sponsor with the same accountId - Middleware.Sponsor.checkDuplicateAccountLinks, - - Middleware.Sponsor.parseSponsor, - - Middleware.Auth.addAccountTypeRoleBinding, - - Middleware.Sponsor.createSponsor, - Controllers.Sponsor.createdSponsor - ); - - /** - * @api {patch} /sponsor/ update a sponsor - * @apiName patchSponsor - * @apiGroup Sponsor - * @apiVersion 1.3.0 - * - * @apiParam (param) {ObjectId} id ObjectID of the sponsor - * @apiParam (body) {String} company Name of the company. - * @apiParam (body) {String} contractURL URL link to the contract with the company. - * @apiParam (body) {ObjectId[]} nominees Array of accounts that the company wish to nominate as hackers. - * - * @apiSuccess {String} message Success message - * @apiSuccess {Object} data Sponsor object - * @apiSuccessExample {object} Success-Response: - * { - "message": "Sponsor update successful", - "data": {...} - } - - * @apiError {String} message Error message - * @apiError {Object} data empty - * @apiErrorExample {object} Error-Response: - * {"message": "Error while updating sponsor", "data": {}} - */ - sponsorRouter.route("/:id").patch( - Middleware.Validator.RouteParam.idValidator, - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized([Services.Sponsor.findById]), - - Middleware.Validator.Sponsor.updateSponsorValidator, - - Middleware.parseBody.middleware, - Middleware.Sponsor.parsePatch, - - Middleware.Sponsor.updateSponsor, - Controllers.Sponsor.updatedSponsor - ); - - apiRouter.use("/sponsor", sponsorRouter); - } -}; diff --git a/routes/api/team.js b/routes/api/team.js deleted file mode 100644 index c5508061..00000000 --- a/routes/api/team.js +++ /dev/null @@ -1,219 +0,0 @@ -"use strict"; - -const express = require("express"); - -const Controllers = { - Team: require("../../controllers/team.controller") -}; -const Middleware = { - Validator: { - /* Insert the require statement to the validator file here */ - Team: require("../../middlewares/validators/team.validator"), - RouteParam: require("../../middlewares/validators/routeParam.validator") - }, - /* Insert all of ther middleware require statements here */ - parseBody: require("../../middlewares/parse-body.middleware"), - Team: require("../../middlewares/team.middleware"), - Auth: require("../../middlewares/auth.middleware") -}; -const Services = { - Hacker: require("../../services/hacker.service") -}; - -module.exports = { - activate: function (apiRouter) { - const teamRouter = new express.Router(); - - /** - * @api {post} /team/ create a new team consisting of only the logged in user - * @apiName createTeam - * @apiGroup Team - * @apiVersion 0.0.8 - * - * @apiParam (body) {String} name Name of the team. - * @apiParam (body) {String} [devpostURL] Devpost link to hack. Once the link is sent, the hack will be considered to be submitted. - * @apiParam (body) {String} [projectName] Name of the team. - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data Team object - * @apiSuccessExample {object} Success-Response: - * { - "message": "Team creation successful", - "data": {...} - } - - * @apiError {string} message Error message - * @apiError {object} data empty - * @apiErrorExample {object} Error-Response: - * {"message": "Error while creating team", "data": {}} - */ - teamRouter.route("/").post( - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized(), - // Validators - Middleware.Validator.Team.newTeamValidator, - Middleware.parseBody.middleware, - Middleware.Team.parseNewTeam, - - Middleware.Team.ensureFreeTeamName, - - Middleware.Team.createTeam, - Controllers.Team.createdTeam - ); - - /** - * @api {patch} /team/join/ Allows a logged in hacker to join a team by name - * @apiName patchJoinTeam - * @apiGroup Team - * @apiVersion 1.1.1 - * - * @apiParam (body) {string} [name] Name of the team to join - * @apiSuccess {string} message Success message - * @apiSuccess {object} data {} - * @apiSuccessExample {object} Success-Response: - * { - * "message": "Team join successful.", - * "data": {} - * } - */ - teamRouter.route("/join/").patch( - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized(), - - Middleware.Validator.Team.joinTeamValidator, - // need to check that the team is not full - Middleware.Team.ensureSpace, - - Middleware.Team.updateHackerTeam, - - Controllers.Team.joinedTeam - ); - - /** - * @api {patch} /team/leave/ Allows a logged in hacker to leave current team - * @apiName deleteSelfFromTeam - * @apiGroup Team - * @apiVersion 1.1.1 - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data {} - * @apiSuccessExample {object} Success-Response: - * { - * "message": "Removal from team successful.", - * "data": {} - * } - */ - teamRouter - .route("/leave") - .patch( - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized(), - Middleware.Team.deleteUserFromTeam, - Controllers.Team.leftTeam - ); - - /** - * @api {get} /team/:id get a team's information - * @apiName getTeam - * @apiGroup Team - * @apiVersion 0.0.8 - * - * @apiParam (param) {ObjectId} id MongoId of the team - * - * @apiSuccess {String} message Success message - * @apiSuccess {Object} data Team object - * @apiSuccessExample {object} Success-Response: - * { - "message": "Team retrieval successful", - "data": { - "team": { - "name":"foo", - "members": [ - ObjectId('...') - ], - "devpostURL": "www.devpost.com/foo", - "projectName": "fooey" - }, - "members": [ - { - "firstName": "John", - "lastName": "Doe", - "school": "McGill University", - "status": "Applied" - } - ], - } - } - - * @apiError {String} message Error message - * @apiError {Object} data empty - * @apiErrorExample {object} Error-Response: - * {"message": "Team not found", "data": {}} - */ - teamRouter.route("/:id").get( - Middleware.Validator.RouteParam.idValidator, - Middleware.Auth.ensureAuthenticated(), - // get is available for all teams, or no teams. No authorization is done on the :id parameter. - // However, a function is needed, so the identity function is put here. In reality, the route - // is /api/team/:all, so the id is not checked. The returned object places the id inside accountId - // to be consistent with other findById functions - Middleware.Auth.ensureAuthorized([ - (id) => { - return { - accountId: id - }; - } - ]), - - Middleware.parseBody.middleware, - - Middleware.Team.populateMemberAccountsById, - Controllers.Team.showTeam - ); - - /** - * @api {patch} /team/:hackerId Update a team's information. The team is specified by the hacker belonging to it. - * @apiName patchTeam - * @apiGroup Team - * @apiVersion 0.0.8 - * @apiDescription - * We use hackerId instead of teamId because authorization requires - * a one-to-one mapping from param id to accountId, but we are not able - * to have that from teamId to accountId due to multiple members in a team. - * Instead, we use hackerId, as there is a 1 to 1 link between hackerId to teamId, - * and a 1 to 1 link between hackerId and accountId - * - * - * @apiParam (param) {ObjectId} hackerId a hacker's unique Id - * - * @apiSuccess {String} message Success message - * @apiSuccess {Object} data Team object - * @apiSuccessExample {object} Success-Response: - * { - "message": "Team update successful.", - "data": {...} - } - - * @apiError {String} message Error message - * @apiError {Object} data Query input that caused the error. - * @apiErrorExample {object} Error-Response: - * {"message": "Team not found", "data": {teamId}} - */ - teamRouter.route("/:hackerId").patch( - Middleware.Auth.ensureAuthenticated(), - Middleware.Validator.RouteParam.hackeridValidator, - Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), - - Middleware.Validator.Team.patchTeamValidator, - Middleware.parseBody.middleware, - Middleware.Team.parsePatch, - - Middleware.Team.getTeamIdByHackerId, - Middleware.Team.updateTeam, - - Controllers.Team.updatedTeam - ); - - apiRouter.use("/team", teamRouter); - } -}; diff --git a/routes/api/travel.js b/routes/api/travel.js deleted file mode 100644 index 41a8994c..00000000 --- a/routes/api/travel.js +++ /dev/null @@ -1,249 +0,0 @@ -"use strict"; -const express = require("express"); -const Controllers = { - Travel: require("../../controllers/travel.controller") -}; -const Middleware = { - Validator: { - /* Insert the require statement to the validator file here */ - Travel: require("../../middlewares/validators/travel.validator"), - RouteParam: require("../../middlewares/validators/routeParam.validator") - }, - /* Insert all of ther middleware require statements here */ - parseBody: require("../../middlewares/parse-body.middleware"), - Util: require("../../middlewares/util.middleware"), - Travel: require("../../middlewares/travel.middleware"), - Hacker: require("../../middlewares/hacker.middleware"), - Auth: require("../../middlewares/auth.middleware"), - //Search: require("../../middlewares/search.middleware") -}; -const Services = { - Travel: require('../../services/travel.service'), - Hacker: require("../../services/hacker.service"), - Account: require("../../services/account.service") -}; -const CONSTANTS = require("../../constants/general.constant"); - -module.exports = { - activate: function (apiRouter) { - const travelRouter = express.Router(); - - - travelRouter.route("/").get( - Controllers.Travel.okay - ) - - /** - * @api {get} /travel/self get information about own hacker's travel - * @apiName self - * @apiGroup Travel - * @apiVersion 2.0.1 - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data Travel object - * @apiSuccessExample {object} Success-Response: - * { - "message": "Travel found by logged in account id", - "data": { - "id":"5bff4d736f86be0a41badb91", - "status": "Claimed" - "request": 90, - "offer": 80 - } - } - - * @apiError {string} message Error message - * @apiError {object} data empty - * @apiErrorExample {object} Error-Response: - * {"message": "Travel not found", "data": {}} - */ - travelRouter.route("/self").get( - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized(), - - Middleware.Travel.findSelf, - Controllers.Travel.showTravel - ); - - /** - * @api {get} /travel/:id get a traveler's information - * @apiName getTravel - * @apiGroup Travel - * @apiVersion 2.0.1 - * - * @apiParam (param) {String} id a travel's unique mongoID - * - * @apiSuccess {String} message Success message - * @apiSuccess {Object} data Travel object - * @apiSuccessExample {object} Success-Response: - * { - "message": "Successfully retrieved travel information", - "data": { - "id":"5bff4d736f86be0a41badb91", - "status": "Valid", - "request": 100, - "offer": 50 - } - } - - * @apiError {String} message Error message - * @apiError {Object} data empty - * @apiErrorExample {object} Error-Response: - * {"message": "Travel not found", "data": {}} - */ - travelRouter.route("/:id").get( - Middleware.Validator.RouteParam.idValidator, - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized([Services.Hacker.findByAccountId]), - - Middleware.parseBody.middleware, - - Middleware.Travel.findById, - Controllers.Travel.showTravel - ); - - /** - * @api {get} /travel/email/:email get a travel's information - * @apiName getTravel - * @apiGroup Travel - * @apiVersion 2.0.1 - * - * @apiParam (param) {String} email a travel's unique email - * - * @apiSuccess {String} message Success message - * @apiSuccess {Object} data Travel object - * @apiSuccessExample {object} Success-Response: - * { - "message": "Successfully retrieved travel information", - "data": { - "id":"5bff4d736f86be0a41badb91", - "status": "Valid", - "request": 100, - "offer": 50 - } - } - - * @apiError {String} message Error message - * @apiError {Object} data empty - * @apiErrorExample {object} Error-Response: - * {"message": "Travel not found", "data": {}} - */ - travelRouter.route("/email/:email").get( - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized([Services.Account.findByEmail]), - - Middleware.Validator.RouteParam.emailValidator, - Middleware.parseBody.middleware, - - Middleware.Travel.findByEmail, - Controllers.Travel.showTravel - ); - - /** - * @api {post} /travel/ create a new travel - * @apiName createTravel - * @apiGroup Travel - * @apiVersion 2.0.1 - * - * @apiParam (body) {MongoID} accountId ObjectID of the respective account - * @apiParam (body) {MongoID} hackerId ObjectID of the respective hacker - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data Travel object - * @apiSuccessExample {object} Success-Response: - * { - * "message": "Travel creation successful", - * "data": { - * "id":"5bff4d736f86be0a41badb91", - * "status": "None", - * "request": 50, - * "offer": 0 - * } - * } - - * @apiError {string} message Error message - * @apiError {object} data empty - * @apiErrorExample {object} Error-Response: - * {"message": "Error while creating travel", "data": {}} - */ - travelRouter.route("/").post( - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized(), - Middleware.Validator.Travel.newTravelValidator, - - Middleware.parseBody.middleware, - // validate type - Middleware.Hacker.validateConfirmedStatusFromAccountId, - - Middleware.Travel.parseTravel, - - Middleware.Travel.addRequestFromHacker, - Middleware.Travel.addDefaultStatusAndOffer, - Middleware.Travel.createTravel, - - Controllers.Travel.createdTravel - ); - - /** - * @api {patch} /travel/status/:id update a traveler's status - * @apiName patchTravelStatus - * @apiGroup Travel - * @apiVersion 2.0.1 - * - * @apiParam (body) {string} [status] Status of the travel's reimbursement ("None"|"Bus"|"Offered"|"Valid"|"Invalid"|"Claimed") - * @apiSuccess {string} message Success message - * @apiSuccess {object} data Travel object - * @apiSuccessExample {object} Success-Response: - * { - * "message": "Changed travel information", - * "data": { - * "status": "Accepted" - * } - * } - * @apiPermission Administrator - */ - travelRouter.route("/status/:id").patch( - Middleware.Validator.RouteParam.idValidator, - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized([Services.Travel.findById]), - Middleware.Validator.Travel.updateStatusValidator, - Middleware.parseBody.middleware, - Middleware.Travel.parsePatch, - - Middleware.Travel.updateTravel, - Controllers.Travel.updatedTravel - ); - - /** - * @api {patch} /travel/offer/:id update a traveler's offer - * @apiName patchTravelOffer - * @apiGroup Travel - * @apiVersion 2.0.1 - * - * @apiParam (body) {number} [offer] Amount of money offered for travel - * @apiSuccess {string} message Success message - * @apiSuccess {object} data Travel object - * @apiSuccessExample {object} Success-Response: - * { - * "message": "Changed travel information", - * "data": { - * "offer": 75 - * } - * } - * @apiPermission Administrator - */ - travelRouter.route("/offer/:id").patch( - Middleware.Validator.RouteParam.idValidator, - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized([Services.Travel.findById]), - Middleware.Validator.Travel.updateOfferValidator, - Middleware.parseBody.middleware, - Middleware.Travel.parsePatch, - - Middleware.Travel.updateTravel, - Controllers.Travel.updatedTravel - ); - - apiRouter.use("/travel", travelRouter); - } -}; diff --git a/services/hacker.service.ts b/services/hacker.service.ts index 839be428..885dd10d 100644 --- a/services/hacker.service.ts +++ b/services/hacker.service.ts @@ -1,104 +1,62 @@ -import { UpdateResult } from "typeorm"; +import { autoInjectable, singleton } from "tsyringe"; +import { getRepository, Repository, UpdateResult } from "typeorm"; import Hacker from "../models/hacker.model"; -const logger = require("./logger.service"); +import { toDataURL } from "qrcode"; +import { EnvService } from "./env.service"; const cache = require("memory-cache"); -const Constants = require("../constants/general.constant"); +@autoInjectable() +@singleton() +export class HackerService { + private readonly hackerRepository: Repository; -const QRCode = require("qrcode"); - -/** - * @function createHacker - * @param {{_id: ObjectId, accountId: ObjectId, application: {Object}}} hackerDetails - * @return {Promise} The promise will resolve to a hacker object if save is successful. - * @description Adds a new hacker to database. - */ -async function createHacker(hackerDetails: Object): Promise { - const TAG = `[Hacker Service # createHacker]:`; + constructor(private readonly envService: EnvService) { + this.hackerRepository = getRepository(Hacker); + } - //if (Date.now() < Constants.APPLICATION_CLOSE_TIME) { - let hacker = Hacker.create(hackerDetails); - return await hacker.save(); - //} - //throw new Error("Sorry, the application deadline has passed!"); -} + public async findByIdentifier( + identifier: number + ): Promise { + return await this.hackerRepository.findOne({ + relations: ["account"], + where: { account: { identifier: identifier } } + }); + } -/** - * @function updateOne - * @param {ObjectId} id - * @param {{_id?: ObjectId, accountId?: ObjectId, application?: {Object}, teamId?: ObjectId}} hackerDetails - * @return {DocumentQuery} The document query will resolve to hacker or null. - * @description Update an account specified by its mongoId with information specified by hackerDetails. - */ -async function updateOne( - identifier: number, - hackerDetails: Object -): Promise { - const TAG = `[Hacker Service # update ]:`; - - return await Hacker.update(identifier, hackerDetails).then((hacker) => { - logger.updateCallbackFactory(TAG, "hacker"); - return hacker; - }); -} + public async save(hacker: Hacker): Promise { + return await this.hackerRepository.save(hacker); + } -/** - * @function findById - * @param {ObjectId} id - * @return {DocumentQuery} The document query will resolve to hacker or null. - * @description Finds an hacker by the id, which is the mongoId. - */ -async function findById(identifier: number): Promise { - const TAG = `[Hacker Service # findById ]:`; - - return await Hacker.findOne(identifier).then((hacker) => { - logger.queryCallbackFactory(TAG, "hacker", identifier); - return hacker; - }); -} + public async update( + identifier: number, + hacker: Partial + ): Promise { + return await this.hackerRepository.update(identifier, hacker); + } -/** - * @async - * @function findOne - * @param {ObjectID} query - * @return {Hacker | null} either hacker or null - * @description Finds an hacker by some query. - */ -async function findIds(queries: Object[]): Promise<(Hacker | undefined)[]> { - const TAG = `[Hacker Service # findIds ]:`; - let ids = []; - - for (const query of queries) { - let current = await Hacker.findOne({ where: query }).then( - (hacker: Hacker) => { - logger.queryCallbackFactory(TAG, "hacker", query); - return hacker; - } - ); - ids.push(current); + public async generateQRCode(data: string) { + return await toDataURL(data, { + scale: 4 + }); } - return ids; -} -//TODO - Remove this function, it is redundant. -/** - * @function findByAccountId - * @param {number} accountId - * @return {Promise} A hacker document queried by accountId - */ -function findByAccountId(accountId: number): Promise { - const TAG = `[ Hacker Service # findByAccountId ]:`; - const query = { - identifier: accountId - }; + public generateHackerApplicationViewLink(identifier: string): string { + const domain = this.getDomain()!; + const protocol = domain.includes("localhost") ? "http" : "https"; + return `${protocol}://${domain}/application/view/${identifier}`; + } - return Hacker.findOne({ where: query }).then((hacker: Hacker) => { - logger.updateCallbackFactory(TAG, "hacker"); - return hacker; - }); + private getDomain() { + return this.envService.isDevelopment() + ? this.envService.get(`FRONTEND_ADDRESS_DEV`) + : this.envService.isProduction() + ? this.envService.get(`FRONTEND_ADDRESS_DEPLOY`) + : this.envService.get(`FRONTEND_ADDRESS_DEV`); + } } +/* async function getStatsAllHackersCached() { const TAG = `[ hacker Service # getStatsAll ]`; if (cache.get(Constants.CACHE_KEY_STATS) !== null) { @@ -113,35 +71,9 @@ async function getStatsAllHackersCached() { const stats = getStats(allHackers); cache.put(Constants.CACHE_KEY_STATS, stats, Constants.CACHE_TIMEOUT_STATS); //set a time-out of 5 minutes return stats; -} - -/** - * Generate a QR code for the hacker. - * @param {string} str The string to be encoded in the QR code. - */ -async function generateQRCode(str: string) { - const response = await QRCode.toDataURL(str, { - scale: 4 - }); - return response; -} +}*/ -/** - * Generate the link for the single hacker view page on frontend. - * @param {string} httpOrHttps either HTTP or HTTPs - * @param {string} domain The domain of the frontend site - * @param {string} id The ID of the hacker to view - */ -function generateHackerViewLink( - httpOrHttps: string, - domain: string, - id: number -) { - const link = `${httpOrHttps}://${domain}/application/view/${id}`; - return link; -} - -function getStats(hackers: Hacker[]): Object { +/*function getStats(hackers: Hacker[]): Object { const TAG = `[ hacker Service # getStats ]`; const stats = { total: 0, @@ -236,18 +168,6 @@ function getStats(hackers: Hacker[]): Object { ? stats.applicationDate[applicationDate] + 1 : 1; */ - }); - return stats; -} - -export { - createHacker, - findById, - updateOne, - findIds, - findByAccountId, - getStats, - getStatsAllHackersCached, - generateQRCode, - generateHackerViewLink -}; +//}); +//return stats; +//} diff --git a/services/sponsor.service.ts b/services/sponsor.service.ts index 00e448b8..ee9c3f90 100644 --- a/services/sponsor.service.ts +++ b/services/sponsor.service.ts @@ -1,73 +1,33 @@ -"use strict"; import { UpdateResult } from "typeorm"; -import Sponsor from "../models/sponsor.model"; import * as logger from "./logger.service"; -/** - * @function findById - * @param {number} identifier - * @return {Promise} The document query will resolve to a sponsor or null. - * @description Find a sponsor by id - */ -function findById(identifier: number): Promise { - const TAG = `[Sponsor Service # findById]:`; - - return Sponsor.findOne(identifier).then((sponsor) => { - logger.queryCallbackFactory(TAG, "sponsor", identifier); - return sponsor; - }); -} - -/** - * @function createSponsor - * @param {{_id: ObjectId, accountId: ObjectId, tier: number, company: string, contractURL: string, nominees: ObjectId[]}} sponsorDetails - * @return {Promise} The promise will resolve to a sponsor object if save was successful. - * @description Adds a new sponsor to database. - */ -async function createSponsor(sponsorDetails: Object): Promise { - const TAG = `[Sponsor Service # createSponsor]:`; - - const sponsor = Sponsor.create(sponsorDetails); - - return await sponsor.save(); -} - -/** - * @function updateOne - * @param {ObjectId} id - * @param {{company?: string, contractURL?: string, nominees?: ObjectId[]}} sponsorDetails - * @return {Promise} The promise will resolve to a sponsor object if update was successful. - * @description Updates a sponsor by id with information in sponsorDetails. Return the updated sponsor - */ -async function updateOne( - identifier: number, - sponsorDetails: Object -): Promise { - const TAG = `[Sponsor Service # updateOne]:`; - - return await Sponsor.update(identifier, sponsorDetails); -} - -// TODO - Remove this function, it's redundant. -/** - * @function findByAccountId - * @param {number} identifier - * @return {Promise} A sponsor document queried by accountId - */ -function findByAccountId(identifier: number): Promise { - const TAG = `[ Sponsor Service # findByAccountId ]:`; +import { autoInjectable, singleton } from "tsyringe"; +import { getRepository, Repository } from "typeorm"; +import Sponsor from "../models/sponsor.model"; - return Sponsor.findOne(identifier).then((sponsor) => { - logger.updateCallbackFactory(TAG, "sponsor"); - return sponsor; - }); +@autoInjectable() +@singleton() +export class SponsorService { + constructor( + private readonly sponsorRepository: Repository = getRepository( + Sponsor + ) + ) {} + + public async findByIdentifier( + identifier: number + ): Promise { + return await this.sponsorRepository.findOne(identifier); + } + + public async save(sponsor: Sponsor): Promise { + return await this.sponsorRepository.save(sponsor); + } + + public async update( + identifier: number, + sponsor: Partial + ): Promise { + return await this.sponsorRepository.update(identifier, sponsor); + } } - -module.exports = { - findByAccountId: findByAccountId, - findById: findById, - createSponsor: createSponsor, - updateOne: updateOne -}; - -export { findByAccountId, findById, createSponsor, updateOne }; diff --git a/services/team.service.ts b/services/team.service.ts index 8c67c740..29dd635e 100644 --- a/services/team.service.ts +++ b/services/team.service.ts @@ -1,247 +1,81 @@ import Team from "../models/team.model"; -import hacker from "../routes/api/hacker"; -import { BaseEntity, UpdateResult } from "typeorm"; +import { getRepository, Repository, UpdateResult } from "typeorm"; +import { autoInjectable, singleton } from "tsyringe"; +import Hacker from "../models/hacker.model"; -const logger = require("./logger.service"); -const Services = { - Hacker: require("../services/hacker.service") -}; -const Middleware = { - Util: require("../middlewares/util.middleware") -}; +@autoInjectable() +@singleton() +export class TeamService { + private readonly teamRepository: Repository; -/** - * @function findTeamByHackerId - * @param {number} hackerId objectID of the hacker - * @return {DocumentQuery} The document query will resolve to a team or null. - * @description Finds the team that the hacker belongs to, or undefined. - */ -async function findTeamByHackerId(hackerId: number): Promise { - const TAG = `[Team Service # findTeamByHackerId]:`; - - const query = { hackers: hackerId }; - - return await Team.findOne({ where: query }).then((team) => { - logger.queryCallbackFactory(TAG, "team", query); - return team; - }); -} - -/** - * @function createTeam - * @param {{_id: ObjectId, name: string, members: ObjectId[], devpostURL: string, projectName: string}} teamDetails - * @return {Promise} The promise will resolve to a team object if save was successful. - * @description Adds a new team to database. - */ -async function createTeam(teamDetails: Object): Promise { - const TAG = `[Team Service # createTeam]:`; - - const team = Team.create(teamDetails); - return await team.save(); -} - -/** - * @function updateOne - * @param {ObjectId} id - * @param {{name?: string, devpostURL?: string, projectName?: string}} teamDetails - * @return {DocumentQuery} The document query will resolve to team or null. - * @description Update a team specified by its mongoId with information specified by teamDetails. - */ - -async function updateOne( - identifier: number, - teamDetails: Object -): Promise { - const TAG = `[Team Service # updateOne]:`; - - return await Team.update(identifier, teamDetails).then((team) => { - logger.updateCallbackFactory(TAG, "team"); - return team; - }); -} - -/** - * @function findById - * @param {number} identifier - * @return {DocumentQuery} The document query will either resolve to a team or null. - * @description Finds a team by its mongoID. - */ -async function findById(identifier: number): Promise { - const TAG = `[Team Service # findById]:`; - - return await Team.findOne(identifier).then((team) => { - logger.queryCallbackFactory(TAG, "team", identifier); - return team; - }); -} - -/** - * @function findByName - * @param {String} name - * @return {DocumentQuery} The document query will either resolve to a team or null. - * @description Finds a team by its team name. - */ -function findByName(name: string): Promise { - const TAG = `[Team Services # findByName]:`; - - const query = { - name: name - }; - - return Team.findOne({ where: query }).then((team: Team) => { - logger.queryCallbackFactory(TAG, "team", query); - return team; - }); -} - -/** - * @async - * @function removeMember - * @param {number} teamId - * @param {number} hackerId - * @return {DocumentQuery} The document query will resolve to the number of objects removed, or null. - * @description Removes the hacker specified by hackerId from a team specified by teamId. - */ -async function removeMember(teamId: number, identifier: number) { - const TAG = `[Team Services # removeMember]:`; - - const hacker = await Services.Hacker.updateOne(identifier, { - team: null - }); + constructor() { + this.teamRepository = getRepository(Team); + } - if (!hacker) { - return null; + public async findByIdentifier(identifier: number) { + return await this.teamRepository.findOne(identifier); } - // TODO - Implement this functionality. - /* return Team.findOneAndUpdate( - { - ident: teamId - }, - { - $pull: { - members: hackerId - } - } - );*/ - return null; -} + public async findByName(name: string) { + return await this.teamRepository.findOne({ where: { name: name } }); + } -/** - * @async - * @function addMember - * @param {ObjectId} teamId - * @param {ObjectId} hackerId - * @return {DocumentQuery} Query evaluates to object that details the number of modified documents, or null. - * @description Add the hacker specified by hackerId to the team specified by teamId - */ -async function addMember(teamId: number, hackerId: number) { - const TAG = `[Team Services # addMember]:`; + public async findByHacker({ account }: Hacker) { + const identifier = account.identifier; + return await this.teamRepository + .createQueryBuilder("team") + .leftJoinAndSelect("team.hackers", "hacker") + .where("hacker.accountIdentifier = :identifier", { identifier }) + .getOne(); + } - const hacker = await Services.Hacker.updateOne(hackerId, { - $set: { - teamId: teamId + public async addMember( + identifier: number, + hacker: Hacker + ): Promise { + const team = await this.findByIdentifier(identifier); + + if (team && team.hackers.length < 4) { + await this.teamRepository + .createQueryBuilder() + .relation("hackers") + .of(team) + .add(hacker); + return true; } - }); - if (!hacker) { - return null; + return false; } - // TODO - Implement this functionality. - /* - return Team.update( - { - _id: teamId - }, - { - $push: { - members: [hackerId] - } + public async removeMember( + identifier: number, + hacker: Hacker + ): Promise { + const team = await this.findByIdentifier(identifier); + + if (team) { + await this.teamRepository + .createQueryBuilder() + .relation("hackers") + .of(team) + .remove(hacker); + // This team had 1 hacker left, and we removed them just above, thus we delete it. + if (team.hackers.length == 1) + await this.teamRepository.remove(team); + return true; } - );*/ - return null; -} - -/** - * @async - * @function removeTeamIfEmpty - * @param {ObjectId} teamId - * @return {Promise} Query evaluates to object that details the number of modified documents, or null. - * @description Removes the team if the team contains no members. Returns null if the team has one or more members, or if the team doesn't exist. - */ -async function removeTeamIfEmpty(teamId: number) { - const TAG = `[Team Services # removeTeam]`; - - const team = await findById(teamId); - if (team?.hackers.length === 0) { - return Team.delete(teamId); + return false; } - return null; -} - -/** - * @async - * @function removeTeam - * @param {ObjectId} teamId - * @return {DocumentQuery} The document query will resolve to the number of objects removed, or null. - * @description Delete the team specified by teamId. - */ -async function removeTeam(teamId: number) { - const TAG = `[Team Services # removeTeam]`; - - const team = await findById(teamId); - - if (team == null) return null; - - for (const hackerId of team.hackers) { - await removeMember(teamId, hackerId.identifier); + public async update( + identifier: number, + team: Partial + ): Promise { + return await this.teamRepository.update(identifier, team); } - return Team.delete(teamId); -} - -/** - * @async - * @function getSize - * @param {*} name - * @return {number} If the team exists, return the number of members in the team. Otherwise, returns -1. - * @description Gets the number of current members of a team defined by name - */ -async function getSize(name: string): Promise { - const team = await findByName(name); - - if (!team) { - return -1; - } else { - return team.hackers.length; + public async save(team: Team): Promise { + return await this.teamRepository.save(team); } } - -/** - * @async - * @function isTeamIdValid - * @param {number} id - * @return {boolean} - * @description Checks whether a Team with the specified mongoID exists. - */ -async function isTeamIdValid(identifier: number): Promise { - const team = await findById(identifier); - return !!team; -} - -module.exports = { - isTeamIdValid: isTeamIdValid, - createTeam: createTeam, - findTeamByHackerId: findTeamByHackerId, - findById: findById, - findByName: findByName, - getSize: getSize, - removeMember: removeMember, - removeTeam: removeTeam, - addMember: addMember, - updateOne: updateOne, - removeTeamIfEmpty: removeTeamIfEmpty -}; diff --git a/services/travel.service.ts b/services/travel.service.ts index 5d034e60..13dfa5aa 100644 --- a/services/travel.service.ts +++ b/services/travel.service.ts @@ -1,94 +1,37 @@ import Travel from "../models/travel.model"; -const logger = require("./logger.service"); -import { UpdateResult } from "typeorm"; +import { getRepository, Repository, UpdateResult } from "typeorm"; +import { autoInjectable } from "tsyringe"; +import Hacker from "../models/hacker.model"; -// const Constants = require("../constants/general.constant"); +@autoInjectable() +export class TravelService { + private readonly travelRepository: Repository; -/** - * @function createTravel - * @param {{_id: ObjectId, accountId: ObjectId, status: enum of Constants.TRAVEL_STATUSES, request: Number, offer?: number}} travelDetails - * @return {Promise} The promise will resolve to a travel object if save is successful. - * @description Adds a new travel to database. - */ -async function createTravel(travelDetails: Object): Promise { - const TAG = `[Travel Service # createTravel]:`; - - const travel = Travel.create(travelDetails); - return await travel.save(); -} - -/** - * @function updateOne - * @param {number} identifier - * @param {{_id?: ObjectId, accountId?: ObjectId, status?: enum of Constants.TRAVEL_STATUSES, request?: Number, offer?: number}} travelDetails - * @return {Promise} The document query will resolve to travel or null. - * @description Update an travel specified by its mongoId with information specified by travelDetails. - */ -async function updateOne( - identifier: number, - travelDetails: Object -): Promise { - const TAG = `[Travel Service # update ]:`; - - return await Travel.findOne(identifier, travelDetails).then((travel) => { - logger.updateCallbackFactory(TAG, "travel"); - return travel; - }); -} - -/** - * @function findById - * @param {number} identifier - * @return {Promise} The document query will resolve to travel or null. - * @description Finds an travel by the id, which is the mongoId. - */ -async function findById(identifier: number): Promise { - const TAG = `[Travel Service # findById ]:`; - - return await Travel.findOne(identifier).then((travel) => { - logger.queryCallbackFactory(TAG, "travel", identifier); - return travel; - }); -} + constructor() { + this.travelRepository = getRepository(Travel); + } -/** - * @async - * @function findOne - * @param {Object} query - * @return {Promise<(Travel | undefined)[]>} either travel or null - * @description Finds an travel by some query. - */ -async function findIds(queries: Object[]): Promise<(Travel | undefined)[]> { - const TAG = `[Travel Service # findIds ]:`; - let ids = []; + public async findByIdentifier( + identifier: number + ): Promise { + return await this.travelRepository.findOne(identifier); + } - for (const query of queries) { - let current = await Travel.findOne({ where: query }).then( - (travel: Travel) => { - logger.queryCallbackFactory(TAG, "travel", query); - return travel; - } - ); - ids.push(current); + public async findByHacker(hacker: Hacker): Promise { + return await this.travelRepository.findOne({ + relations: ["hacker"], + where: { hacker: hacker } + }); } - return ids; -} -/** - * @function findByHackerId - * @param {number} identifier - * @return {Promise} A travel document queried by accountId - */ -async function findByHackerId(identifier: number): Promise { - const TAG = `[ Travel Service # findByHackerId ]:`; - const query = { - hacker: identifier - }; + public async update( + identifier: number, + travel: Partial + ): Promise { + return await this.travelRepository.update(identifier, travel); + } - return await Travel.findOne({ where: query }).then((travel) => { - logger.updateCallbackFactory(TAG, "travel"); - return travel; - }); + public async save(travel: Travel): Promise { + return await this.travelRepository.save(travel); + } } - -export { createTravel, findById, updateOne, findIds, findByHackerId }; From 4e013d329a6287187b9dd4a22eaf4f48d8dc523f Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Sat, 25 Dec 2021 22:07:21 -0500 Subject: [PATCH 20/72] fix: add logging to catch storage service errors. --- services/storage.service.ts | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/services/storage.service.ts b/services/storage.service.ts index c573fe8d..7950655c 100644 --- a/services/storage.service.ts +++ b/services/storage.service.ts @@ -1,21 +1,26 @@ // Imports the Google Cloud client library import * as GStorage from "@google-cloud/storage"; -import * as Logger from "./logger.service"; -import * as Env from "./env.service"; +import { autoInjectable } from "tsyringe"; +import { EnvService } from "./env.service"; +import { LoggerService } from "./logger.service"; -class StorageService { +@autoInjectable() +export class StorageService { bucketName: string | undefined; storage: any; bucket: any; - constructor() { + constructor( + private readonly envService: EnvService, + loggerService: LoggerService + ) { this.bucketName = process.env.BUCKET_NAME || ""; try { this.storage = new GStorage.Storage(); } catch (error) { - Logger.error(error); + loggerService.getLogger().error(error); } - if (Env.isProduction()) + if (this.envService.isProduction()) this.bucket = this.storage.bucket(this.bucketName); } @@ -43,6 +48,7 @@ class StorageService { blobStream.end(file.buffer); }); } + /** * Download file from storage. * @param {string} filename path to file in bucket @@ -81,6 +87,7 @@ class StorageService { const file = this.bucket.file(filename); return file.exists(); } + /** * Get the public URL of the file * @param {string} filename the path of the file @@ -89,5 +96,3 @@ class StorageService { return `https://storage.googleapis.com/${this.bucket.name}/${filename}`; } } - -export default new StorageService(); From fc76cbabd38406fab6b4e571e4ffc261edc72a79 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Sun, 26 Dec 2021 12:02:31 -0500 Subject: [PATCH 21/72] refactor: reimplement search service and search controller for sql. - reimplement the search service from mongodb to sql. - instead of using GTE OR LTE OR NE we now should use <=, >=, <>, etc... - reimplement the search controller using decorators. --- app.ts | 4 +- controllers/search.controller.js | 26 ------- controllers/search.controller.ts | 59 +++++++++++++++ middlewares/search.middleware.js | 75 ------------------ services/search.service.ts | 126 ++++++++++--------------------- 5 files changed, 100 insertions(+), 190 deletions(-) delete mode 100644 controllers/search.controller.js create mode 100644 controllers/search.controller.ts delete mode 100644 middlewares/search.middleware.js diff --git a/app.ts b/app.ts index 1dc12109..b9bb0e09 100755 --- a/app.ts +++ b/app.ts @@ -6,6 +6,7 @@ import { container } from "tsyringe"; import { AccountController } from "./controllers/account.controller"; import { AuthenticationController } from "./controllers/authentication.controller"; import { HackerController } from "./controllers/hacker.controller"; +import { SearchController } from "./controllers/search.controller"; import { SponsorController } from "./controllers/sponsor.controller"; import { TeamController } from "./controllers/team.controller"; import { TravelController } from "./controllers/travel.controller"; @@ -79,7 +80,8 @@ const cors = require("cors"); container.resolve(HackerController), container.resolve(TeamController), container.resolve(SponsorController), - container.resolve(TravelController) + container.resolve(TravelController), + container.resolve(SearchController) ]); application.use("/api", router); diff --git a/controllers/search.controller.js b/controllers/search.controller.js deleted file mode 100644 index d127f2ee..00000000 --- a/controllers/search.controller.js +++ /dev/null @@ -1,26 +0,0 @@ -"use strict"; -const Services = { - Search: require("../services/search.service"), - Logger: require("../services/logger.service") -}; -const Util = require("../middlewares/util.middleware"); -const Success = require("../constants/success.constant"); - -async function searchResults(req, res) { - let results = req.body.results; - let message; - if (results.length < 1) { - message = Success.SEARCH_NO_RESULTS; - results = {}; - } else { - message = Success.SEARCH_QUERY; - } - return res.status(200).json({ - message: message, - data: results - }); -} - -module.exports = { - searchResults: Util.asyncMiddleware(searchResults) -}; diff --git a/controllers/search.controller.ts b/controllers/search.controller.ts new file mode 100644 index 00000000..b3e6cce6 --- /dev/null +++ b/controllers/search.controller.ts @@ -0,0 +1,59 @@ +import { Body, Controller, Get, Params, Response } from "@decorators/express"; +import { autoInjectable } from "tsyringe"; +import { AuthorizationLevel } from "../constants/authorization-level.constant"; +import { EnsureAuthenticated } from "../middlewares/authenticated.middleware"; +import { EnsureAuthorization } from "../middlewares/authorization.middleware"; +import { SearchService } from "../services/search.service"; +import { Response as ExpressResponse } from "express"; +import * as SuccessConstants from "../constants/success.constant"; + +export interface SearchBody { + page?: number; + limit?: number; + sort?: string; + expand?: boolean; + model: string; + q: any; +} + +@autoInjectable() +@Controller("/search") +export class SearchController { + constructor(private readonly searchService: SearchService) {} + + @Get("/", [ + EnsureAuthenticated, + EnsureAuthorization([ + AuthorizationLevel.Staff, + AuthorizationLevel.Sponsor, + AuthorizationLevel.Volunteer + ]) + ]) + async execute( + @Response() response: ExpressResponse, + @Body() body: SearchBody + ) { + if (!body.page) body.page = 0; + if (!body.limit) body.limit = 10000; + if (!body.sort) body.sort = ""; + if (!body.expand) body.expand = false; + + const result = await this.searchService.executeQuery( + body.model, + body.q, + body.page, + body.limit, + body.sort, + "", + body.expand + ); + + response.status(200).send({ + message: + result.length >= 1 + ? SuccessConstants.SEARCH_QUERY + : SuccessConstants.SEARCH_NO_RESULTS, + data: result + }); + } +} diff --git a/middlewares/search.middleware.js b/middlewares/search.middleware.js deleted file mode 100644 index 4280f62e..00000000 --- a/middlewares/search.middleware.js +++ /dev/null @@ -1,75 +0,0 @@ -"use strict"; -const Services = { - Search: require("../services/search.service") -}; -const Middleware = { - Util: require("../middlewares/util.middleware") -}; - -/** - * @function parseQuery - * @param {JSON} req - * @param {JSON} res - * @param {JSON} next - * @description parses the json in the parameter - */ -function parseQuery(req, res, next) { - let query = req.body.q; - - req.body.q = JSON.parse(query); - - //Default page - if (!req.body.hasOwnProperty("page")) { - req.body.page = 0; - } else { - req.body.page = parseInt(req.body.page); - } - //Default limit - if (!req.body.hasOwnProperty("limit")) { - req.body.limit = 10000; - } else { - req.body.limit = parseInt(req.body.limit); - } - //Default sorting - if (!req.body.hasOwnProperty("sort")) { - req.body.sort = ""; - req.body.sort_by = ""; - } - - if (!req.body.hasOwnProperty("expand")) { - req.body.expand = false; - } - - return next(); -} - -/** - * Middleware that executes the query passed - * @param {{body: {model: string, q: Array, page: Integer, limit: Integer}}} req - * @param {*} res - * @param {(err?)=>void} next - * @returns {Promise.} - */ -async function executeQuery(req, res, next) { - req.body.results = await Services.Search.executeQuery( - req.body.model, - req.body.q, - req.body.page, - req.body.limit, - req.body.sort, - req.body.sort_by, - req.body.expand - ); - return next(); -} - -function setExpandTrue(req, res, next) { - req.body.expand = true; - next(); -} - -module.exports = { - parseQuery: parseQuery, - executeQuery: Middleware.Util.asyncMiddleware(executeQuery), - setExpandTrue: setExpandTrue -}; diff --git a/services/search.service.ts b/services/search.service.ts index 78f0b987..2ecce2b3 100644 --- a/services/search.service.ts +++ b/services/search.service.ts @@ -1,93 +1,43 @@ -"use strict"; -const Hacker = require("../models/hacker.model"); -const logger = require("./logger.service"); +import { singleton } from "tsyringe"; +import { Connection, getConnection } from "typeorm"; -/** - * @function executeQuery - * @param {string} model the model which is being searched - * @param {Array} queryArray array of clauses for the query - * @param {number} page the page number you want - * @param {number} limit the limit to the number of responses you want - * @param {"asc"|"desc"} sort which direction you want to sort by - * @param {string} sort_by the attribute you want to sort by - * @returns {Promise<[Array]>} - * @description Builds and executes a search query based on a subset of mongodb - */ -function executeQuery( - model: Object, - queryArray: Array, - page: number, - limit: number, - sort: string, - sort_by: string, - shouldExpand = false -) { - //TODO: Fix this / update for TypeOrm. - var query = {}; - /*switch (model.toLowerCase()) { - case "hacker": - query = shouldExpand - ? Hacker.find().populate([ - { - path: "accountId", - select: " -password" - }, - { - path: "teamId" - } - ]) - : Hacker.find(); - break; - default: - return []; - } - for (var i in queryArray) { - var clause = queryArray[i]; - var param = clause.param; - var val = clause.value; - switch (clause.operation) { - case "equals": - query.where(param).equals(val); - break; - case "ne": - query.where(param).ne(val); - break; - case "lt": - query.where(param).lt(val); - break; - case "gt": - query.where(param).gt(val); - break; - case "lte": - query.where(param).lte(val); - break; - case "gte": - query.where(param).gte(val); - break; - case "in": - query.where(param).in(val); - break; - case "regex": - query.where(param).regex(val); - break; - case "elemMatch": - query.where(param).elemMatch(val); - break; +@singleton() +export class SearchService { + constructor(private readonly connection: Connection = getConnection()) {} + + public executeQuery( + model: any, + query: Array, + page: number, + limit: number, + sort: string, + sort_by: string, + shouldExpand: boolean = false + ) { + var builder = this.connection + .createQueryBuilder() + .relation(model) + .select(); + for (const element in query) { + const { + parameter, + value, + operation + }: { parameter: any; value: any; operation: string } = query[ + element + ]; + + //TODO: Ensure santitized input for operation and value? + builder = builder.where(`:${parameter}${operation}${value}`, { + parameter, + value + }); } - } - if (sort == "desc") { - query.sort("-" + sort_by); - } else if (sort == "asc") { - query.sort(sort_by); + //TODO: Implement sorting by ascending, descending. + return builder + .limit(limit) + .skip(limit * page) + .getMany(); } - return query - .limit(limit) - .skip(limit * page) - .exec();*/ - return query; } - -module.exports = { - executeQuery: executeQuery -}; From b92442d8d30fa5e9eb5bb88b45ba09cb414da4ab Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Sun, 26 Dec 2021 17:49:29 -0500 Subject: [PATCH 22/72] feat: add ability to upload & download resumes, delete old js files. - TODO: - add statistics feature for hacker controller. - add invites feature for hacker controller. - add batch accept for hacker controller. - add status change e-mail sending for hacker applications. - find a more elegant way to implement file validation (multer). --- controllers/hacker.controller.js | 115 ---- controllers/hacker.controller.ts | 82 ++- middlewares/hacker.middleware.js | 930 ------------------------------- middlewares/multer.middleware.ts | 16 + 4 files changed, 96 insertions(+), 1047 deletions(-) delete mode 100644 controllers/hacker.controller.js delete mode 100644 middlewares/hacker.middleware.js create mode 100644 middlewares/multer.middleware.ts diff --git a/controllers/hacker.controller.js b/controllers/hacker.controller.js deleted file mode 100644 index 25b2a635..00000000 --- a/controllers/hacker.controller.js +++ /dev/null @@ -1,115 +0,0 @@ -"use strict"; -const Constants = { - Success: require("../constants/success.constant"), - Error: require("../constants/error.constant") -}; - -/** - * @function showHacker - * @param {{body: {hacker: Object}}} req - * @param {*} res - * @return {JSON} Success status and hacker object - * @description Returns the JSON of hacker object located in req.body.hacker - */ -function showHacker(req, res) { - return res.status(200).json({ - message: Constants.Success.HACKER_READ, - data: req.body.hacker.toJSON() - }); -} - -/** - * @function createdHacker - * @param {{body: {hacker: {_id: ObjectId, accountId: ObjectId, status: string, application: {Object}}}}} req - * @param {*} res - * @return {JSON} Success status - * @description returns success message - */ -function createdHacker(req, res) { - return res.status(200).json({ - message: Constants.Success.HACKER_CREATE, - data: req.body.hacker.toJSON() - }); -} - -/** - * @function updateHacker - * @param {{params: {id: ObjectId}, body: {Object}}} req - * @param {*} res - * @return {JSON} Success or error status - * @description - * Change a hacker's information based on the hacker's mongoID specified in req.params.id. - * The id is moved to req.body.id from req.params.id by validation. - * Returns a 200 status for an updated hacker. - * The new information is located in req.body. - */ -function updatedHacker(req, res) { - return res.status(200).json({ - message: Constants.Success.HACKER_UPDATE, - data: req.body - }); -} - -function uploadedResume(req, res) { - return res.status(200).json({ - message: Constants.Success.RESUME_UPLOAD, - data: { - filename: req.body.gcfilename - } - }); -} - -function downloadedResume(req, res) { - return res.status(200).json({ - message: Constants.Success.RESUME_DOWNLOAD, - data: { - id: req.body.id, - resume: req.body.resume - } - }); -} - -function gotStats(req, res) { - return res.status(200).json({ - message: "Retrieved stats", - data: { - stats: req.body.stats - } - }); -} - -function sentWeekOfEmail(req, res) { - return res.status(200).json({ - message: Constants.Success.HACKER_SENT_WEEK_OF, - data: {} - }); -} - -function sentDayOfEmail(req, res) { - return res.status(200).json({ - message: Constants.Success.HACKER_SENT_DAY_OF, - data: {} - }); -} - -function updatedHackerBatch(req, res) { - return res.status(200).json({ - message: Constants.Success.HACKER_UPDATE_BATCH, - data: { - success_ids: req.body.ids, - errors: req.errors || [] - } - }); -} - -module.exports = { - updatedHacker: updatedHacker, - updatedHackerBatch: updatedHackerBatch, - createdHacker: createdHacker, - uploadedResume: uploadedResume, - downloadedResume: downloadedResume, - showHacker: showHacker, - gotStats: gotStats, - sentWeekOfEmail: sentWeekOfEmail, - sentDayOfEmail: sentDayOfEmail -}; diff --git a/controllers/hacker.controller.ts b/controllers/hacker.controller.ts index da90046f..7b8bde83 100644 --- a/controllers/hacker.controller.ts +++ b/controllers/hacker.controller.ts @@ -5,6 +5,7 @@ import { Params, Patch, Post, + Request, Response } from "@decorators/express"; import { autoInjectable } from "tsyringe"; @@ -15,12 +16,20 @@ import Hacker from "../models/hacker.model"; import { HackerService } from "../services/hacker.service"; import * as SuccessConstants from "../constants/success.constant"; import * as ErrorConstants from "../constants/error.constant"; -import { request, Response as ExpressResponse } from "express"; +import { + Request as ExpressRequest, + Response as ExpressResponse +} from "express"; +import { StorageService } from "../services/storage.service"; +import { upload } from "../middlewares/multer.middleware"; @autoInjectable() @Controller("/hacker") export class HackerController { - constructor(private readonly hackerService: HackerService) {} + constructor( + private readonly hackerService: HackerService, + private readonly storageService: StorageService + ) {} @Get("/:identifier", [ EnsureAuthenticated, @@ -91,4 +100,73 @@ export class HackerController { } }); } + + @Get("/resume/:identifier", [ + EnsureAuthenticated, + EnsureAuthorization([ + AuthorizationLevel.Staff, + AuthorizationLevel.Hacker + ]) + ]) + async downloadResume( + @Response() response: ExpressResponse, + @Params("identifier") identifier: number + ) { + const hacker: + | Hacker + | undefined = await this.hackerService.findByIdentifier(identifier); + const resume = await this.storageService.download( + hacker?.application.general.URL.resume! + ); + + resume + ? response.status(200).send({ + message: SuccessConstants.RESUME_DOWNLOAD, + data: { + identifier: identifier, + resume: resume + } + }) + : response.status(404).send({ + message: ErrorConstants.RESUME_404_MESSAGE + }); + } + + @Post("/resume/:identifier", [ + EnsureAuthenticated, + EnsureAuthorization([ + AuthorizationLevel.Staff, + AuthorizationLevel.Hacker + ]), + upload.single("file") + ]) + async uploadResume( + @Request() request: ExpressRequest, + @Response() response: ExpressResponse, + @Params("identifier") identifier: number + ) { + if (!request.file) + response.status(400).send({ + message: ErrorConstants.RESUME_404_MESSAGE + }); + else { + const fileName = `resumes/${Date.now()}-${identifier}`; + + await this.storageService.upload(request.file, fileName); + + //TODO - Implement affectedRows > 0 success check. + const result = await this.hackerService.updateApplicationField( + identifier, + "general.URL.resume", + request.file + ); + + response.status(200).send({ + message: SuccessConstants.RESUME_UPLOAD, + data: { fileName: fileName } + }); + } + } } + +//TODO - Implement statistics features, batch accept/application change features, and status change emails. diff --git a/middlewares/hacker.middleware.js b/middlewares/hacker.middleware.js deleted file mode 100644 index d3aabbfe..00000000 --- a/middlewares/hacker.middleware.js +++ /dev/null @@ -1,930 +0,0 @@ -/* eslint-disable require-atomic-updates */ -"use strict"; - -const TAG = `[ HACKER.MIDDLEWARE.js ]`; -const mongoose = require("mongoose"); - -// shim to allow us to use Promise.allSettled -require("promise.allsettled").shim(); - -const Services = { - Hacker: require("../services/hacker.service"), - Storage: require("../services/storage.service"), - Email: require("../services/email.service"), - Account: require("../services/account.service"), - Travel: require("../services/travel.service"), - Env: require("../services/env.service") -}; -const Middleware = { - Util: require("./util.middleware") -}; -const Constants = { - General: require("../constants/general.constant"), - Error: require("../constants/error.constant") -}; - -/** - * @function parsePatch - * @param {body: {id: ObjectId}} req - * @param {*} res - * @param {(err?) => void} next - * @return {void} - * @description Delete the req.body.id that was added by the validation of route parameter. - */ -function parsePatch(req, res, next) { - delete req.body.id; - return next(); -} - -/** - * @function parseHacker - * @param {{body: {accountId: ObjectId, application: Object, authorization: string}}} req - * @param {*} res - * @param {(err?)=>void} next - * @return {void} - * @description - * Moves accountId, application from req.body to req.body.hackerDetails. - * Adds _id to hackerDetails. - */ -function parseHacker(req, res, next) { - const hackerDetails = { - _id: mongoose.Types.ObjectId(), - accountId: req.body.accountId, - application: req.body.application, - teamId: req.body.teamId - }; - req.body.token = req.body.authorization; - - delete req.body.accountId; - delete req.body.application; - delete req.body.teamId; - - req.body.hackerDetails = hackerDetails; - - return next(); -} - -/** - * @function parseCheckin - * @param {{body: {*}}} req - * @param {*} res - * @param {(err?)=>void} next - * @return {void} - * @description - * Adds the checked-in status to req.body - */ -function parseCheckIn(req, res, next) { - req.body.status = Constants.General.HACKER_STATUS_CHECKED_IN; - - return next(); -} - -/** - * @function parseCheckin - * @param {{body: {confirm: boolean}}} req - * @param {*} res - * @param {(err?)=>void} next - * @return {void} - * @description - * Changes req.body.status to confirmed or withdrawn depending on whether req.body.confirm is true or false respectively. - * Deletes req.body.confirm afterwards - */ -function parseConfirmation(req, res, next) { - const confirm = req.body.confirm; - - if (confirm) { - req.body.status = Constants.General.HACKER_STATUS_CONFIRMED; - } else { - req.body.status = Constants.General.HACKER_STATUS_WITHDRAWN; - } - - delete req.body.confirm; - return next(); -} - -/** - * @function addDefaultStatus - * @param {{body: {hackerDetails: {status: String}}}} req - * @param {JSON} res - * @param {(err?)=>void} next - * @return {void} - * @description Adds status to hackerDetails. - */ -function addDefaultStatus(req, res, next) { - req.body.hackerDetails.status = "Applied"; - return next(); -} - -/** - * Helper function that validates if account is confirmed and is of proper type. - * @param account account object containing the information for an account - * @returns {{status: number, message: string, error: Object}| null} returns error message if invalid, or null if valid. - */ -function validateConfirmedStatus(account) { - if (!account) { - return { - status: 404, - message: Constants.Error.ACCOUNT_404_MESSAGE, - data: { account: account } - }; - } else if (!account.confirmed) { - return { - status: 403, - message: Constants.Error.ACCOUNT_403_MESSAGE, - data: { account: { id: account.id, confirmed: account.confirmed } } - }; - } else if (account.accountType !== Constants.General.HACKER) { - return { - status: 409, - message: Constants.Error.ACCOUNT_TYPE_409_MESSAGE, - data: { - account: { id: account.id, accountType: account.accountType } - } - }; - } else { - return; - } -} - -/** - * Verifies that account is confirmed and of proper type from the hacker ID - * @param {string} id - * @returns {string} the id if it is confirmed. - * @throws ACCOUNT_404_MESSAGE if hacker / and or the account does not exist - * @throws ACCOUNT_403_MESSAGE if account is not confirmed - * @throws ACCOUNT_409_MESSAGE if account is not hacker - */ -async function hackerHasConfirmedAccount(id) { - const account = await Services.Account.findByHackerId(id); - const error = validateConfirmedStatus(account); - if (error) { - error.data.hacker_id = id; - throw error; - } - return id; -} - -/** - * Verifies that account is confirmed and of proper type from the account ID passed in req.body.accountId - * @param {{body: {accountId: ObjectId}}} req - * @param {*} res - * @param {(err?) => void} next - */ -async function validateConfirmedStatusFromAccountId(req, res, next) { - const account = await Services.Account.findById(req.body.accountId); - return next(validateConfirmedStatus(account)); -} - -/** - * Verifies that account is confirmed and of proper type from the hacker ID passed in req.params.id - * @param {{params: {id: ObjectId}}} req - * @param {*} res - * @param {(err?) => void} next - */ -async function validateConfirmedStatusFromHackerId(req, res, next) { - // Throws error if not confirmed. - await hackerHasConfirmedAccount(req.params.id); - next(); -} - -/** - * Verifies that account is confirmed and of proper type from the hacker ID passed in req.body.ids. - * It will remove all ids that are not valid. - * @param {{body: {ids: ObjectId[]}}} req - * @param {*} res - * @param {(err?) => void} next - */ -async function validateConfirmedStatusFromArrayofHackerIds(req, res, next) { - if (!req.body.ids) { - return next({ - status: 404, - message: Constants.Error.HACKER_404_MESSAGE - }); - } - let confirmedStatusPromises = []; - for (const id of req.body.ids) { - confirmedStatusPromises.push(hackerHasConfirmedAccount(id)); - } - const results = await Promise.allSettled(confirmedStatusPromises); - req.body.ids = []; - req.errors = req.errors ? req.errors : []; - // Iterate through results and split by errors and IDs - for (const result of results) { - if (result.status === "rejected") { - req.errors.push(result.reason); - } else { - // hackerHasConfirmedAccount will return ID - req.body.ids.push(result.value); - } - } - next(); -} - -/** - * Verifies that account is confirmed and of proper type from the account object passed in req.body.account - * @param {{body: {account: Object}}} req - * @param {*} res - * @param {(err?) => void} next - */ -async function validateConfirmedStatusFromObject(req, res, next) { - next(validateConfirmedStatus(req.body.account)); -} - -/** - * @async - * @function findById - * @param {{body: {id: ObjectId}}} req - * @param {*} res - * @description Retrieves a hacker's information via req.body.id, moving result to req.body.hacker if succesful. - */ -async function findById(req, res, next) { - const hacker = await Services.Hacker.findById(req.body.id); - - if (!hacker) { - return next({ - status: 404, - message: Constants.Error.HACKER_404_MESSAGE - }); - } - - req.body.hacker = hacker; - next(); -} - -async function findByEmail(req, res, next) { - const account = await Services.Account.findByEmail(req.body.email); - if (!account) { - return next({ - status: 404, - message: Constants.Error.ACCOUNT_404_MESSAGE, - error: {} - }); - } - const hacker = await Services.Hacker.findByAccountId(account._id); - if (!hacker) { - return next({ - status: 404, - message: Constants.Error.HACKER_404_MESSAGE, - error: {} - }); - } - - req.body.hacker = hacker; - next(); -} - -/** - * Verifies that the current signed in user is linked to the hacker passed in via req.body.id - * @param {{body: {id: ObjectId}}} req - * @param {*} res - * @param {(err?)=>void} next - */ -// must check that the account id is in the hacker schema. -function ensureAccountLinkedToHacker(req, res, next) { - Services.Hacker.findById(req.body.id) - .then((hacker) => { - req.hacker = hacker; - if ( - hacker && - req.user && - String.toString(hacker.accountId) === - String.toString(req.user.id) - ) { - return next(); - } else { - return next({ - status: 403, - message: Constants.Error.AUTH_403_MESSAGE, - error: {} - }); - } - }) - .catch(next); -} - -/** - * Uploads resume via the storage service. Assumes there is a resume in req, and a hacker id in req.body. - * @param {{body: {id: ObjectId}, resume: [Buffer]}} req - * @param {*} res - * @param {(err?)=>void} next - */ -async function uploadResume(req, res, next) { - const gcfilename = `resumes/${Date.now()}-${req.hacker.id}`; - await Services.Storage.upload(req.file, gcfilename); - req.body.gcfilename = gcfilename; - await Services.Hacker.updateOne(req.hacker.id, { - $set: { - "application.general.URL.resume": gcfilename - } - }); - return next(); -} - -/** - * Attaches the resume of a hacker to req.body.resume. Assumes req.body.id exists. - * @param {{body: {id: ObjectId}}} req - * @param {*} res - * @param {(err?)=>void} next - */ -async function downloadResume(req, res, next) { - const hacker = await Services.Hacker.findById(req.body.id); - if ( - hacker && - hacker.application && - hacker.application.general && - hacker.application.general.URL && - hacker.application.general.URL.resume - ) { - req.body.resume = await Services.Storage.download( - hacker.application.general.URL.resume - ); - } else { - return next({ - status: 404, - message: Constants.Error.RESUME_404_MESSAGE, - error: {} - }); - } - return next(); -} - -/** - * Sends the status for a given hacker. - * @returns {Promise} Returns a promise, which resolves into the ID, or rejects with the reason. - * @param {string} id - * @param {string} status - */ -async function sendStatusUpdateEmailHelper(id, status) { - // send it to the hacker that is being updated. - const account = await Services.Account.findByHackerId(id); - if (!account) { - throw { - status: 500, - message: Constants.Error.GENERIC_500_MESSAGE, - id: id - }; - } - // Promisify sendStatusUpdate :/ - return new Promise((resolve, reject) => { - Services.Email.sendStatusUpdate( - account.firstName, - account.email, - status, - (err) => { - err ? reject(err) : resolve(id); - } - ); - }); -} - -/** - * Sends a preset email to a user if a status change occured. - * @param {{body: {status?: string}, params: {id: string}}} req - * @param {*} res - * @param {(err?:*)=>void} next - */ -async function sendStatusUpdateEmail(req, res, next) { - //skip if the status doesn't exist - if (!req.body.status) { - return next(); - } else { - await sendStatusUpdateEmailHelper(req.params.id, req.body.status); - next(); - } -} - -/** - * Sends a preset email to a user if a status change occured. - * @param {{body: {status?: string, ids: string[]}} req - * @param {*} res - * @param {(err?:*)=>void} next - */ -async function sendStatusUpdateEmailForMultipleIds(req, res, next) { - //skip if the status doesn't exist - if (!req.body.status) { - return next(); - } else { - const statusUpdatePromises = []; - for (const id of req.body.ids) { - statusUpdatePromises.push( - sendStatusUpdateEmailHelper(id, req.body.status) - ); - } - const results = await Promise.allSettled(statusUpdatePromises); - req.body.ids = []; - req.errors = req.errors ? req.errors : []; - for (const result of results) { - if (result.status === "rejected") { - req.errors.push(result.reason); - } else { - // result.value will be the hacker's ID. - req.body.ids.push(result.value); - } - } - next(); - } -} -/** - * Sends a preset email to a user if a status change occured with email params. - * @param {{body: {status?: string}, params: {email: string}}} req - * @param {*} res - * @param {(err?:*)=>void} next - */ -async function completeStatusUpdateEmail(req, res, next) { - //skip if the status doesn't exist - if (!req.body.hacker.status) { - return next(); - } else { - // send it to the hacker that is being updated. - const hacker = await Services.Hacker.findById(req.body.hacker._id); - const account = await Services.Account.findById(hacker.accountId); - if (!hacker) { - return next({ - status: 404, - message: Constants.Error.HACKER_404_MESSAGE - }); - } else if (!account) { - return next({ - status: 500, - message: Constants.Error.GENERIC_500_MESSAGE - }); - } - Services.Email.sendStatusUpdate( - account.firstName, - account.email, - req.body.hacker.status, - next - ); - } -} - -/** - * Sends an email telling the user that they have applied. This is used exclusively when we POST a hacker. - * @param {{body: {hacker: {accountId: string}}}} req - * @param {*} res - * @param {(err?:*)=>void} next - */ -async function sendAppliedStatusEmail(req, res, next) { - const hacker = req.body.hacker; - const account = await Services.Account.findById(hacker.accountId); - if (!account) { - return next({ - status: 500, - message: Constants.Error.GENERIC_500_MESSAGE, - error: {} - }); - } - Services.Email.sendStatusUpdate( - account.firstName, - account.email, - Constants.General.HACKER_STATUS_APPLIED, - next - ); -} - -/** - * Sends an email telling the user that they have applied. This is used exclusively when we POST a hacker. - * @param {{body: {hacker: {accountId: string}}}} req - * @param {*} res - * @param {(err?:*)=>void} next - */ -async function sendWeekOfEmail(req, res, next) { - const hacker = req.body.hacker; - const address = Services.Env.isProduction() - ? process.env.FRONTEND_ADDRESS_DEPLOY - : process.env.FRONTEND_ADDRESS_DEV; - const httpOrHttps = address.includes("localhost") ? "http" : "https"; - const singleHackerViewLink = Services.Hacker.generateHackerViewLink( - httpOrHttps, - address, - hacker._id.toString() - ); - const ticketSVG = await Services.Hacker.generateQRCode( - singleHackerViewLink - ); - const account = await Services.Account.findById(hacker.identifier); - if (!account || !ticketSVG) { - return next({ - status: 500, - message: Constants.Error.GENERIC_500_MESSAGE, - error: {} - }); - } - Services.Email.sendWeekOfEmail( - account.firstName, - account.email, - ticketSVG, - next - ); -} - -/** - * Sends an email telling the user that they have applied. This is used exclusively when we POST a hacker. - * @param {{body: {hacker: {accountId: string}}}} req - * @param {*} res - * @param {(err?:*)=>void} next - */ -async function sendDayOfEmail(req, res, next) { - const hacker = req.body.hacker; - const account = await Services.Account.findById(hacker.accountId); - if (!account) { - return next({ - status: 500, - message: Constants.Error.GENERIC_500_MESSAGE, - error: {} - }); - } - Services.Email.sendDayOfEmail(account.firstName, account.email, next); -} - -/** - * If the current hacker's status is Constants.HACKER_STATUS_NONE, and the hacker's application is completed, - * then it will change the status of the hacker to Constants.General.HACKER_STATUS_APPLIED, and then email the hacker to - * confirm that they applied. - * @param {{body: {status?: string}, params: {id: string}}} req - * @param {*} res - * @param {(err?:*)=>void} next - */ -async function updateStatusIfApplicationCompleted(req, res, next) { - const hacker = await Services.Hacker.findById(req.params.id); - if (hacker) { - if ( - hacker.status === Constants.General.HACKER_STATUS_NONE && - hacker.isApplicationComplete() - ) { - await Services.Hacker.updateOne(req.params.id, { - status: Constants.General.HACKER_STATUS_APPLIED - }); - const account = await Services.Account.findById(hacker.accountId); - if (!account) { - return next({ - status: 500, - message: Constants.Error.GENERIC_500_MESSAGE, - error: {} - }); - } - Services.Email.sendStatusUpdate( - account.firstName, - account.email, - Constants.General.HACKER_STATUS_APPLIED, - next - ); - } else { - return next(); - } - } else { - return next({ - status: 404, - message: Constants.Error.HACKER_404_MESSAGE, - data: { - id: req.params.id - } - }); - } -} - -/** - * Checks that the hacker's status matches one of the input statuses - * @param {String[]} statuses - * @returns {(req, res, next) => {}} the middleware that will check hacker's status - */ -function checkStatus(statuses) { - return Middleware.Util.asyncMiddleware(async (req, res, next) => { - let hacker = await Services.Hacker.findById(req.params.id); - - if (hacker) { - const status = hacker.status; - // makes sure the hacker's status is in the accepted statuses list - if (statuses.indexOf(status) === -1) { - return next({ - status: 409, - message: Constants.Error.HACKER_STATUS_409_MESSAGE, - data: { - id: req.params.id, - validStatuses: statuses - } - }); - } - - return next(); - } else { - return next({ - status: 404, - message: Constants.Error.HACKER_404_MESSAGE, - data: { - id: req.params.id - } - }); - } - }); -} - -/** - * Updates a hacker that is specified by req.params.id, and then sets req.email - * to the email of the hacker, found in Account. - * @param {{params:{id: string}, body: *}} req - * @param {*} res - * @param {*} next - */ -async function updateHacker(req, res, next) { - const hacker = await Services.Hacker.updateOne(req.params.id, req.body); - if (hacker) { - const acct = await Services.Account.findById(hacker.accountId); - if (!acct) { - return next({ - status: 500, - message: Constants.Error.HACKER_UPDATE_500_MESSAGE, - data: { - hackerId: hacker.id, - accountId: hacker.accountId - } - }); - } - req.email = acct.email; - - // If this hacker has a travel account associated with it, then update request to reflect amount wanted for travel - const travel = await Services.Travel.findByHackerId(hacker.id); - if (travel) { - await Services.Travel.updateOne(travel.id, { - request: hacker.application.accommodation.travel - }); - } - return next(); - } else { - return next({ - status: 404, - message: Constants.Error.HACKER_404_MESSAGE, - data: { - id: req.params.id - } - }); - } -} - -/** - * Updates a hacker that is specified by req.body.hacker._id, and then sets req.email - * to the email of the hacker, found in Account. - * @param {{params:{_id: string}, body: *}} req - * @param {*} res - * @param {*} next - */ -async function obtainEmailByHackerId(req, res, next) { - const hacker = await Services.Hacker.findById(req.body.hacker._id); - if (hacker) { - const acct = await Services.Account.findById(hacker.accountId); - if (!acct) { - return next({ - status: 500, - message: Constants.Error.HACKER_UPDATE_500_MESSAGE, - data: { - hackerId: hacker.id, - accountId: hacker.accountId - } - }); - } - req.email = acct.email; - return next(); - } else { - return next({ - status: 404, - message: Constants.Error.HACKER_404_MESSAGE, - data: { - id: req.params.id - } - }); - } -} - -/** - * Updates a list of hacker that is specified by req.body.ids. - * Some hackers may fail, and that will be stored in req.errors. - * Filters req.body.ids to only the successful processes. - * @param {{body:{ids: String[]}}} req - * @param {*} res - * @param {*} next - */ -async function updateBatchHacker(req, res, next) { - let eachHackerPromise = []; - for (const id of req.body.ids) { - eachHackerPromise.push(Services.Hacker.updateOne(id, req.body)); - } - const updateResults = await Promise.allSettled(eachHackerPromise); - // clear req.body.ids so that we store only the good ones. - req.body.ids = []; - req.errors = req.errors ? req.errors : []; - for (const result of updateResults) { - // Some error happened when trying to update a hacker. - if (result.status === "rejected") { - req.errors.push(result.reason); - } else { - // result.value will be the hacker object. - req.body.ids.push(result.value._id); - } - } - next(); -} - -/** - * Sets req.body.status to Accepted for next middleware, and store req.params.id as req.hackerId - * @param {{params:{id: string}, body: *}} req - * @param {*} res - * @param {*} next - */ -function parseAccept(req, res, next) { - req.body.status = Constants.General.HACKER_STATUS_ACCEPTED; - req.hackerId = req.params.id; - next(); -} - -/** - * Sets req.body.hacker.status to Accepted for next middleware. - * @param {{params:{email: string}, body: *}} req - * @param {*} res - * @param {*} next - */ -function parseAcceptEmail(req, res, next) { - req.body.hacker.status = Constants.General.HACKER_STATUS_ACCEPTED; - req.hackerId = req.body.hacker._id; - next(); -} - -/** - * Sets req.body.status to Accepted for next middleware. - * @param {{body: *}} req - * @param {*} res - * @param {*} next - */ -function parseAcceptBatch(req, res, next) { - req.body.status = Constants.General.HACKER_STATUS_ACCEPTED; - next(); -} - -/** - * Sets req.body.status to Accepted for next middleware. - * @param {{params:{id: string}, body: *}} req - * @param {*} res - * @param {*} next - */ -function parseBatchAccept(req, res, next) { - req.body.status = Constants.General.HACKER_STATUS_ACCEPTED; - next(); -} - -/** - * @function createHacker - * @param {{body: {hackerDetails: object}}} req - * @param {*} res - * @param {(err?)=>void} next - * @return {void} - * @description - * Creates hacker document after making sure there is no other hacker with the same linked accountId - */ -async function createHacker(req, res, next) { - const hackerDetails = req.body.hackerDetails; - - const exists = await Services.Hacker.findByAccountId( - hackerDetails.accountId - ); - - if (exists) { - return next({ - status: 422, - message: Constants.Error.ACCOUNT_DUPLICATE_422_MESSAGE, - data: { - id: hackerDetails.accountId - } - }); - } - const hacker = await Services.Hacker.createHacker(hackerDetails); - if (hacker) { - req.body.hacker = hacker; - return next(); - } else { - return next({ - status: 500, - message: Constants.Error.HACKER_CREATE_500_MESSAGE, - data: {} - }); - } -} - -/** - * Checks that there are no other hackers with the same account id as the one passed into req.body.accountId - * @param {{body:{accountId: ObjectId}}} req - * @param {*} res - * @param {*} next - */ -async function checkDuplicateAccountLinks(req, res, next) { - const hacker = await Services.Hacker.findByAccountId(req.body.accountId); - if (!hacker) { - return next(); - } else { - return next({ - status: 409, - message: Constants.Error.HACKER_ID_409_MESSAGE, - data: { - id: req.body.accountId - } - }); - } -} - -/** - * Finds the hacker information of the logged in user - * @param {{user: {id: string}}} req - * @param {*} res - * @param {(err?)=>void} next - */ -async function findSelf(req, res, next) { - if ( - req.user.accountType != Constants.General.HACKER || - !req.user.confirmed - ) { - return next({ - status: 409, - message: Constants.Error.ACCOUNT_TYPE_409_MESSAGE, - error: { - id: req.user.id - } - }); - } - - const hacker = await Services.Hacker.findByAccountId(req.user.id); - - if (hacker) { - req.body.hacker = hacker; - return next(); - } else { - return next({ - status: 409, - message: Constants.Error.HACKER_404_MESSAGE, - error: { - id: req.user.id - } - }); - } -} - -async function getStats(req, res, next) { - const stats = await Services.Hacker.getStats(req.body.results); - req.body.stats = stats; - next(); -} - -module.exports = { - parsePatch: parsePatch, - parseHacker: parseHacker, - addDefaultStatus: addDefaultStatus, - ensureAccountLinkedToHacker: ensureAccountLinkedToHacker, - uploadResume: Middleware.Util.asyncMiddleware(uploadResume), - downloadResume: Middleware.Util.asyncMiddleware(downloadResume), - sendWeekOfEmail: Middleware.Util.asyncMiddleware(sendWeekOfEmail), - sendDayOfEmail: Middleware.Util.asyncMiddleware(sendDayOfEmail), - sendStatusUpdateEmail: Middleware.Util.asyncMiddleware( - sendStatusUpdateEmail - ), - sendStatusUpdateEmailForMultipleIds: Middleware.Util.asyncMiddleware( - sendStatusUpdateEmailForMultipleIds - ), - sendAppliedStatusEmail: Middleware.Util.asyncMiddleware( - sendAppliedStatusEmail - ), - updateHacker: Middleware.Util.asyncMiddleware(updateHacker), - updateBatchHacker: Middleware.Util.asyncMiddleware(updateBatchHacker), - parseAccept: parseAccept, - parseAcceptBatch: parseAcceptBatch, - parseAcceptEmail: parseAcceptEmail, - parseBatch: parseBatchAccept, - validateConfirmedStatusFromAccountId: Middleware.Util.asyncMiddleware( - validateConfirmedStatusFromAccountId - ), - validateConfirmedStatusFromHackerId: Middleware.Util.asyncMiddleware( - validateConfirmedStatusFromHackerId - ), - validateConfirmedStatusFromArrayofHackerIds: Middleware.Util.asyncMiddleware( - validateConfirmedStatusFromArrayofHackerIds - ), - validateConfirmedStatusFromObject: Middleware.Util.asyncMiddleware( - validateConfirmedStatusFromObject - ), - completeStatusUpdateEmail: Middleware.Util.asyncMiddleware( - completeStatusUpdateEmail - ), - checkDuplicateAccountLinks: Middleware.Util.asyncMiddleware( - checkDuplicateAccountLinks - ), - updateStatusIfApplicationCompleted: Middleware.Util.asyncMiddleware( - updateStatusIfApplicationCompleted - ), - checkStatus: checkStatus, - parseCheckIn: parseCheckIn, - parseConfirmation: parseConfirmation, - createHacker: Middleware.Util.asyncMiddleware(createHacker), - findSelf: Middleware.Util.asyncMiddleware(findSelf), - getStats: Middleware.Util.asyncMiddleware(getStats), - findById: Middleware.Util.asyncMiddleware(findById), - findByEmail: Middleware.Util.asyncMiddleware(findByEmail), - obtainEmailByHackerId: Middleware.Util.asyncMiddleware( - obtainEmailByHackerId - ) -}; diff --git a/middlewares/multer.middleware.ts b/middlewares/multer.middleware.ts new file mode 100644 index 00000000..389aac35 --- /dev/null +++ b/middlewares/multer.middleware.ts @@ -0,0 +1,16 @@ +import multer, { Multer } from "multer"; + +// TODO: Find a more elegant implementation for this. +export const upload: Multer = multer({ + storage: multer.memoryStorage(), + limits: { + fileSize: 4000000 //4mb + }, + fileFilter: function(_, file, callback) { + if (file.mimetype !== "application/pdf") { + callback(null, false); + } else { + callback(null, true); + } + } +}); From 10c109bc0035e5735dc9f68e87fd1dff29e3d37c Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Sun, 26 Dec 2021 17:53:06 -0500 Subject: [PATCH 23/72] feat: remove older validators, and start using class-validator. - TODO: - find a consistent way to return the error messages or find a way to change the frontend parsing of error messages. --- middlewares/validators/account.validator.js | 44 - middlewares/validators/auth.validator.js | 31 - middlewares/validators/hacker.validator.js | 295 ----- middlewares/validators/role.validator.js | 10 - .../validators/routeParam.validator.js | 13 - middlewares/validators/search.validator.js | 14 - middlewares/validators/settings.validator.js | 11 - middlewares/validators/sponsor.validator.js | 33 - middlewares/validators/team.validator.js | 29 - middlewares/validators/travel.validator.js | 35 - middlewares/validators/validator.helper.js | 1033 ----------------- middlewares/validators/volunteer.validator.js | 8 - models/account.model.ts | 23 +- models/accountConfirmationToken.model.ts | 25 +- models/application.model.ts | 5 +- models/bus.model.ts | 17 +- models/passwordResetToken.model.ts | 10 +- models/settings.model.ts | 25 - models/sponsor.model.ts | 4 + models/team.model.ts | 7 +- models/travel.model.ts | 20 +- 21 files changed, 67 insertions(+), 1625 deletions(-) delete mode 100644 middlewares/validators/account.validator.js delete mode 100644 middlewares/validators/auth.validator.js delete mode 100644 middlewares/validators/hacker.validator.js delete mode 100644 middlewares/validators/role.validator.js delete mode 100644 middlewares/validators/routeParam.validator.js delete mode 100644 middlewares/validators/search.validator.js delete mode 100644 middlewares/validators/settings.validator.js delete mode 100644 middlewares/validators/sponsor.validator.js delete mode 100644 middlewares/validators/team.validator.js delete mode 100644 middlewares/validators/travel.validator.js delete mode 100644 middlewares/validators/validator.helper.js delete mode 100644 middlewares/validators/volunteer.validator.js delete mode 100644 models/settings.model.ts diff --git a/middlewares/validators/account.validator.js b/middlewares/validators/account.validator.js deleted file mode 100644 index 51ada35b..00000000 --- a/middlewares/validators/account.validator.js +++ /dev/null @@ -1,44 +0,0 @@ -"use strict"; -const VALIDATOR = require("./validator.helper"); -const Constants = require("../../constants/general.constant"); - -module.exports = { - newAccountValidator: [ - VALIDATOR.stringValidator("body", "firstName", false), - VALIDATOR.stringValidator("body", "lastName", false), - VALIDATOR.stringValidator("body", "pronoun", false), - VALIDATOR.stringValidator("body", "gender", false), - VALIDATOR.regexValidator("body", "email", false, Constants.EMAIL_REGEX), - VALIDATOR.alphaArrayValidator("body", "dietaryRestrictions", false), - VALIDATOR.stringValidator("body", "gender", false), - VALIDATOR.passwordValidator("body", "password", false), - VALIDATOR.jwtValidator( - "header", - "token", - process.env.JWT_CONFIRM_ACC_SECRET, - true - ), - VALIDATOR.dateValidator("body", "birthDate", false), - VALIDATOR.phoneNumberValidator("body", "phoneNumber", true) - ], - updateAccountValidator: [ - VALIDATOR.stringValidator("body", "firstName", true), - VALIDATOR.stringValidator("body", "lastName", true), - VALIDATOR.stringValidator("body", "pronoun", true), - VALIDATOR.stringValidator("body", "gender", true), - VALIDATOR.regexValidator("body", "email", true, Constants.EMAIL_REGEX), - VALIDATOR.alphaArrayValidator("body", "dietaryRestrictions", true), - VALIDATOR.stringValidator("body", "gender", true), - VALIDATOR.dateValidator("body", "birthDate", true), - VALIDATOR.phoneNumberValidator("body", "phoneNumber", true) - ], - inviteAccountValidator: [ - VALIDATOR.regexValidator("body", "email", false, Constants.EMAIL_REGEX), - VALIDATOR.enumValidator( - "body", - "accountType", - Constants.EXTENDED_USER_TYPES, - false - ) - ] -}; diff --git a/middlewares/validators/auth.validator.js b/middlewares/validators/auth.validator.js deleted file mode 100644 index 564713c6..00000000 --- a/middlewares/validators/auth.validator.js +++ /dev/null @@ -1,31 +0,0 @@ -"use strict"; -const VALIDATOR = require("./validator.helper"); -const Constants = require("../../constants/general.constant"); - -module.exports = { - ForgotPasswordValidator: [ - VALIDATOR.regexValidator("body", "email", false, Constants.EMAIL_REGEX) - ], - ChangePasswordValidator: [ - VALIDATOR.passwordValidator("body", "oldPassword", false), - VALIDATOR.passwordValidator("body", "newPassword", false) - ], - ResetPasswordValidator: [ - VALIDATOR.passwordValidator("body", "password", false), - //The json web token is provided via the header with param "Authentication". - VALIDATOR.jwtValidator( - "header", - "X-Reset-Token", - process.env.JWT_RESET_PWD_SECRET, - false - ) - ], - accountConfirmationValidator: [ - VALIDATOR.jwtValidator( - "param", - "token", - process.env.JWT_CONFIRM_ACC_SECRET, - false - ) - ] -}; diff --git a/middlewares/validators/hacker.validator.js b/middlewares/validators/hacker.validator.js deleted file mode 100644 index 37b1f705..00000000 --- a/middlewares/validators/hacker.validator.js +++ /dev/null @@ -1,295 +0,0 @@ -"use strict"; -const VALIDATOR = require("./validator.helper"); -const Constants = require("../../constants/general.constant"); - -module.exports = { - newHackerValidator: [ - // status will be added automatically - VALIDATOR.mongoIdValidator("body", "accountId", false), - // validate that application is a valid object - VALIDATOR.applicationValidator("body", "application", false), - VALIDATOR.stringValidator("body", "application.general.school", false), - VALIDATOR.stringValidator("body", "application.general.degree", false), - VALIDATOR.alphaArrayValidator( - "body", - "application.general.fieldOfStudy", - false - ), - VALIDATOR.integerValidator( - "body", - "application.general.graduationYear", - false, - 2019, - 2030 - ), - VALIDATOR.enumValidator( - "body", - "application.accommodation.shirtSize", - Constants.SHIRT_SIZES, - false - ), - VALIDATOR.stringValidator( - "body", - "application.accommodation.impairments", - true - ), - VALIDATOR.stringValidator( - "body", - "application.accommodation.barriers", - true - ), - VALIDATOR.enumValidator( - "body", - "application.accommodation.attendancePreference", - Constants.ATTENDANCE_PREFERENCES, - false - ), - VALIDATOR.stringValidator( - "body", - "application.general.URL.resume", - false - ), - VALIDATOR.stringValidator( - "body", - "application.general.URL.github", - true - ), - VALIDATOR.stringValidator( - "body", - "application.general.URL.dribbble", - true - ), - VALIDATOR.stringValidator( - "body", - "application.general.URL.linkedin", - true - ), - VALIDATOR.stringValidator( - "body", - "application.general.URL.other", - true - ), - VALIDATOR.stringValidator( - "body", - "application.general.URL.personal", - true - ), - VALIDATOR.enumValidator( - "body", - "application.general.jobInterest", - Constants.JOB_INTERESTS, - false - ), - VALIDATOR.alphaArrayValidator( - "body", - "application.shortAnswer.skills", - true - ), - VALIDATOR.stringValidator( - "body", - "application.shortAnswer.comments", - true - ), - VALIDATOR.stringValidator( - "body", - "application.shortAnswer.question1", - false - ), - VALIDATOR.stringValidator( - "body", - "application.shortAnswer.question2", - false - ), - VALIDATOR.enumValidator( - "body", - "application.shortAnswer.previousHackathons", - Constants.PREVIOUS_HACKATHONS, - false - ), - - VALIDATOR.alphaArrayValidator( - "body", - "application.other.ethnicity", - false - ), - VALIDATOR.booleanValidator( - "body", - "application.other.privacyPolicy", - false, - true - ), - VALIDATOR.booleanValidator( - "body", - "application.other.codeOfConduct", - false, - true - ), - VALIDATOR.integerValidator( - "body", - "application.accommodation.travel", - true, - 0, - 100 - ), - VALIDATOR.mongoIdValidator("body", "application.team", true), - VALIDATOR.stringValidator("body", "application.location.timeZone", true), - VALIDATOR.stringValidator("body", "application.location.country", true), - VALIDATOR.stringValidator("body", "application.location.city", true), - VALIDATOR.mongoIdValidator("body", "teamId", true), - ], - - updateConfirmationValidator: [ - VALIDATOR.booleanValidator("body", "confirm", false) - ], - - updateHackerValidator: [ - // validate that application is a valid object - VALIDATOR.applicationValidator("body", "application", false), - VALIDATOR.stringValidator("body", "application.general.school", false), - VALIDATOR.stringValidator("body", "application.general.degree", false), - VALIDATOR.alphaArrayValidator( - "body", - "application.general.fieldOfStudy", - false - ), - VALIDATOR.integerValidator( - "body", - "application.general.graduationYear", - false, - 2019, - 2030 - ), - VALIDATOR.enumValidator( - "body", - "application.accommodation.shirtSize", - Constants.SHIRT_SIZES, - false - ), - VALIDATOR.stringValidator( - "body", - "application.accommodation.impairments", - true - ), - VALIDATOR.stringValidator( - "body", - "application.accommodation.barriers", - true - ), - VALIDATOR.stringValidator( - "body", - "application.general.URL.resume", - false - ), - VALIDATOR.stringValidator( - "body", - "application.general.URL.github", - true - ), - VALIDATOR.stringValidator( - "body", - "application.general.URL.dribbble", - true - ), - VALIDATOR.stringValidator( - "body", - "application.general.URL.linkedin", - true - ), - VALIDATOR.stringValidator( - "body", - "application.general.URL.other", - true - ), - VALIDATOR.stringValidator( - "body", - "application.general.URL.personal", - true - ), - VALIDATOR.enumValidator( - "body", - "application.general.jobInterest", - Constants.JOB_INTERESTS, - false - ), - VALIDATOR.alphaArrayValidator( - "body", - "application.shortAnswer.skills", - true - ), - VALIDATOR.stringValidator( - "body", - "application.shortAnswer.comments", - true - ), - VALIDATOR.stringValidator( - "body", - "application.shortAnswer.question1", - false - ), - VALIDATOR.stringValidator( - "body", - "application.shortAnswer.question2", - false - ), - VALIDATOR.enumValidator( - "body", - "application.shortAnswer.previousHackathons", - Constants.PREVIOUS_HACKATHONS, - false - ), - - VALIDATOR.alphaArrayValidator( - "body", - "application.other.ethnicity", - false - ), - VALIDATOR.booleanValidator( - "body", - "application.other.privacyPolicy", - false, - true - ), - VALIDATOR.booleanValidator( - "body", - "application.other.codeOfConduct", - false, - true - ), - VALIDATOR.integerValidator( - "body", - "application.accommodation.travel", - true, - 0, - 100 - ), - VALIDATOR.mongoIdValidator("body", "application.team", true), - VALIDATOR.stringValidator("body", "application.location.timeZone", true), - VALIDATOR.stringValidator("body", "application.location.country", true), - VALIDATOR.stringValidator("body", "application.location.city", true), - ], - updateStatusValidator: [ - VALIDATOR.enumValidator( - "body", - "status", - Constants.HACKER_STATUSES, - false - ) - ], - checkInStatusValidator: [ - VALIDATOR.enumValidator( - "body", - "status", - Constants.HACKER_STATUS_CHECKED_IN, - false - ) - ], - uploadResumeValidator: [VALIDATOR.mongoIdValidator("param", "id", false)], - downloadResumeValidator: [VALIDATOR.mongoIdValidator("param", "id", false)], - statsValidator: [ - VALIDATOR.searchModelValidator("query", "model", false), - VALIDATOR.searchValidator("query", "q") - ], - batchUpdateValidator: [ - VALIDATOR.mongoIdArrayValidator("body", "ids", false) - ] -}; diff --git a/middlewares/validators/role.validator.js b/middlewares/validators/role.validator.js deleted file mode 100644 index e9b1d5e5..00000000 --- a/middlewares/validators/role.validator.js +++ /dev/null @@ -1,10 +0,0 @@ -"use strict"; -const VALIDATOR = require("./validator.helper"); -const Constants = require("../../constants/general.constant"); - -module.exports = { - newRoleValidator: [ - VALIDATOR.alphaValidator("body", "name", false), - VALIDATOR.routesValidator("body", "routes", false) - ] -}; diff --git a/middlewares/validators/routeParam.validator.js b/middlewares/validators/routeParam.validator.js deleted file mode 100644 index 88823d1d..00000000 --- a/middlewares/validators/routeParam.validator.js +++ /dev/null @@ -1,13 +0,0 @@ -"use strict"; -const VALIDATOR = require("./validator.helper"); -const Constants = require("../../constants/general.constant"); - -module.exports = { - idValidator: [VALIDATOR.mongoIdValidator("param", "id", false)], - - hackeridValidator: [VALIDATOR.mongoIdValidator("param", "hackerId", false)], - - emailValidator: [ - VALIDATOR.regexValidator("param", "email", false, Constants.EMAIL_REGEX) - ] -}; diff --git a/middlewares/validators/search.validator.js b/middlewares/validators/search.validator.js deleted file mode 100644 index 76becb19..00000000 --- a/middlewares/validators/search.validator.js +++ /dev/null @@ -1,14 +0,0 @@ -"use strict"; -const VALIDATOR = require("./validator.helper"); - -module.exports = { - searchQueryValidator: [ - VALIDATOR.searchModelValidator("query", "model", false), - VALIDATOR.alphaValidator("query", "sort", true), - VALIDATOR.integerValidator("query", "page", true, 0), - VALIDATOR.integerValidator("query", "limit", true, 0, 1000), - VALIDATOR.searchSortValidator("query", "sort_by"), - VALIDATOR.booleanValidator("query", "expand", true), - VALIDATOR.searchValidator("query", "q") - ] -}; diff --git a/middlewares/validators/settings.validator.js b/middlewares/validators/settings.validator.js deleted file mode 100644 index aebbc1d3..00000000 --- a/middlewares/validators/settings.validator.js +++ /dev/null @@ -1,11 +0,0 @@ -"use strict"; -const VALIDATOR = require("./validator.helper"); - -module.exports = { - createSettingsValidator: [ - VALIDATOR.dateValidator("body", "openTime", true), - VALIDATOR.dateValidator("body", "closeTime", true), - VALIDATOR.dateValidator("body", "confirmTime", true), - VALIDATOR.booleanValidator("body", "isRemote", true) - ] -}; diff --git a/middlewares/validators/sponsor.validator.js b/middlewares/validators/sponsor.validator.js deleted file mode 100644 index 61de86c1..00000000 --- a/middlewares/validators/sponsor.validator.js +++ /dev/null @@ -1,33 +0,0 @@ -"use strict"; -const VALIDATOR = require("./validator.helper"); -const Constants = require("../../constants/general.constant"); - -module.exports = { - // mongo id will be added at parse middleware - newSponsorValidator: [ - // the id of the base account - VALIDATOR.mongoIdValidator("body", "accountId", false), - // assuming that the tiers are between 0 and 5 (inclusive) - // 5 is the custom class - VALIDATOR.integerValidator("body", "tier", false, 0, 5), - VALIDATOR.stringValidator("body", "company", false), - VALIDATOR.regexValidator( - "body", - "contractURL", - false, - Constants.URL_REGEX - ), - VALIDATOR.mongoIdArrayValidator("body", "nominees", true) - ], - - updateSponsorValidator: [ - VALIDATOR.stringValidator("body", "company", true), - VALIDATOR.regexValidator( - "body", - "contractURL", - true, - Constants.URL_REGEX - ), - VALIDATOR.mongoIdArrayValidator("body", "nominees", true) - ] -}; diff --git a/middlewares/validators/team.validator.js b/middlewares/validators/team.validator.js deleted file mode 100644 index 2e61b491..00000000 --- a/middlewares/validators/team.validator.js +++ /dev/null @@ -1,29 +0,0 @@ -"use strict"; -const VALIDATOR = require("./validator.helper"); -const Constants = require("../../constants/general.constant"); - -module.exports = { - newTeamValidator: [ - VALIDATOR.stringValidator("body", "name", false), - VALIDATOR.regexValidator( - "body", - "devpostURL", - true, - Constants.DEVPOST_REGEX - ), - VALIDATOR.stringValidator("body", "projectName", true) - ], - - joinTeamValidator: [VALIDATOR.stringValidator("body", "name", false)], - - patchTeamValidator: [ - VALIDATOR.stringValidator("body", "name", true), - VALIDATOR.regexValidator( - "body", - "devpostURL", - true, - Constants.DEVPOST_REGEX - ), - VALIDATOR.stringValidator("body", "projectName", true) - ] -}; diff --git a/middlewares/validators/travel.validator.js b/middlewares/validators/travel.validator.js deleted file mode 100644 index 9f9c768c..00000000 --- a/middlewares/validators/travel.validator.js +++ /dev/null @@ -1,35 +0,0 @@ -"use strict"; -const VALIDATOR = require("./validator.helper"); -const Constants = require("../../constants/general.constant"); - -module.exports = { - newTravelValidator: [ - VALIDATOR.integerValidator("body", "request", false, 0, 3000), - VALIDATOR.jwtValidator( - "header", - "token", - process.env.JWT_CONFIRM_ACC_SECRET, - true - ) - ], - updateTravelValidator: [ - VALIDATOR.integerValidator("body", "request", false, 0, 3000) - ], - updateStatusValidator: [ - VALIDATOR.enumValidator( - "body", - "status", - Constants.TRAVEL_STATUSES, - false - ) - ], - updateOfferValidator: [ - VALIDATOR.integerValidator( - "body", - "offer", - false, - 0, - 3000 - ) - ] -}; diff --git a/middlewares/validators/validator.helper.js b/middlewares/validators/validator.helper.js deleted file mode 100644 index 25154791..00000000 --- a/middlewares/validators/validator.helper.js +++ /dev/null @@ -1,1033 +0,0 @@ -"use strict"; -const { body, query, header, param } = require("express-validator"); -const logger = require("../../services/logger.service"); -const mongoose = require("mongoose"); -const TAG = `[ VALIDATOR.HELPER.js ]`; -const jwt = require("jsonwebtoken"); -const Constants = require("../../constants/general.constant"); -const Models = { - Hacker: require("../../models/hacker.model") -}; - -/** - * Validates that field is a valid integer - * @param {"query" | "body" | "header" | "param"} fieldLocation the location where the field should be found - * @param {string} fieldname Name of the field that needs to be validated. - * @param {boolean} optional Whether the field is optional or not. - * @param {number} lowerBound Lower bound for a valid integer. - * @param {number} upperBound Lpper bound for a valid integer. - */ -function integerValidator( - fieldLocation, - fieldname, - optional = true, - lowerBound = -Infinity, - upperBound = Infinity -) { - const value = setProperValidationChainBuilder( - fieldLocation, - fieldname, - "Invalid integer" - ); - - if (optional) { - return value - .optional({ - checkFalsy: true - }) - .isInt() - .withMessage(`${fieldname} must be an integer.`) - .custom((value) => { - return value >= lowerBound && value <= upperBound; - }) - .withMessage( - `${fieldname} must be between ${lowerBound} and ${upperBound}` - ); - } else { - return value - .exists() - .withMessage("tier must exist") - .isInt() - .withMessage(`${fieldname} must be an integer.`) - .custom((value) => { - return value >= lowerBound && value <= upperBound; - }) - .withMessage( - `${fieldname} must be between ${lowerBound} and ${upperBound}` - ); - } -} - -/** - * Validates that field is a valid mongoID - * @param {"query" | "body" | "header" | "param"} fieldLocation the location where the field should be found - * @param {string} fieldname Name of the field that needs to be validated. - * @param {boolean} optional Whether the field is optional or not. - */ -function mongoIdValidator(fieldLocation, fieldname, optional = true) { - const mongoId = setProperValidationChainBuilder( - fieldLocation, - fieldname, - "Invalid mongoID" - ); - - if (optional) { - return mongoId - .optional({ - checkFalsy: true - }) - .isMongoId() - .withMessage("must be a valid mongoID"); - } else { - return mongoId - .exists() - .isMongoId() - .withMessage("must be a valid mongoID"); - } -} - -/** - * Validates that field is a valid mongoID array - * @param {"get" | "post"} getOrPost Whether the query is sent as a get or post request - * @param {string} fieldname Name of the field that needs to be validated. - * @param {boolean} optional Whether the field is optional or not. - */ -function mongoIdArrayValidator(fieldLocation, fieldname, optional = true) { - const arr = setProperValidationChainBuilder( - fieldLocation, - fieldname, - "Invalid mongoID array" - ); - - if (optional) { - return arr - .optional({ - checkFalsy: true - }) - .custom(isMongoIdArray) - .withMessage("Value must be an array of mongoIDs"); - } else { - return arr - .exists() - .custom(isMongoIdArray) - .withMessage("Value must be an array of mongoIDs"); - } -} - -/** - * Validates that field must be boolean. Optionally checks for desired boolean - * @param {"query" | "body" | "header" | "param"} fieldLocation the location where the field should be found - * @param {string} fieldname name of the field that needs to be validated. - * @param {boolean} optional whether the field is optional or not. - */ -function booleanValidator( - fieldLocation, - fieldname, - optional = true, - desire = null -) { - const booleanField = setProperValidationChainBuilder( - fieldLocation, - fieldname, - "Invalid boolean" - ); - - if (optional) { - // do not use check falsy option as a 'false' boolean will be skipped - return booleanField - .optional() - .isBoolean() - .withMessage("must be boolean") - .custom((val) => { - if (desire !== null) { - return desire === val; - } - return true; - }) - .withMessage(`Must be equal to ${desire}`); - } else { - return booleanField - .exists() - .isBoolean() - .withMessage("must be boolean") - .custom((val) => { - if (desire !== null) { - return desire === val; - } - return true; - }) - .withMessage(`Must be equal to ${desire}`); - } -} - -/** - * Validates that field name is ascii only. - * @param {"query" | "body" | "header" | "param"} fieldLocation the location where the field should be found - * @param {string} fieldname name of the field that needs to be validated. - * @param {boolean} optional whether the field is optional or not. - */ -function asciiValidator(fieldLocation, fieldname, optional = true) { - const name = setProperValidationChainBuilder( - fieldLocation, - fieldname, - "Invalid name" - ); - if (optional) { - return name - .optional({ - checkFalsy: true - }) - .isAscii() - .withMessage("must contain only ascii characters"); - } else { - return name - .exists() - .withMessage("name must exist") - .isAscii() - .withMessage("must contain only ascii characters"); - } -} - -/** - * Validates that field name is string only. - * @param {"query" | "body" | "header" | "param"} fieldLocation the location where the field should be found - * @param {string} fieldname name of the field that needs to be validated. - * @param {boolean} optional whether the field is optional or not. - */ -function stringValidator(fieldLocation, fieldname, optional = true) { - const name = setProperValidationChainBuilder( - fieldLocation, - fieldname, - "Invalid String" - ); - - if (optional) { - return name - .optional({ - checkFalsy: true - }) - .isString() - .withMessage("must be a string"); - } else { - return name - .exists() - .withMessage("name must exist") - .isString() - .withMessage("must be a string"); - } -} - -/** - * Validates the field against a regex - * @param {"query" | "body" | "header" | "param"} fieldLocation the location where the field should be found - * @param {string} fieldname Name of the field that needs to be validated. - * @param {boolean} optional Whether the field is optional or not. - * @param {regex} desire The regex to match against - * @description The default regex to match against accepts anything - */ -function regexValidator( - fieldLocation, - fieldname, - optional = true, - desire = Constants.ANY_REGEX -) { - const match = setProperValidationChainBuilder( - fieldLocation, - fieldname, - "Invalid name" - ); - - if (optional) { - return match - .optional({ - checkFalsy: true - }) - .matches(desire) - .withMessage("must be valid url"); - } else { - return match - .exists() - .withMessage("url must exist") - .matches(desire) - .withMessage("must be valid url"); - } -} - -/** - * Validates that field must be alphabetical. - * @param {"query" | "body" | "header" | "param"} fieldLocation the location where the field should be found - * @param {string} fieldname name of the field that needs to be validated. - * @param {boolean} optional whether the field is optional or not. - */ -function alphaValidator(fieldLocation, fieldname, optional = true) { - const name = setProperValidationChainBuilder( - fieldLocation, - fieldname, - "Invalid alpha string" - ); - if (optional) { - return name - .optional({ - checkFalsy: true - }) - .isAlpha() - .withMessage("must contain alphabet characters"); - } else { - return name - .exists() - .withMessage("must exist") - .isAlpha() - .withMessage("must contain alphabet characters"); - } -} -/** - * Validates that field must be an array with alphabetical characters. - * @param {"query" | "body" | "header" | "param"} fieldLocation the location where the field should be found - * @param {string} fieldname name of the field that needs to be validated. - * @param {boolean} optional whether the field is optional or not. - */ -function alphaArrayValidator(fieldLocation, fieldname, optional = true) { - const name = setProperValidationChainBuilder( - fieldLocation, - fieldname, - "Invalid alpha array" - ); - - if (optional) { - return name - .optional({ - checkFalsy: true - }) - .custom(alphaArrayValidationHelper) - .withMessage( - "must contain alphabet characters in each element of the array" - ); - } else { - return name - .exists() - .withMessage("must exist") - .custom(alphaArrayValidationHelper) - .withMessage( - "must contain alphabet characters in each element of the array" - ); - } -} - -/** - * Returns true if value is an alpha array, else false - * @param {*} value value to check against - */ -function alphaArrayValidationHelper(value) { - if (!Array.isArray(value)) { - return false; - } - for (const el of value) { - if (typeof el !== "string") { - return false; - } - } - return true; -} - -/** - * Validates that field must be at least 6 characters long. - * TODO: impose better restrictions. - * @param {"query" | "body" | "header" | "param"} fieldLocation the location where the field should be found - * @param {string} fieldname name of the field that needs to be validated. - * @param {boolean} optional whether the field is optional or not. - */ -function passwordValidator(fieldLocation, fieldname, optional = true) { - const password = setProperValidationChainBuilder( - fieldLocation, - fieldname, - "Invalid password" - ); - if (optional) { - return password - .optional({ - checkFalsy: true - }) - .isLength({ - min: 6 - }) - .withMessage("must be longer than 6 characters"); - } else { - return password - .exists() - .withMessage("password must exist") - .isLength({ - min: 6 - }) - .withMessage("must be longer than 6 characters"); - } -} - -/** - * Validates that field must be a valid application. - * @param {"query" | "body" | "header" | "param"} fieldLocation the location where the field should be found - * @param {string} fieldname name of the field that needs to be validated. - * @param {boolean} optional whether the field is optional or not. - */ -function applicationValidator(fieldLocation, fieldname, optional = true) { - const application = setProperValidationChainBuilder( - fieldLocation, - fieldname, - "Invalid application" - ); - let valid = true; - //helper object to iterate through the items in the application and track which items are not present. - const hasValid = { - general: false, - school: false, - degree: false, - graduationYear: false, - fieldOfStudy: false, - jobInterest: false, - URL: false, - shortAnswer: false, - question1: false, - question2: false, - previousHackathons: false, - accommodation: false, - shirtSize: false, - other: false, - ethnicity: false, - codeOfConduct: false, - privacyPolicy: false - }; - - if (optional) { - return application - .optional({ - checkFalsy: true - }) - .custom((app) => { - hasValid.general = app.hasOwnProperty("general"); - if (hasValid.general) { - hasValid.school = app.general.hasOwnProperty("school"); - hasValid.degree = app.general.hasOwnProperty("degree"); - hasValid.fieldOfStudy = app.general.hasOwnProperty( - "fieldOfStudy" - ); - hasValid.graduationYear = app.general.hasOwnProperty( - "graduationYear" - ); - hasValid.jobInterest = app.general.hasOwnProperty( - "jobInterest" - ); - hasValid.URL = app.general.hasOwnProperty("URL"); - } - - hasValid.shortAnswer = app.hasOwnProperty("shortAnswer"); - if (hasValid.shortAnswer) { - hasValid.question1 = app.shortAnswer.hasOwnProperty( - "question1" - ); - hasValid.question2 = app.shortAnswer.hasOwnProperty( - "question2" - ); - hasValid.previousHackathons = app.shortAnswer.hasOwnProperty( - "previousHackathons" - ); - } - hasValid.accommodation = app.hasOwnProperty("accommodation"); - if (hasValid.accommodation) { - hasValid.shirtSize = app.accommodation.hasOwnProperty( - "shirtSize" - ); - } - hasValid.other = app.hasOwnProperty("other"); - if (hasValid.other) { - hasValid.ethnicity = app.other.hasOwnProperty("ethnicity"); - hasValid.codeOfConduct = app.other.hasOwnProperty( - "codeOfConduct" - ); - hasValid.privacyPolicy = app.other.hasOwnProperty( - "privacyPolicy" - ); - } - // hasValid.github = - // !app.general.URL.github || - // typeof app.general.URL.github === "string"; - // hasValid.dribbble = - // !app.general.URL.dribbble || - // typeof app.general.URL.dribbble === "string"; - // hasValid.personal = - // !app.general.URL.personal || - // typeof app.general.URL.personal === "string"; - // hasValid.linkedIn = - // !app.general.URL.linkedIn || - // typeof app.general.URL.linkedIn === "string"; - // hasValid.other = - // !app.general.URL.other || - // typeof app.general.URL.other === "string"; - // hasValid.jobInterest = - // !!app.general.jobInterest && - // jobInterests.includes(app.general.jobInterest); - // hasValid.skills = - // !app.shortAnswer.skills || - // alphaArrayValidationHelper(app.shortAnswer.skills); - // hasValid.comments = - // !app.shortAnswer.comments || - // typeof app.shortAnswer.comments === "string"; - // hasValid.question1 = - // !!app.shortAnswer.question1 && - // typeof app.shortAnswer.question1 === "string"; - // hasValid.question2 = - // !!app.shortAnswer.question2 && - // typeof app.shortAnswer.question2 === "string"; - // hasValid.previousHackathons = - // !!app.shortAnswer.previousHackathons && - // typeof app.shortAnswer.previousHackathons === "number"; - // hasValid.team = - // !app.team || mongoose.Types.ObjectId.isValid(app.team); - - return ( - hasValid.general && - hasValid.school && - hasValid.degree && - hasValid.graduationYear && - hasValid.fieldOfStudy && - hasValid.jobInterest && - hasValid.URL && - hasValid.shortAnswer && - hasValid.question1 && - hasValid.question2 && - hasValid.accommodation && - hasValid.shirtSize && - hasValid.other && - hasValid.ethnicity && - hasValid.privacyPolicy && - hasValid.codeOfConduct - ); - }) - .withMessage({ - message: "Not all items of the application are valid", - isValid: hasValid - }); - } else { - return application - .custom((app) => { - hasValid.general = app.hasOwnProperty("general"); - if (hasValid.general) { - hasValid.school = app.general.hasOwnProperty("school"); - hasValid.degree = app.general.hasOwnProperty("degree"); - hasValid.fieldOfStudy = app.general.hasOwnProperty( - "fieldOfStudy" - ); - hasValid.graduationYear = app.general.hasOwnProperty( - "graduationYear" - ); - hasValid.jobInterest = app.general.hasOwnProperty( - "jobInterest" - ); - hasValid.URL = app.general.hasOwnProperty("URL"); - } - - hasValid.shortAnswer = app.hasOwnProperty("shortAnswer"); - if (hasValid.shortAnswer) { - hasValid.question1 = app.shortAnswer.hasOwnProperty( - "question1" - ); - hasValid.question2 = app.shortAnswer.hasOwnProperty( - "question2" - ); - hasValid.previousHackathons = app.shortAnswer.hasOwnProperty( - "previousHackathons" - ); - } - hasValid.accommodation = app.hasOwnProperty("accommodation"); - if (hasValid.accommodation) { - hasValid.shirtSize = app.accommodation.hasOwnProperty( - "shirtSize" - ); - } - hasValid.other = app.hasOwnProperty("other"); - if (hasValid.other) { - hasValid.ethnicity = app.other.hasOwnProperty("ethnicity"); - hasValid.codeOfConduct = app.other.hasOwnProperty( - "codeOfConduct" - ); - hasValid.privacyPolicy = app.other.hasOwnProperty( - "privacyPolicy" - ); - } - // hasValid.github = - // !app.general.URL.github || - // typeof app.general.URL.github === "string"; - // hasValid.dribbble = - // !app.general.URL.dribbble || - // typeof app.general.URL.dribbble === "string"; - // hasValid.personal = - // !app.general.URL.personal || - // typeof app.general.URL.personal === "string"; - // hasValid.linkedIn = - // !app.general.URL.linkedIn || - // typeof app.general.URL.linkedIn === "string"; - // hasValid.other = - // !app.general.URL.other || - // typeof app.general.URL.other === "string"; - // hasValid.jobInterest = - // !!app.general.jobInterest && - // jobInterests.includes(app.general.jobInterest); - // hasValid.skills = - // !app.shortAnswer.skills || - // alphaArrayValidationHelper(app.shortAnswer.skills); - // hasValid.comments = - // !app.shortAnswer.comments || - // typeof app.shortAnswer.comments === "string"; - // hasValid.question1 = - // !!app.shortAnswer.question1 && - // typeof app.shortAnswer.question1 === "string"; - // hasValid.question2 = - // !!app.shortAnswer.question2 && - // typeof app.shortAnswer.question2 === "string"; - // hasValid.previousHackathons = - // !!app.shortAnswer.previousHackathons && - // typeof app.shortAnswer.previousHackathons === "number"; - // hasValid.team = - // !app.team || mongoose.Types.ObjectId.isValid(app.team); - return ( - hasValid.general && - hasValid.school && - hasValid.degree && - hasValid.graduationYear && - hasValid.fieldOfStudy && - hasValid.jobInterest && - hasValid.URL && - hasValid.shortAnswer && - hasValid.question1 && - hasValid.question2 && - hasValid.previousHackathons && - hasValid.accommodation && - hasValid.shirtSize && - hasValid.other && - hasValid.ethnicity && - hasValid.privacyPolicy && - hasValid.codeOfConduct - ); - }) - .withMessage({ - message: - "Application does not have all of the required fields.", - isValid: hasValid - }); - } -} - -/** - * Function that checks whether the input array contains only mongoIds - * @param {String[]} arr array of strings - * @returns {boolean} whether the array contains only mongoIds - */ -function isMongoIdArray(arr) { - if (!Array.isArray(arr)) { - return false; - } - - for (var ele of arr) { - if (!mongoose.Types.ObjectId.isValid(ele)) { - return false; - } - } - - return true; -} - -/** - * Validates that field must be a valid json web token. - * @param {"query" | "body" | "header" | "param"} fieldLocation the location where the field should be found - * @param {string} fieldname name of the field that needs to be validated. - * @param {*} jwtSecret The secret that the json web token was encrypted with. - * @param {boolean} optional whether the field is optional or not. - */ -function jwtValidator(fieldLocation, fieldname, jwtSecret, optional = true) { - const jwtValidationChain = setProperValidationChainBuilder( - fieldLocation, - fieldname, - "Must be vali jwt" - ); - if (optional) { - return jwtValidationChain - .optional({ - checkFalsy: true - }) - .custom((value) => { - const token = jwt.verify(value, jwtSecret); - if (typeof token !== "undefined") { - return true; - } - return false; - }) - .withMessage(`must be valid jwt`); - } else { - return jwtValidationChain - .exists() - .withMessage("Token must be provided") - .custom((value) => { - const token = jwt.verify(value, jwtSecret); - if (typeof token !== "undefined") { - return true; - } - return false; - }) - .withMessage(`must be valid jwt`); - } -} - -/** - * Validates that field must be a valid searchable model - * @param {"query" | "body" | "header" | "param"} fieldLocation the location where the field should be found - * @param {string} fieldname name of the field that needs to be validated. - */ -function searchModelValidator(fieldLocation, fieldName) { - const paramChain = setProperValidationChainBuilder( - fieldLocation, - fieldName, - "Must be a valid searchable model" - ); - return paramChain - .exists() - .withMessage("Model must be provided") - .isLowercase() - .withMessage("Model must be lower case") - .isAlpha() - .withMessage("must contain alphabet characters") - .isIn([Constants.HACKER.toLowerCase()]); -} - -/**== - * Validates that field must be a valid search query. - * @param {"query" | "body" | "header" | "param"} fieldLocation the location where the field should be found - * @param {string} fieldname name of the field that needs to be validated. - */ -function searchValidator(fieldLocation, fieldname) { - const search = setProperValidationChainBuilder( - fieldLocation, - fieldname, - "Invalid search query" - ); - - return search - .exists() - .withMessage("Search query must be provided") - .custom((value, { req }) => { - //value is a serialized JSON - value = JSON.parse(value); - let modelString = req.query.model; - //Supported models for searching - let model; - if (modelString === Constants.HACKER.toLowerCase()) { - model = Models.Hacker; - } else { - return false; - } - //Validates each clause in the query - for (var q in value) { - //Checks that each clause has Param, Value, and Operation - var clause = value[q]; - if ( - !( - clause.hasOwnProperty("param") || - clause.hasOwnProperty("value") || - clause.hasOwnProperty("operation") - ) - ) { - return false; - } - var schemaPath = model.searchableField(clause.param); - if (!schemaPath) return false; - //Validates that operation corresponding to each clause is valid - switch (schemaPath) { - case "String": - if ( - !["equals", "ne", "regex", "in"].includes( - clause.operation - ) - ) { - return false; - } - break; - case "Number": - if ( - ![ - "equals", - "ne", - "gte", - "lte", - "le", - "ge", - "in" - ].includes(clause.operation) - ) { - return false; - } - break; - case "Boolean": - if (!["equals", "ne"].includes(clause.operation)) { - return false; - } - break; - } - } - return true; - }); -} - -function searchSortValidator(fieldLocation, fieldName) { - const searchSort = setProperValidationChainBuilder( - fieldLocation, - fieldName, - "Invalid sort criteria" - ); - return searchSort - .optional({ - checkFalsy: true - }) - .custom((value, { req }) => { - let modelString = req.query.model; - if (modelString.equals("hacker")) { - model = Models.Hacker; - } else { - return false; - } - if (model.searchableField(value)) { - let sortOrder = param("sort", "Sorting order not found"); - if (!sortOrder.equals("asc") || !sortOrder.equals("desc")) { - return false; - } - } else { - return false; - } - return true; - }); -} - -/** - * Validates that field must be a valid date according to javascript Date.parse - * @param {"query" | "body" | "header" | "param"} fieldLocation the location where the field should be found - * @param {string} fieldname name of the field that needs to be validated. - * @param {boolean} optional whether the field is optional or not. - */ -function dateValidator(fieldLocation, fieldname, optional = true) { - const date = setProperValidationChainBuilder( - fieldLocation, - fieldname, - "Invalid date" - ); - if (optional) { - return date - .optional({ - checkFalsy: true - }) - .custom((value) => { - return !isNaN(Date.parse(value)); - }) - .withMessage({ - message: "Date is not valid.", - isValid: date - }); - } else { - return date - .exists() - .withMessage("Date field must be specified") - .custom((value) => { - return !isNaN(Date.parse(value)); - }) - .withMessage({ - message: "Date is not valid.", - isValid: date - }); - } -} - -/** - * Validates that field must be a valid phone number, having numbers and having a minimum length of 8 - * Regex was not chosen because the number is not restricted to a particular country or location - * The smallest number length without country code is 5 digits. With the country code, it makes 8. - * @param {"query" | "body" | "header" | "param"} fieldLocation the location where the field should be found - * @param {string} fieldname name of the field that needs to be validated. - * @param {boolean} optional whether the field is optional or not. - */ -function phoneNumberValidator(fieldLocation, fieldname, optional = true) { - const number = setProperValidationChainBuilder( - fieldLocation, - fieldname, - "Invalid phone number" - ); - if (optional) { - return number - .optional({ - checkFalsy: true - }) - .isLength({ - min: 8 - }) - .isInt() - .withMessage("Phone number must consist of numbers."); - } else { - return number - .exists() - .withMessage("Phone number must be specified.") - .isLength({ - min: 8 - }) - .isInt() - .withMessage("Phone number must consist of numbers."); - } -} - -/** - * Validates that field must be an array of routes - * @param {"query" | "body" | "header" | "param"} fieldLocation the location where the field should be found - * @param {string} fieldname name of the field that needs to be validated. - * @param {boolean} optional whether the field is optional or not. - */ -function routesValidator(fieldLocation, fieldname, optional = true) { - const routes = setProperValidationChainBuilder( - fieldLocation, - fieldname, - "Invalid routes" - ); - - if (optional) { - return routes - .optional({ - checkFalsy: true - }) - .custom(routesArrayValidationHelper) - .withMessage("The value must be a route"); - } else { - return routes - .exists() - .withMessage("The route must exist.") - .custom(routesArrayValidationHelper) - .withMessage("The value must be a route"); - } -} - -/** - * Returns true if value an array of routes - * @param {*} routes value to check against - */ -function routesArrayValidationHelper(routes) { - if (!Array.isArray(routes)) { - return false; - } - for (const route of routes) { - if (route.uri === null || typeof route.uri !== "string") { - return false; - } - if ( - route.requestType === null || - !checkEnum(route.requestType, Constants.REQUEST_TYPES) - ) { - return false; - } - } - return true; -} - -/** - * Validates that field must be a value within the enum passed in through parameter 'enums' - * @param {"query" | "body" | "header" | "param"} fieldLocation The location where the field should be found. - * @param {string} fieldname The name of the field that needs to be validated. - * @param {Object} enums The enum object that the field must be part of. - * @param {boolean} optional Whether the field is optional or not. - */ -function enumValidator(fieldLocation, fieldname, enums, optional = true) { - const enumValue = setProperValidationChainBuilder( - fieldLocation, - fieldname, - "Invalid enums" - ); - - if (optional) { - return enumValue - .optional({ - checkFalsy: true - }) - .custom((val) => { - return checkEnum(val, enums); - }) - .withMessage("The value must be part of the enum"); - } else { - return enumValue - .exists() - .withMessage("The value being checked agains the enums must exist.") - .custom((val) => { - return checkEnum(val, enums); - }) - .withMessage("The value must be part of the enum"); - } -} - -/** - * Checks that 'value' is part of 'enums'. 'enums' should be an enum dict. - * @param {*} value Should be of the same type as the values of the enum - * @param {Object} enums An object that represents an enum. They keys are the keys of the enum, and the values are the enum values. - * @return {boolean} Returns true if the value is part of the enum, false otherwise. - */ -function checkEnum(value, enums) { - for (var enumKey in enums) { - if (value === enums[enumKey]) { - return true; - } - } - return false; -} - -/** - * - * @param {"query" | "body" | "header" | "param"} fieldLocation the location where the field should be found - * @param {string} fieldname name of the field that needs to be validated. - * @param {*} errorString the string that is sent back to the user if the field is Invalid - */ -function setProperValidationChainBuilder( - fieldLocation, - fieldName, - errorString -) { - /** - * check: ValidationChainBuilder; - * body: ValidationChainBuilder; - * cookie: ValidationChainBuilder; - * header: ValidationChainBuilder; - * param: ValidationChainBuilder; - * query: ValidationChainBuilder; - */ - switch (fieldLocation) { - case "query": - return query(fieldName, errorString); - case "body": - return body(fieldName, errorString); - case "header": - return header(fieldName, errorString); - case "param": - return param(fieldName, errorString); - default: - logger.error(`${TAG} Invalid field location: ${fieldLocation}`); - } -} - -module.exports = { - regexValidator: regexValidator, - integerValidator: integerValidator, - mongoIdValidator: mongoIdValidator, - mongoIdArrayValidator: mongoIdArrayValidator, - asciiValidator: asciiValidator, - alphaValidator: alphaValidator, - alphaArrayValidator: alphaArrayValidator, - passwordValidator: passwordValidator, - booleanValidator: booleanValidator, - applicationValidator: applicationValidator, - jwtValidator: jwtValidator, - searchValidator: searchValidator, - searchModelValidator: searchModelValidator, - searchSortValidator: searchSortValidator, - phoneNumberValidator: phoneNumberValidator, - dateValidator: dateValidator, - enumValidator: enumValidator, - routesValidator: routesValidator, - stringValidator: stringValidator -}; diff --git a/middlewares/validators/volunteer.validator.js b/middlewares/validators/volunteer.validator.js deleted file mode 100644 index 36c784f1..00000000 --- a/middlewares/validators/volunteer.validator.js +++ /dev/null @@ -1,8 +0,0 @@ -"use strict"; -const VALIDATOR = require("./validator.helper"); - -module.exports = { - newVolunteerValidator: [ - VALIDATOR.mongoIdValidator("body", "accountId", false) - ] -}; diff --git a/models/account.model.ts b/models/account.model.ts index 91ac634c..34a6dd43 100644 --- a/models/account.model.ts +++ b/models/account.model.ts @@ -1,24 +1,37 @@ import { Column, Entity, PrimaryGeneratedColumn } from "typeorm"; import { compareSync } from "bcrypt"; -import { IsDate, IsEmail, IsPhoneNumber } from "class-validator"; +import { + IsDate, + IsEmail, + IsEnum, + IsInt, + IsPhoneNumber, + IsString, + Length +} from "class-validator"; import * as Constants from "../constants/general.constant"; import { classToPlain, Exclude } from "class-transformer"; @Entity() -export abstract class Account { +class Account { @PrimaryGeneratedColumn() - identifier: number; + @IsInt() + readonly identifier: number; @Column({ nullable: false }) + @IsString() firstName: string; @Column({ nullable: false }) + @IsString() lastName: string; @Column({ default: "Prefer not to say" }) + @IsString() pronoun: string; @Column({ default: "Prefer not to say" }) + @IsString() gender: string; @Column({ nullable: false, unique: true }) @@ -27,9 +40,11 @@ export abstract class Account { @Column({ nullable: false }) @Exclude({ toPlainOnly: true }) + @Length(8, 255) password: string; @Column() + @IsString() dietaryRestrictions: string; @Column({ default: false }) @@ -39,9 +54,11 @@ export abstract class Account { enum: Constants.EXTENDED_USER_TYPES, default: Constants.HACKER }) + @IsEnum(Constants.EXTENDED_USER_TYPES) accountType: string; @Column("date", { nullable: false }) + @IsDate() birthDate: Date; @Column() diff --git a/models/accountConfirmationToken.model.ts b/models/accountConfirmationToken.model.ts index 459fb2a8..0acc5c4f 100644 --- a/models/accountConfirmationToken.model.ts +++ b/models/accountConfirmationToken.model.ts @@ -1,3 +1,4 @@ +import { IsEmail, IsEnum } from "class-validator"; import { Entity, BaseEntity, @@ -7,38 +8,34 @@ import { PrimaryGeneratedColumn } from "typeorm"; import Account from "./account.model"; - -const Constants = { - General: require("../constants/general.constant") -}; +import * as GeneralConstants from "../constants/general.constant"; @Entity() -class AccountConfirmation extends BaseEntity { +class AccountConfirmation { @PrimaryGeneratedColumn() - identifier: number; + readonly identifier: number; @OneToOne(() => Account) @JoinColumn() account?: Account; @Column({ - enum: Constants.General.EXTENDED_USER_TYPES, - default: Constants.General.HACKER + enum: GeneralConstants.EXTENDED_USER_TYPES, + default: GeneralConstants.HACKER }) + @IsEnum(GeneralConstants.EXTENDED_USER_TYPES) accountType: string; @Column({ nullable: false }) + @IsEmail() email: string; @Column({ - enum: Constants.General.CONFIRMATION_TYPES, - default: Constants.General.CONFIRMATION_TYPE_ORGANIC + enum: GeneralConstants.CONFIRMATION_TYPES, + default: GeneralConstants.CONFIRMATION_TYPE_ORGANIC }) + @IsEnum(GeneralConstants.CONFIRMATION_TYPES) confirmationType: string; - - toJSON() { - return this; - } } export default AccountConfirmation; diff --git a/models/application.model.ts b/models/application.model.ts index 6a6bf53e..4af86c0c 100644 --- a/models/application.model.ts +++ b/models/application.model.ts @@ -1,7 +1,6 @@ import { IsInt, IsJSON, IsString, Max } from "class-validator"; import { Entity, - BaseEntity, PrimaryGeneratedColumn, Column, JoinColumn, @@ -57,9 +56,9 @@ export interface ApplicationSchema { } @Entity() -class Application extends BaseEntity { +class Application { @PrimaryGeneratedColumn() - identifier: number; + readonly identifier: number; @Column({ nullable: false }) @IsInt() diff --git a/models/bus.model.ts b/models/bus.model.ts index a5933603..2731370f 100644 --- a/models/bus.model.ts +++ b/models/bus.model.ts @@ -1,4 +1,11 @@ -import { Entity, BaseEntity, Column, ManyToOne, JoinColumn, PrimaryGeneratedColumn } from "typeorm"; +import { + Entity, + BaseEntity, + Column, + ManyToOne, + JoinColumn, + PrimaryGeneratedColumn +} from "typeorm"; import Hacker from "./hacker.model"; interface OriginSchema { @@ -11,9 +18,9 @@ interface OriginSchema { } @Entity() -class Bus extends BaseEntity { +class Bus { @PrimaryGeneratedColumn() - identifier: number; + readonly identifier: number; @Column("jsonb", { nullable: false }) origin: OriginSchema; @@ -24,10 +31,6 @@ class Bus extends BaseEntity { @ManyToOne(() => Hacker) @JoinColumn() hackers: Hacker[]; - - toJSON() { - return this; - } } export default Bus; diff --git a/models/passwordResetToken.model.ts b/models/passwordResetToken.model.ts index ef107229..0bdae6d5 100644 --- a/models/passwordResetToken.model.ts +++ b/models/passwordResetToken.model.ts @@ -1,3 +1,4 @@ +import { IsDate } from "class-validator"; import { Entity, BaseEntity, @@ -9,20 +10,17 @@ import { import Account from "./account.model"; @Entity() -class PasswordReset extends BaseEntity { +class PasswordReset { @PrimaryGeneratedColumn() - identifier: number; + readonly identifier: number; @OneToOne(() => Account) @JoinColumn() account: Account; @Column({ nullable: false }) + @IsDate() createdAt: Date; - - toJSON() { - return this; - } } export default PasswordReset; diff --git a/models/settings.model.ts b/models/settings.model.ts deleted file mode 100644 index 48d27611..00000000 --- a/models/settings.model.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Entity, BaseEntity, Column, PrimaryGeneratedColumn } from "typeorm"; - -@Entity() -class Settings extends BaseEntity { - @PrimaryGeneratedColumn() - identifier: number; - - @Column() // One month from now. - openTime: Date; - - @Column() // One year and 1 month from now. - closeTime: Date; - - @Column() // 1 year and 2 months from now. - confirmTime: Date; - - @Column({ default: false }) - isRemote: boolean; - - toJSON() { - return this; - } -} - -export default Settings; diff --git a/models/sponsor.model.ts b/models/sponsor.model.ts index 309f661d..785cb24c 100644 --- a/models/sponsor.model.ts +++ b/models/sponsor.model.ts @@ -1,3 +1,4 @@ +import { IsInt, IsString } from "class-validator"; import { Entity, Column, @@ -12,12 +13,15 @@ import Hacker from "./hacker.model"; @Entity() class Sponsor { @Column({ default: 0 }) + @IsInt() tier: number; @Column({ nullable: false }) + @IsString() company: string; @Column({ nullable: false }) + @IsString() contract: string; @ManyToMany(() => Hacker) diff --git a/models/team.model.ts b/models/team.model.ts index dcfc2305..d44ba397 100644 --- a/models/team.model.ts +++ b/models/team.model.ts @@ -1,3 +1,4 @@ +import { IsString } from "class-validator"; import { Entity, BaseEntity, @@ -5,15 +6,15 @@ import { OneToMany, PrimaryGeneratedColumn } from "typeorm"; -import * as Constants from "../constants/general.constant"; import Hacker from "./hacker.model"; @Entity() -class Team extends BaseEntity { +class Team { @PrimaryGeneratedColumn() identifier: number; @Column({ nullable: false, unique: true }) + @IsString() name: string; //TODO: Implement max team size. @@ -24,9 +25,11 @@ class Team extends BaseEntity { hackers: Hacker[]; @Column({ default: undefined }) + @IsString() submission: string; @Column() + @IsString() project: string; } diff --git a/models/travel.model.ts b/models/travel.model.ts index f9d2d6c3..2f0bfc0d 100644 --- a/models/travel.model.ts +++ b/models/travel.model.ts @@ -1,13 +1,8 @@ import * as Constants from "../constants/general.constant"; -import { - Entity, - BaseEntity, - OneToOne, - JoinColumn, - Column, - PrimaryGeneratedColumn -} from "typeorm"; +import { Entity, BaseEntity, OneToOne, JoinColumn, Column } from "typeorm"; import Hacker from "./hacker.model"; +import * as GeneralConstants from "../constants/general.constant"; +import { IsEnum, IsInt, IsNumber, IsString, Max, Min } from "class-validator"; @Entity() class Travel extends BaseEntity { @@ -16,16 +11,23 @@ class Travel extends BaseEntity { hacker: Hacker; @Column({ - enum: Constants.TRAVEL_STATUSES, + enum: GeneralConstants.TravelStatus, nullable: false, default: "None" }) + @IsEnum(GeneralConstants.TravelStatus) status: String; @Column({ nullable: false }) + @IsNumber() + @Min(0) + @Max(300) request: number; @Column({ default: 0 }) + @IsNumber() + @Min(0) + @Max(300) offer: number; } From 3c2da705fc8c245c7c54f0bfb632bdf46f2d5f68 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Sun, 26 Dec 2021 18:08:42 -0500 Subject: [PATCH 24/72] refactor: remove unnecessary routing, middleware, and script files. --- middlewares/parse-body.middleware.js | 28 - middlewares/util.middleware.js | 32 - routes/api/hacker.js | 910 --------------------------- routes/api/search.js | 74 --- scripts/batch_update_travel.js | 10 - 5 files changed, 1054 deletions(-) delete mode 100644 middlewares/parse-body.middleware.js delete mode 100644 middlewares/util.middleware.js delete mode 100644 routes/api/hacker.js delete mode 100644 routes/api/search.js delete mode 100644 scripts/batch_update_travel.js diff --git a/middlewares/parse-body.middleware.js b/middlewares/parse-body.middleware.js deleted file mode 100644 index 02dad8ae..00000000 --- a/middlewares/parse-body.middleware.js +++ /dev/null @@ -1,28 +0,0 @@ -"use strict"; -const { validationResult, matchedData } = require("express-validator"); -const Constants = { - Error: require("../constants/error.constant") -}; - -module.exports = { - middleware: middleware -}; - -/** - * Moves matched data to req.body, and fails if any validation fails. - * @param {*} req - * @param {*} res - * @param {(err?)=>void} next - */ -function middleware(req, res, next) { - const errors = validationResult(req); - if (!errors.isEmpty()) { - return next({ - status: 422, - message: Constants.Error.VALIDATION_422_MESSAGE, - data: errors.mapped() - }); - } - req.body = matchedData(req); - return next(); -} diff --git a/middlewares/util.middleware.js b/middlewares/util.middleware.js deleted file mode 100644 index 9eebb32b..00000000 --- a/middlewares/util.middleware.js +++ /dev/null @@ -1,32 +0,0 @@ -"use strict"; -const multer = require("multer"); -//Set up multer middleware -const m = multer({ - storage: multer.memoryStorage(), - limits: { - fileSize: 4000000 //4mb - }, - fileFilter: function(req, file, cb) { - if (file.mimetype !== "application/pdf") { - cb(null, false); - } else { - cb(null, true); - } - } -}); - -/** - * Wrapper function for all asynchronous middleware, aka middleware that returns promises. - * @param {(req,res,next:(err?:any)=>void)=>any} fn The function that is asynchronous - * @returns {(req,res,next:(err?:any)=>void)=>any} Another middleware that, when invoked, will attempt to resolve fn. If there is an error, - * then it will pass the error to 'next' function. - */ -function asyncMiddleware(fn) { - return (req, res, next) => { - Promise.resolve(fn(req, res, next)).catch(next); - }; -} -module.exports = { - asyncMiddleware: asyncMiddleware, - Multer: m -}; diff --git a/routes/api/hacker.js b/routes/api/hacker.js deleted file mode 100644 index d3da1d65..00000000 --- a/routes/api/hacker.js +++ /dev/null @@ -1,910 +0,0 @@ -"use strict"; -const express = require("express"); -const Controllers = { - Hacker: require("../../controllers/hacker.controller") -}; -const Middleware = { - Validator: { - /* Insert the require statement to the validator file here */ - Hacker: require("../../middlewares/validators/hacker.validator"), - RouteParam: require("../../middlewares/validators/routeParam.validator") - }, - /* Insert all of ther middleware require statements here */ - parseBody: require("../../middlewares/parse-body.middleware"), - Util: require("../../middlewares/util.middleware"), - Hacker: require("../../middlewares/hacker.middleware"), - Auth: require("../../middlewares/auth.middleware"), - Search: require("../../middlewares/search.middleware"), - Settings: require("../../middlewares/settings.middleware") -}; -const Services = { - Hacker: require("../../services/hacker.service"), - Account: require("../../services/account.service") -}; -const CONSTANTS = require("../../constants/general.constant"); - -module.exports = { - activate: function(apiRouter) { - const hackerRouter = express.Router(); - - /** - * @api {get} /hacker/self get information about own hacker - * @apiName self - * @apiGroup Hacker - * @apiVersion 0.0.8 - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data Hacker object - * @apiSuccessExample {object} Success-Response: - * { - "message": "Hacker found by logged in account id", - "data": { - "id":"5bff4d736f86be0a41badb91", - "application":{ - "URL":{ - "resume":"resumes/1543458163426-5bff4d736f86be0a41badb91", - "github":"https://github.com/abcd", - "dropler":"https://dribbble.com/abcd", - "personal":"https://www.hi.com/", - "linkedIn":"https://linkedin.com/in/abcd", - "other":"https://github.com/hackmcgill/hackerAPI/issues/168" - }, - "jobInterest":"Internship", - "skills":["Javascript","Typescript"], - "comments":"hi!", - "essay":"Pls accept me" - }, - "status":"Applied", - "ethnicity":["White or Caucasian"," Asian or Pacific Islander"], - "accountId":"5bff2a35e533b0f6562b4998", - "school":"McPherson College", - "gender":"Female", - "travel":0, - "major":["Accounting"], - "graduationYear":2019, - "codeOfConduct":true, - } - } - - * @apiError {string} message Error message - * @apiError {object} data empty - * @apiErrorExample {object} Error-Response: - * {"message": "Hacker not found", "data": {}} - */ - hackerRouter.route("/self").get( - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized(), - - Middleware.Hacker.findSelf, - Controllers.Hacker.showHacker - ); - - /** - * @api {post} /hacker/ create a new hacker - * @apiName createHacker - * @apiGroup Hacker - * @apiVersion 0.0.8 - * - * @apiParam (body) {MongoID} accountId ObjectID of the respective account - * @apiParam (body) {String} school Name of the school the hacker goes to - * @apiParam (body) {String} gender Gender of the hacker - * @apiParam (body) {Number} travel Whether the hacker requires a bus for transportation - * @apiParam (body) {String[]} ethnicity the ethnicities of the hacker - * @apiParam (body) {String[]} major the major of the hacker - * @apiParam (body) {Number} graduationYear the graduation year of the hacker - * @apiParam (body) {Boolean} codeOfConduct acceptance of the code of conduct - * @apiParam (body) {Json} application The hacker's application. Resume and jobInterest fields are required. - * @apiParamExample {Json} application: - * { - "application":{ - "general":{ - "school": "McGill University", - "degree": "Undergraduate", - "fieldOfStudy": "Computer Science", - "graduationYear": "2021", - "jobInterest":"Internship", - "URL":{ - "resume":"resumes/1543458163426-5bff4d736f86be0a41badb91", - "github":"https://github.com/abcd", - "dropler":"https://dribbble.com/abcd", - "personal":"https://www.hi.com/", - "linkedIn":"https://linkedin.com/in/abcd", - "other":"https://github.com/hackmcgill/hackerAPI/issues/168" - }, - }, - "shortAnswer": { - "skills":["Javascript","Typescript"], - "question1": "I love McHacks", - "question2":"Pls accept me", - "previousHackathons": "5", - "comments":"hi!", - }, - "other:" { - "gender": "male", - "ethnicity": "Asian or Pacific Islander", - "privacyPolicy": true, - "codeOfConduct": true, - } - "accommodation": { - "travel": 0 - }, - "location": { - "timeZone": "GMT-5", - "country": "Canada", - "city": "Montreal" - } - } - - * } - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data Hacker object - * @apiSuccessExample {object} Success-Response: - * { - * "message": "Hacker creation successful", - * "data": { - "id":"5bff4d736f86be0a41badb91", - "application":{ - "general":{ - "school": "McGill University", - "degree": "Undergraduate", - "fieldOfStudy": "Computer Science", - "graduationYear": "2021", - "jobInterest":"Internship", - "URL":{ - "resume":"resumes/1543458163426-5bff4d736f86be0a41badb91", - "github":"https://github.com/abcd", - "dropler":"https://dribbble.com/abcd", - "personal":"https://www.hi.com/", - "linkedIn":"https://linkedin.com/in/abcd", - "other":"https://github.com/hackmcgill/hackerAPI/issues/168" - }, - }, - "shortAnswer": { - "skills":["Javascript","Typescript"], - "question1": "I love McHacks", - "question2":"Pls accept me", - "previousHackathons": "5", - "comments":"hi!", - }, - "other:" { - "gender": "male", - "ethnicity": "Asian or Pacific Islander", - "privacyPolicy": true, - "codeOfConduct": true, - } - "accommodation": { - "travel": 0 - }, - "location": { - "timeZone": "GMT-5", - "country": "Canada", - "city": "Montreal" - } - } - * } - - * @apiError {string} message Error message - * @apiError {object} data empty - * @apiErrorExample {object} Error-Response: - * {"message": "Error while creating hacker", "data": {}} - */ - hackerRouter.route("/").post( - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized(), - Middleware.Validator.Hacker.newHackerValidator, - Middleware.parseBody.middleware, - Middleware.Settings.confirmAppsOpen, - - // validate type - Middleware.Hacker.validateConfirmedStatusFromAccountId, - // validate that the accountId is not being used for any other thing - Middleware.Hacker.checkDuplicateAccountLinks, - - Middleware.Hacker.parseHacker, - - Middleware.Hacker.addDefaultStatus, - Middleware.Auth.createRoleBindings(CONSTANTS.HACKER), - Middleware.Hacker.createHacker, - Middleware.Hacker.sendAppliedStatusEmail, - - Controllers.Hacker.createdHacker - ); - - /** - * @api {get} /hacker/stats - * Gets the stats of all of the hackers who have applied. - * @apiName getHackerStats - * @apiGroup Hacker - * @apiVersion 0.0.9 - * - * @apiParam (query) {String} model the model to be searched (Only hacker supported) - * @apiParam (query) {Array} q the query to be executed. For more information on how to format this, please see https://docs.mchacks.ca/architecture/ - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data Hacker object - * @apiSuccessExample {object} Success-Response: - * { - * "message": "Retrieved stats", - * "data": { - * "stats" : { - * "total": 10, - "status": { "Applied": 10 }, - "school": { "McGill University": 3, "Harvard University": 7 }, - degree: { "Undergraduate": 10 }, - gender: { "Male": 1, "Female": 9 }, - travel: { "true": 7, "false": 3 }, - ethnicity: { "White": 10, }, - jobInterest: { "Internship": 10 }, - major: { "Computer Science": 10 }, - graduationYear: { "2019": 10 }, - dietaryRestrictions: { "None": 10 }, - shirtSize: { "M": 3, "XL": 7 }, - age: { "22": 10 }, - applicationDate: {"2020-12-27" : 2, "2020-12-28" : 8} - } - * } - * } - * - */ - hackerRouter - .route("/stats") - .get( - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized(), - Middleware.Validator.Hacker.statsValidator, - Middleware.parseBody.middleware, - Middleware.Search.setExpandTrue, - Middleware.Search.parseQuery, - Middleware.Search.executeQuery, - Middleware.Hacker.getStats, - Controllers.Hacker.gotStats - ); - - /** - * @api {patch} /hacker/status/:id update a hacker's status - * @apiName patchHackerStatus - * @apiGroup Hacker - * @apiVersion 0.0.9 - * - * @apiParam (body) {string} [status] Status of the hacker's application ("None"|"Applied"|"Accepted"|"Declined"|"Waitlisted"|"Confirmed"|"Withdrawn"|"Checked-in") - * @apiSuccess {string} message Success message - * @apiSuccess {object} data Hacker object - * @apiSuccessExample {object} Success-Response: - * { - * "message": "Changed hacker information", - * "data": { - * "status": "Accepted" - * } - * } - * @apiPermission Administrator - */ - hackerRouter.route("/status/:id").patch( - Middleware.Validator.RouteParam.idValidator, - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), - Middleware.Validator.Hacker.updateStatusValidator, - Middleware.parseBody.middleware, - Middleware.Hacker.parsePatch, - Middleware.Hacker.validateConfirmedStatusFromHackerId, - - Middleware.Hacker.updateHacker, - Middleware.Hacker.sendStatusUpdateEmail, - Controllers.Hacker.updatedHacker - ); - - /** - * @api {patch} /hacker/accept/:id accept a Hacker - * @apiName acceptHacker - * @apiGroup Hacker - * @apiVersion 2.0.0 - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data Hacker object - * @apiSuccessExample {object} Success-Response: - * { - * "message": "Changed hacker information", - * "data": { - * "status": "Accepted" - * } - * } - * @apiPermission Administrator - */ - hackerRouter - .route("/accept/:id") - .patch( - Middleware.Validator.RouteParam.idValidator, - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), - Middleware.Hacker.validateConfirmedStatusFromHackerId, - Middleware.Hacker.parseAccept, - Middleware.Hacker.updateHacker, - Middleware.Hacker.sendStatusUpdateEmail, - Controllers.Hacker.updatedHacker - ); - - /** - * @api {patch} /hacker/acceptEmail/:email accept a Hacker by email - * @apiName acceptHacker - * @apiGroup Hacker - * @apiVersion 2.0.0 - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data Hacker object - * @apiSuccessExample {object} Success-Response: - * { - * "message": "Changed hacker information", - * "data": { - * "status": "Accepted" - * } - * } - * @apiPermission Administrator - */ - hackerRouter - .route("/acceptEmail/:email") - .patch( - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized([Services.Hacker.findByEmail]), - Middleware.Validator.RouteParam.emailValidator, - Middleware.parseBody.middleware, - Middleware.Hacker.findByEmail, - Middleware.Hacker.parseAcceptEmail, - Middleware.Hacker.obtainEmailByHackerId, - Middleware.Hacker.completeStatusUpdateEmail, - Controllers.Hacker.updatedHacker - ); - - /** - * @api {patch} /hacker/batchAccept/ accept array of Hackers - * @apiName acceptHacker - * @apiGroup Hacker - * @apiVersion 3.0.0 - * - * @apiParam (body) {{ids: ObjectId[]}} Array of id(s) that needed to be accepted - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data success_ids array and errors array. Errors array will contain a detailed error for why the batch update for a given ID did not work - * @apiSuccessExample {object} Success-Response: - * { - * "message": "Hacker batch update successful.", - * "data": { - * "success_ids": ["id1", "id2"] - * "errors": [{status: 404, message: "ACCOUNT_NOT_FOUND", account: null, hacker_id: "id3"}] - * } - * } - * @apiPermission Administrator - */ - hackerRouter - .route("/batchAccept") - .patch( - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized([]), - Middleware.Validator.Hacker.batchUpdateValidator, - Middleware.parseBody.middleware, - Middleware.Hacker.validateConfirmedStatusFromArrayofHackerIds, - Middleware.Hacker.parseAcceptBatch, - Middleware.Hacker.updateBatchHacker, - Middleware.Hacker.sendStatusUpdateEmailForMultipleIds, - Controllers.Hacker.updatedHackerBatch - ); - /** - * @api {patch} /hacker/checkin/:id update a hacker's status to be 'Checked-in'. Note that the Hacker must eitehr be Accepted or Confirmed. - * @apiName checkinHacker - * @apiGroup Hacker - * @apiVersion 0.0.9 - * @apiParam (body) {string} [status] Check-in status. "Checked-in" - * @apiSuccess {string} message Success message - * @apiSuccess {object} data Hacker object - * @apiSuccessExample {object} Success-Response: - * { - * "message": "Changed hacker information", - * "data": { - * "status": "Checked-in" - * } - * } - * @apiPermission Administrator - * @apiPermission Volunteer - */ - hackerRouter.route("/checkin/:id").patch( - Middleware.Validator.RouteParam.idValidator, - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), - - Middleware.parseBody.middleware, - Middleware.Hacker.parsePatch, - Middleware.Hacker.validateConfirmedStatusFromHackerId, - Middleware.Hacker.checkStatus([ - CONSTANTS.HACKER_STATUS_ACCEPTED, - CONSTANTS.HACKER_STATUS_CONFIRMED - ]), - Middleware.Hacker.parseCheckIn, - Middleware.Hacker.updateHacker, - - Middleware.Hacker.sendStatusUpdateEmail, - Controllers.Hacker.updatedHacker - ); - - /** - * @api {patch} /hacker/:id update a hacker's information. - * @apiDescription This route only contains the ability to update a subset of a hacker's information. If you want to update a status, you must have Admin priviledges and use PATCH /hacker/status/:id. - * @apiName patchHacker - * @apiGroup Hacker - * @apiVersion 0.0.8 - * - * @apiParam (body) {String} [school] Name of the school the hacker goes to - * @apiParam (body) {String} [gender] Gender of the hacker - * @apiParam (body) {Number} [travel] How much the hacker requires a bus for transportation - * @apiParam (body) {String[]} [ethnicity] the ethnicities of the hacker - * @apiParam (body) {String[]} [major] the major of the hacker - * @apiParam (body) {Number} [graduationYear] the graduation year of the hacker - * @apiParam (body) {Json} [application] The hacker's application - * @apiParamExample {Json} application: - * { - "application":{ - "general":{ - "school": "McGill University", - "degree": "Undergraduate", - "fieldOfStudy": "Computer Science", - "graduationYear": "2021", - "jobInterest":"Internship", - "URL":{ - "resume":"resumes/1543458163426-5bff4d736f86be0a41badb91", - "github":"https://github.com/abcd", - "dropler":"https://dribbble.com/abcd", - "personal":"https://www.hi.com/", - "linkedIn":"https://linkedin.com/in/abcd", - "other":"https://github.com/hackmcgill/hackerAPI/issues/168" - }, - }, - "shortAnswer": { - "skills":["Javascript","Typescript"], - "question1": "I love McHacks", - "question2":"Pls accept me", - "previousHackathons": "5", - "comments":"hi!", - }, - "other:" { - "gender": "male", - "ethnicity": "Asian or Pacific Islander", - "privacyPolicy": true, - "codeOfConduct": true, - } - "accommodation": { - "travel": 0 - }, - "location": { - "timeZone": "GMT-5", - "country": "Canada", - "city": "Montreal" - } - } - } - * - * @apiSuccess {string} message Success message - * @apiSuccess {object} data Hacker object - * @apiSuccessExample {object} Success-Response: - * { - * "message": "Changed hacker information", - * "data": { - "id":"5bff4d736f86be0a41badb91", - "status": "Applied", - "application":{ - "general":{ - "school": "McGill University", - "degree": "Undergraduate", - "fieldOfStudy": "Computer Science", - "graduationYear": "2021", - "jobInterest":"Internship", - "URL":{ - "resume":"resumes/1543458163426-5bff4d736f86be0a41badb91", - "github":"https://github.com/abcd", - "dropler":"https://dribbble.com/abcd", - "personal":"https://www.hi.com/", - "linkedIn":"https://linkedin.com/in/abcd", - "other":"https://github.com/hackmcgill/hackerAPI/issues/168" - }, - }, - "shortAnswer": { - "skills":["Javascript","Typescript"], - "question1": "I love McHacks", - "question2":"Pls accept me", - "previousHackathons": "5", - "comments":"hi!", - }, - "other:" { - "gender": "male", - "ethnicity": "Asian or Pacific Islander", - "privacyPolicy": true, - "codeOfConduct": true, - } - "accommodation": { - "travel": 0 - }, - "location": { - "timeZone": "GMT-5", - "country": "Canada", - "city": "Montreal" - } - } - } - * } - * @apiError {string} message Error message - * @apiError {object} data empty - * @apiErrorExample {object} Error-Response: - * {"message": "Error while updating hacker", "data": {}} - */ - hackerRouter.route("/:id").patch( - Middleware.Validator.RouteParam.idValidator, - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), - - Middleware.Validator.Hacker.updateHackerValidator, - - Middleware.parseBody.middleware, - Middleware.Hacker.parsePatch, - Middleware.Hacker.validateConfirmedStatusFromHackerId, - - Middleware.Hacker.updateHacker, - Middleware.Hacker.updateStatusIfApplicationCompleted, - Controllers.Hacker.updatedHacker - ); - - /** - * @api {get} /hacker/:id get a hacker's information - * @apiName getHacker - * @apiGroup Hacker - * @apiVersion 0.0.8 - * - * @apiParam (param) {String} id a hacker's unique mongoID - * - * @apiSuccess {String} message Success message - * @apiSuccess {Object} data Hacker object - * @apiSuccessExample {object} Success-Response: - * { - "message": "Successfully retrieved hacker information", - "data": { - "id":"5bff4d736f86be0a41badb91", - "status": "Applied", - "application":{ - "general":{ - "school": "McGill University", - "degree": "Undergraduate", - "fieldOfStudy": "Computer Science", - "graduationYear": "2021", - "jobInterest":"Internship", - "URL":{ - "resume":"resumes/1543458163426-5bff4d736f86be0a41badb91", - "github":"https://github.com/abcd", - "dropler":"https://dribbble.com/abcd", - "personal":"https://www.hi.com/", - "linkedIn":"https://linkedin.com/in/abcd", - "other":"https://github.com/hackmcgill/hackerAPI/issues/168" - }, - }, - "shortAnswer": { - "skills":["Javascript","Typescript"], - "question1": "I love McHacks", - "question2":"Pls accept me", - "previousHackathons": "5", - "comments":"hi!", - }, - "other:" { - "gender": "male", - "ethnicity": "Asian or Pacific Islander", - "privacyPolicy": true, - "codeOfConduct": true, - } - "accommodation": { - "travel": 0 - }, - "location": { - "timeZone": "GMT-5", - "country": "Canada", - "city": "Montreal" - } - } - } - } - - * @apiError {String} message Error message - * @apiError {Object} data empty - * @apiErrorExample {object} Error-Response: - * {"message": "Hacker not found", "data": {}} - */ - hackerRouter.route("/:id").get( - Middleware.Validator.RouteParam.idValidator, - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), - - Middleware.parseBody.middleware, - - Middleware.Hacker.findById, - Controllers.Hacker.showHacker - ); - - /** - * @api {get} /hacker/email/:email get a hacker's information - * @apiName getHacker - * @apiGroup Hacker - * @apiVersion 0.0.8 - * - * @apiParam (param) {String} email a hacker's unique email - * - * @apiSuccess {String} message Success message - * @apiSuccess {Object} data Hacker object - * @apiSuccessExample {object} Success-Response: - * { - "message": "Successfully retrieved hacker information", - "data": { - "id":"5bff4d736f86be0a41badb91", - "status": "Applied", - "application":{ - "general":{ - "school": "McGill University", - "degree": "Undergraduate", - "fieldOfStudy": "Computer Science", - "graduationYear": "2021", - "jobInterest":"Internship", - "URL":{ - "resume":"resumes/1543458163426-5bff4d736f86be0a41badb91", - "github":"https://github.com/abcd", - "dropler":"https://dribbble.com/abcd", - "personal":"https://www.hi.com/", - "linkedIn":"https://linkedin.com/in/abcd", - "other":"https://github.com/hackmcgill/hackerAPI/issues/168" - }, - }, - "shortAnswer": { - "skills":["Javascript","Typescript"], - "question1": "I love McHacks", - "question2":"Pls accept me", - "previousHackathons": "5", - "comments":"hi!", - }, - "other:" { - "gender": "male", - "ethnicity": "Asian or Pacific Islander", - "privacyPolicy": true, - "codeOfConduct": true, - } - "accommodation": { - "travel": 0 - }, - "location": { - "timeZone": "GMT-5", - "country": "Canada", - "city": "Montreal" - } - } - } - } - - * @apiError {String} message Error message - * @apiError {Object} data empty - * @apiErrorExample {object} Error-Response: - * {"message": "Hacker not found", "data": {}} - */ - hackerRouter.route("/email/:email").get( - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized([Services.Account.findByEmail]), - - Middleware.Validator.RouteParam.emailValidator, - Middleware.parseBody.middleware, - - Middleware.Hacker.findByEmail, - Controllers.Hacker.showHacker - ); - - hackerRouter - .route("/resume/:id") - /** - * @api {post} /hacker/resume/:id upload or update resume for a hacker. - * @apiName postHackerResume - * @apiGroup Hacker - * @apiVersion 0.0.8 - * @apiDescription NOTE: This must be sent via multipart/form-data POST request - * - * @apiParam (param) {ObjectId} id Hacker id - * @apiParam (body) {File} resume The uploaded file. - * - * @apiSuccess {String} message Success message - * @apiSuccess {Object} data Location in the bucket that the file was stored. - * @apiSuccessExample {json} Success-Response: - * HTTP/1.1 200 OK - * { - * message: "Uploaded resume", - * data: { - * filename: "resumes/1535032624768-507f191e810c19729de860ea" - * } - * } - * - * @apiPermission Must be logged in, and the account id must be linked to the hacker. - */ - .post( - //TODO: authenticate middleware - Middleware.Validator.Hacker.uploadResumeValidator, - Middleware.parseBody.middleware, - //verify that the hacker entity contains the account id - Middleware.Hacker.ensureAccountLinkedToHacker, - //load resume into memory - Middleware.Util.Multer.single("resume"), - //upload resume to storage and update hacker profile - Middleware.Hacker.uploadResume, - //controller response - Controllers.Hacker.uploadedResume - ) - /** - * @api {get} /hacker/resume:id get the resume for a hacker. - * @apiName getHackerResume - * @apiGroup Hacker - * @apiVersion 0.0.8 - * - * @apiParam (param) {ObjectId} id Hacker id - * - * @apiSuccess {String} message Success message - * @apiSuccessExample {json} Success-Response: - * HTTP/1.1 200 OK - * { - * message: "Downloaded resume", - * data: { - * id: "507f191e810c19729de860ea", - * resume: [Buffer] - * } - * } - * @apiError {String} message "Resume does not exist" - * @apiErrorExample {json} Error-Response: - * HTTP/1.1 404 - * { - * message: "Resume not found", - * data: {} - * } - * @apiSampleRequest off - * @apiPermission Must be logged in, and the account id must be linked to the hacker. - */ - .get( - //TODO: authenticate middleware - Middleware.Validator.Hacker.downloadResumeValidator, - Middleware.parseBody.middleware, - Middleware.Hacker.downloadResume, - Controllers.Hacker.downloadedResume - ); - - /** - * @api {patch} /hacker/confirmation/:id - * Allows confirmation of hacker attendence if they are accepted. Also allows change from 'confirmed' to 'withdrawn'. - * @apiName patchHackerConfirmed - * @apiGroup Hacker - * @apiVersion 0.0.9 - * - * @apiParam (body) {string} [status] The new status of the hacker. "Accepted", "Confirmed", or "Withdrawn" - * @apiSuccess {string} message Success message - * @apiSuccess {object} data Hacker object - * @apiSuccessExample {object} Success-Response: - * { - * "message": "Changed hacker information", - * "data": { - * "status": "Confirmed" - * } - * } - * @apiPermission Administrator - * @apiPermission Hacker - */ - hackerRouter.route("/confirmation/:id").patch( - Middleware.Validator.RouteParam.idValidator, - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), - - Middleware.Validator.Hacker.updateConfirmationValidator, - Middleware.parseBody.middleware, - Middleware.Hacker.parsePatch, - Middleware.Hacker.validateConfirmedStatusFromHackerId, - Middleware.Hacker.checkStatus([ - CONSTANTS.HACKER_STATUS_ACCEPTED, - CONSTANTS.HACKER_STATUS_CONFIRMED, - CONSTANTS.HACKER_STATUS_WITHDRAWN - ]), - - Middleware.Hacker.parseConfirmation, - Middleware.Hacker.updateHacker, - - Middleware.Hacker.sendStatusUpdateEmail, - Controllers.Hacker.updatedHacker - ); - - /** - * @api {post} /hacker/email/weekOf/:id - * @apiDescription Sends a hacker the week-of email, along with the HackPass QR code to view their hacker profile (for checkin purposes). Hackers must be either confirmed, or checked in. - * @apiName postHackerSendWeekOfEmail - * @apiGroup Hacker - * @apiVersion 0.0.9 - * - * @apiParam (param) {string} [status] The hacker ID - * @apiSuccess {string} message Success message - * @apiSuccess {object} data empty - * @apiSuccessExample {object} Success-Response: - * { - * "message": "Hacker week-of email sent.", - * "data": {} - * } - * @apiPermission Administrator - */ - hackerRouter.route("/email/weekOf/:id").post( - Middleware.Validator.RouteParam.idValidator, - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), - - Middleware.parseBody.middleware, - Middleware.Hacker.findById, - - Middleware.Hacker.validateConfirmedStatusFromHackerId, - Middleware.Hacker.checkStatus([ - CONSTANTS.HACKER_STATUS_CONFIRMED, - CONSTANTS.HACKER_STATUS_CHECKED_IN - ]), - - Middleware.Hacker.sendWeekOfEmail, - Controllers.Hacker.sentWeekOfEmail - ); - - /** - * @api {post} /hacker/email/dayOf/:id - * @apiDescription Sends a hacker the day-of email, along with the HackPass QR code to view their hacker profile (for checkin purposes). Hackers must be either confirmed, or checked in. - * @apiName postHackerSendDayOfEmail - * @apiGroup Hacker - * @apiVersion 0.0.9 - * - * @apiParam (param) {string} [status] The hacker ID - * @apiSuccess {string} message Success message - * @apiSuccess {object} data empty - * @apiSuccessExample {object} Success-Response: - * { - * "message": "Hacker day-of email sent.", - * "data": {} - * } - * @apiPermission Administrator - */ - hackerRouter.route("/email/dayOf/:id").post( - Middleware.Validator.RouteParam.idValidator, - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), - - Middleware.parseBody.middleware, - Middleware.Hacker.findById, - Middleware.Hacker.validateConfirmedStatusFromHackerId, - Middleware.Hacker.checkStatus([CONSTANTS.HACKER_STATUS_CHECKED_IN]), - Middleware.Hacker.sendDayOfEmail, - Controllers.Hacker.sentDayOfEmail - ); - - /** - * @api {post} /hacker/email/weekOf/:id - * @apiDescription Sends a hacker the week-of email, along with the HackPass QR code to view their hacker profile (for checkin purposes). Hackers must be eitherconfirmed, or checked in. - * @apiName postHackerSendWeekOfEmail - * @apiGroup Hacker - * @apiVersion 0.0.9 - * - * @apiParam (param) {string} [status] The hacker ID - * @apiSuccess {string} message Success message - * @apiSuccess {object} data empty - * @apiSuccessExample {object} Success-Response: - * { - * "message": "Hacker week-of email sent.", - * "data": {} - * } - * @apiPermission Administrator - */ - hackerRouter.route("/email/dayOf/:id").post( - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), - - Middleware.Validator.RouteParam.idValidator, - Middleware.parseBody.middleware, - Middleware.Hacker.findById, - Middleware.Hacker.checkStatus([CONSTANTS.HACKER_STATUS_CHECKED_IN]), - Middleware.Hacker.sendDayOfEmail, - Controllers.Hacker.sentDayOfEmail - ); - - apiRouter.use("/hacker", hackerRouter); - } -}; diff --git a/routes/api/search.js b/routes/api/search.js deleted file mode 100644 index 45d53f67..00000000 --- a/routes/api/search.js +++ /dev/null @@ -1,74 +0,0 @@ -"use strict"; - -const express = require("express"); - -const Controllers = { - Search: require("../../controllers/search.controller") -}; - -const Middleware = { - Validator: { - Search: require("../../middlewares/validators/search.validator") - }, - parseBody: require("../../middlewares/parse-body.middleware"), - Search: require("../../middlewares/search.middleware"), - Auth: require("../../middlewares/auth.middleware") -}; - -module.exports = { - activate: function(apiRouter) { - const searchRouter = new express.Router(); - - /** - * @api {get} /search/ provide a specific query for any defined model - * @apiName search - * @apiGroup Search - * @apiVersion 0.0.8 - * - * @apiParam (query) {String} model the model to be searched - * @apiParam (query) {Array} q the query to be executed. For more information on how to format this, please see https://docs.mchacks.ca/architecture/ - * @apiParam (query) {String} model the model to be searched - * @apiParam (query) {String} sort either "asc" or "desc" - * @apiParam (query) {number} page the page number that you would like - * @apiParam (query) {number} limit the maximum number of results that you would like returned - * @apiParam (query) {any} sort_by any parameter you want to sort the results by - * @apiParam (query) {boolean} expand whether you want to expand sub documents within the results - * - * @apiSuccess {String} message Success message - * @apiSuccess {Object} data Results - * @apiSuccessExample {object} Success-Response: - * { - "message": "Successfully executed query, returning all results", - "data": [ - {...} - ] - } - * - * @apiSuccess {String} message Success message - * @apiSuccess {Object} data Empty object - * @apiSuccessExample {object} Success-Response: - * { - "message": "No results found.", - "data": {} - } - * - * @apiError {String} message Error message - * @apiError {Object} data empty - * @apiErrorExample {object} Error-Response: - * {"message": "Validation failed", "data": {}} - */ - searchRouter - .route("/") - .get( - Middleware.Auth.ensureAuthenticated(), - Middleware.Auth.ensureAuthorized(), - Middleware.Validator.Search.searchQueryValidator, - Middleware.parseBody.middleware, - Middleware.Search.parseQuery, - Middleware.Search.executeQuery, - Controllers.Search.searchResults - ); - - apiRouter.use("/search", searchRouter); - } -}; diff --git a/scripts/batch_update_travel.js b/scripts/batch_update_travel.js deleted file mode 100644 index 4d69ba1c..00000000 --- a/scripts/batch_update_travel.js +++ /dev/null @@ -1,10 +0,0 @@ -// use hackboard-dev; // Change to product for actual update - -// Create a travel document for every hacker document -db.hackers.find().forEach(hacker => { - let request = 0; - if (hacker.application && hacker.application.accommodation && hacker.application.accommodation.travel) { - request = hacker.application.accommodation.travel; - } - db.travels.insert({ hackerId: hacker._id, accountId: hacker.accountId, request: request, offer: 0, status: "None" }) -}); From f0fdfa8dffd73f60236c943fd007a5176f81aa0c Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Sun, 26 Dec 2021 18:10:30 -0500 Subject: [PATCH 25/72] feat: add ability to update application fields using hacker service. --- services/hacker.service.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/services/hacker.service.ts b/services/hacker.service.ts index 885dd10d..871db7f6 100644 --- a/services/hacker.service.ts +++ b/services/hacker.service.ts @@ -35,6 +35,23 @@ export class HackerService { return await this.hackerRepository.update(identifier, hacker); } + public async updateApplicationField( + identifier: number, + key: string, + value: any + ): Promise { + return await this.hackerRepository + .createQueryBuilder() + .update() + .set({ + application: () => `jsonb_set(application,${key},${value})` + }) + .where("accountIdentifier = :identifier", { + identifier: identifier + }) + .execute(); + } + public async generateQRCode(data: string) { return await toDataURL(data, { scale: 4 From b52b33600b55bf9dd70a22d960ed37562f3b814b Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Sun, 26 Dec 2021 18:14:30 -0500 Subject: [PATCH 26/72] fix: avoid tsyringe attempting di on search service constructor, and load relation when finding by account on account confirmation. --- services/account-confirmation.service.ts | 1 + services/search.service.ts | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/services/account-confirmation.service.ts b/services/account-confirmation.service.ts index ba5bc6c1..d98ee8ce 100644 --- a/services/account-confirmation.service.ts +++ b/services/account-confirmation.service.ts @@ -28,6 +28,7 @@ export class AccountConfirmationService { identifier: number ): Promise { return await this.accountConfirmationRepository.findOne({ + relations: ["account"], where: { account: { identifier: identifier } } }); } diff --git a/services/search.service.ts b/services/search.service.ts index 2ecce2b3..4cdbe9e5 100644 --- a/services/search.service.ts +++ b/services/search.service.ts @@ -3,7 +3,10 @@ import { Connection, getConnection } from "typeorm"; @singleton() export class SearchService { - constructor(private readonly connection: Connection = getConnection()) {} + private readonly connection: Connection; + constructor() { + this.connection = getConnection(); + } public executeQuery( model: any, From 141427497015fc75e425acee9a26a18809314152 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Sun, 26 Dec 2021 18:16:04 -0500 Subject: [PATCH 27/72] feat: change settings js file to ts, start migration to enums for constants. --- constants/general.constant.ts | 260 +++++++++++++++------------------ constants/settings.constant.ts | 39 +++++ 2 files changed, 156 insertions(+), 143 deletions(-) create mode 100644 constants/settings.constant.ts diff --git a/constants/general.constant.ts b/constants/general.constant.ts index 76a4c628..74f4d8cd 100644 --- a/constants/general.constant.ts +++ b/constants/general.constant.ts @@ -2,11 +2,9 @@ const HACKATHON_NAME = "McHacks"; // constants kept in alphabetical order // matches optional http://, https://, http:, https:, and optional www., and then matches for devpost.com and further parameters -const DEVPOST_REGEX = - /^(http(s)?:(\/\/)?)?(www\.)?(([-a-zA-Z0-9@:%._\+~#=]{2,256}\.)?devpost\.com)\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/; +const DEVPOST_REGEX = /^(http(s)?:(\/\/)?)?(www\.)?(([-a-zA-Z0-9@:%._\+~#=]{2,256}\.)?devpost\.com)\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/; // from https://emailregex.com -const EMAIL_REGEX = - /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; +const EMAIL_REGEX = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; const HACKER_STATUS_NONE = "None"; const HACKER_STATUS_APPLIED = "Applied"; const HACKER_STATUS_ACCEPTED = "Accepted"; @@ -16,14 +14,14 @@ const HACKER_STATUS_CONFIRMED = "Confirmed"; const HACKER_STATUS_WITHDRAWN = "Withdrawn"; const HACKER_STATUS_CHECKED_IN = "Checked-in"; const HACKER_STATUSES = [ - HACKER_STATUS_NONE, - HACKER_STATUS_APPLIED, - HACKER_STATUS_ACCEPTED, - HACKER_STATUS_WAITLISTED, - HACKER_STATUS_CONFIRMED, - HACKER_STATUS_WITHDRAWN, - HACKER_STATUS_CHECKED_IN, - HACKER_STATUS_DECLINED, + HACKER_STATUS_NONE, + HACKER_STATUS_APPLIED, + HACKER_STATUS_ACCEPTED, + HACKER_STATUS_WAITLISTED, + HACKER_STATUS_CONFIRMED, + HACKER_STATUS_WITHDRAWN, + HACKER_STATUS_CHECKED_IN, + HACKER_STATUS_DECLINED ]; // This date is Jan 6, 2020 00:00:00 GMT -0500 const APPLICATION_CLOSE_TIME = 1578286800000; @@ -31,42 +29,35 @@ const APPLICATION_CLOSE_TIME = 1578286800000; const CONFIRMATION_TYPE_INVITE = "Invite"; const CONFIRMATION_TYPE_ORGANIC = "Organic"; const CONFIRMATION_TYPES = [ - CONFIRMATION_TYPE_INVITE, - CONFIRMATION_TYPE_ORGANIC, + CONFIRMATION_TYPE_INVITE, + CONFIRMATION_TYPE_ORGANIC ]; -const TRAVEL_STATUS_NONE = "None"; // Hacker has not been offered compensation for travelling -const TRAVEL_STATUS_BUS = "Bus"; // Hacker is taking bus to hackathon -const TRAVEL_STATUS_POLICY = "Policy"; // Hacker has been offer some reimbursement, but we are waiting for hacker to accept travel policy first -const TRAVEL_STATUS_OFFERED = "Offered"; // Hacker has been offered some amount of compensation for travelling, but we have not verified their reciepts yet -const TRAVEL_STATUS_VALID = "Valid"; // Hacker has been offered some amount of compensation for travelling and have uploaded reciepts which we have confirmed to be an approprate amount -const TRAVEL_STATUS_INVALID = "Invalid"; // Hacker has been offered some amount of compensation for travelling but have uploaded reciepts which we have confirmed to be an inapproprate amount -const TRAVEL_STATUS_CLAIMED = "Claimed"; // Hacker has been offered some amount of compensation and has recieved such the funds -const TRAVEL_STATUSES = [ - TRAVEL_STATUS_NONE, - TRAVEL_STATUS_BUS, - TRAVEL_STATUS_POLICY, - TRAVEL_STATUS_OFFERED, - TRAVEL_STATUS_VALID, - TRAVEL_STATUS_INVALID, - TRAVEL_STATUS_CLAIMED, -]; +export enum TravelStatus { + None = "None", // Hacker has not been offered compensation for travelling + Bus = "Bus", // Hacker is taking bus to hackathon + Policy = "Policy", // Hacker has been offer some reimbursement, but we are waiting for hacker to accept travel policy first + Offered = "Offered", // Hacker has been offered some amount of compensation for travelling, but we have not verified their reciepts yet + Valid = "Valid", // Hacker has been offered some amount of compensation for travelling and have uploaded reciepts which we have confirmed to be an approprate amount + Invalid = "Invalid", // Hacker has been offered some amount of compensation for travelling but have uploaded reciepts which we have confirmed to be an inapproprate amount + Claimed = "Claimed" // Hacker has been offered some amount of compensation and has recieved such the funds +} const SAMPLE_DIET_RESTRICTIONS = [ - "None", - "Vegan", - "Vegetarian", - "Keto", - "Gluten free", - "Pescetarian", - "Peanut allergy", - "Milk allergy", - "Egg allergy", - "Allergy", - "No beef", - "No porc", - "No fish", - "No shellfish", + "None", + "Vegan", + "Vegetarian", + "Keto", + "Gluten free", + "Pescetarian", + "Peanut allergy", + "Milk allergy", + "Egg allergy", + "Allergy", + "No beef", + "No porc", + "No fish", + "No shellfish" ]; const HACKER = "Hacker"; @@ -80,60 +71,54 @@ const SPONSOR_T3 = "SponsorT3"; const SPONSOR_T4 = "SponsorT4"; const SPONSOR_T5 = "SponsorT5"; +enum JobInterest { + Internship = "Internship", + FullTime = "Full Time", + None = "None" +} + +enum ShirtSize { + XS = "XS", + S = "S", + M = "M", + L = "L", + XL = "XL", + XXL = "XXL" +} + +enum AttendancePreference { + Remote = "Remote", + InPerson = "In Person" +} + // Enums (must match with frontend) const JOB_INTERESTS = ["Internship", "Full Time", "None"]; const SHIRT_SIZES = ["XS", "S", "M", "L", "XL", "XXL"]; const PREVIOUS_HACKATHONS = [0, 1, 2, 3, 4, 5]; const ATTENDANCE_PREFERENCES = ["Remote", "In Person"]; -const ROLE_CATEGORIES = { - SELF: ":self", - ALL: ":all", -}; -// enum of type of requests -const REQUEST_TYPES = { - GET: "GET", - POST: "POST", - PATCH: "PATCH", - DELETE: "DELETE", - PUT: "PUT", -}; - -//Define names of the roles specifically associated with permission to create an account -const POST_ROLES = { - Hacker: "postHacker", - SponsorT1: "postSponsor", - SponsorT2: "postSponsor", - SponsorT3: "postSponsor", - SponsorT4: "postSponsor", - SponsorT5: "postSponsor", - Volunteer: "postSponsor", - Staff: "postSponsor", -}; - const USER_TYPES = [HACKER, VOLUNTEER, STAFF, SPONSOR]; const SPONSOR_TIERS = [ - SPONSOR_T1, - SPONSOR_T2, - SPONSOR_T3, - SPONSOR_T4, - SPONSOR_T5, + SPONSOR_T1, + SPONSOR_T2, + SPONSOR_T3, + SPONSOR_T4, + SPONSOR_T5 ]; const EXTENDED_USER_TYPES = [ - HACKER, - VOLUNTEER, - STAFF, - SPONSOR_T1, - SPONSOR_T2, - SPONSOR_T3, - SPONSOR_T4, - SPONSOR_T5, + HACKER, + VOLUNTEER, + STAFF, + SPONSOR_T1, + SPONSOR_T2, + SPONSOR_T3, + SPONSOR_T4, + SPONSOR_T5 ]; // matches optional http://, https://, http:, https:, and optional www. // matches the domain, and then optional route, path, query parameters -const URL_REGEX = - /^(http(s)?:(\/\/)?)?(www\.)?([-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6})\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/; +const URL_REGEX = /^(http(s)?:(\/\/)?)?(www\.)?([-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6})\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/; const ANY_REGEX = /^.+$/; const MAX_TEAM_SIZE = 4; @@ -143,13 +128,13 @@ const WEEK_OF = "Week Of"; const EMAIL_SUBJECTS: any = {}; EMAIL_SUBJECTS[HACKER_STATUS_NONE] = `Get started on your application!`; EMAIL_SUBJECTS[ - HACKER_STATUS_APPLIED + HACKER_STATUS_APPLIED ] = `Thanks for applying to ${HACKATHON_NAME}!`; EMAIL_SUBJECTS[HACKER_STATUS_ACCEPTED] = `Great update from ${HACKATHON_NAME}`; EMAIL_SUBJECTS[HACKER_STATUS_DECLINED] = `Update from ${HACKATHON_NAME}`; EMAIL_SUBJECTS[HACKER_STATUS_WAITLISTED] = `Update from ${HACKATHON_NAME}`; EMAIL_SUBJECTS[ - HACKER_STATUS_CONFIRMED + HACKER_STATUS_CONFIRMED ] = `Thanks for confirming your attendance to ${HACKATHON_NAME}`; EMAIL_SUBJECTS[HACKER_STATUS_WITHDRAWN] = "Sorry to see you go"; EMAIL_SUBJECTS[HACKER_STATUS_CHECKED_IN] = `Welcome to ${HACKATHON_NAME}`; @@ -159,73 +144,62 @@ EMAIL_SUBJECTS[WEEK_OF] = `Welcome to ${HACKATHON_NAME}`; const CONFIRM_ACC_EMAIL_SUBJECT = `Confirm your ${HACKATHON_NAME} Account`; const CREATE_ACC_EMAIL_SUBJECTS: any = {}; CREATE_ACC_EMAIL_SUBJECTS[ - HACKER + HACKER ] = `You've been invited to create a hacker account for ${HACKATHON_NAME}`; CREATE_ACC_EMAIL_SUBJECTS[ - SPONSOR + SPONSOR ] = `You've been invited to create a sponsor account for ${HACKATHON_NAME}`; CREATE_ACC_EMAIL_SUBJECTS[ - VOLUNTEER + VOLUNTEER ] = `You've been invited to create a volunteer account for ${HACKATHON_NAME}`; CREATE_ACC_EMAIL_SUBJECTS[ - STAFF + STAFF ] = `You've been invited to create a staff account for ${HACKATHON_NAME}`; const CACHE_TIMEOUT_STATS = 5 * 60 * 1000; const CACHE_KEY_STATS = "hackerStats"; export { - HACKATHON_NAME, - DEVPOST_REGEX, - EMAIL_REGEX, - ANY_REGEX, - HACKER_STATUS_NONE, - HACKER_STATUS_APPLIED, - HACKER_STATUS_ACCEPTED, - HACKER_STATUS_DECLINED, - HACKER_STATUS_WAITLISTED, - HACKER_STATUS_CONFIRMED, - HACKER_STATUS_WITHDRAWN, - HACKER_STATUS_CHECKED_IN, - HACKER_STATUSES, - TRAVEL_STATUS_NONE, - TRAVEL_STATUS_BUS, - TRAVEL_STATUS_POLICY, - TRAVEL_STATUS_OFFERED, - TRAVEL_STATUS_VALID, - TRAVEL_STATUS_INVALID, - TRAVEL_STATUS_CLAIMED, - TRAVEL_STATUSES, - APPLICATION_CLOSE_TIME, - REQUEST_TYPES, - JOB_INTERESTS, - SHIRT_SIZES, - PREVIOUS_HACKATHONS, - ATTENDANCE_PREFERENCES, - USER_TYPES, - SPONSOR_TIERS, - EXTENDED_USER_TYPES, - URL_REGEX, - EMAIL_SUBJECTS, - CREATE_ACC_EMAIL_SUBJECTS, - CONFIRM_ACC_EMAIL_SUBJECT, - HACKER, - SPONSOR, - VOLUNTEER, - STAFF, - SPONSOR_T1, - SPONSOR_T2, - SPONSOR_T3, - SPONSOR_T4, - SPONSOR_T5, - ROLE_CATEGORIES, - POST_ROLES, - CACHE_TIMEOUT_STATS, - CACHE_KEY_STATS, - MAX_TEAM_SIZE, - WEEK_OF, - SAMPLE_DIET_RESTRICTIONS, - CONFIRMATION_TYPES, - CONFIRMATION_TYPE_INVITE, - CONFIRMATION_TYPE_ORGANIC, + HACKATHON_NAME, + DEVPOST_REGEX, + EMAIL_REGEX, + ANY_REGEX, + HACKER_STATUS_NONE, + HACKER_STATUS_APPLIED, + HACKER_STATUS_ACCEPTED, + HACKER_STATUS_DECLINED, + HACKER_STATUS_WAITLISTED, + HACKER_STATUS_CONFIRMED, + HACKER_STATUS_WITHDRAWN, + HACKER_STATUS_CHECKED_IN, + HACKER_STATUSES, + APPLICATION_CLOSE_TIME, + JOB_INTERESTS, + SHIRT_SIZES, + PREVIOUS_HACKATHONS, + ATTENDANCE_PREFERENCES, + USER_TYPES, + SPONSOR_TIERS, + EXTENDED_USER_TYPES, + URL_REGEX, + EMAIL_SUBJECTS, + CREATE_ACC_EMAIL_SUBJECTS, + CONFIRM_ACC_EMAIL_SUBJECT, + HACKER, + SPONSOR, + VOLUNTEER, + STAFF, + SPONSOR_T1, + SPONSOR_T2, + SPONSOR_T3, + SPONSOR_T4, + SPONSOR_T5, + CACHE_TIMEOUT_STATS, + CACHE_KEY_STATS, + MAX_TEAM_SIZE, + WEEK_OF, + SAMPLE_DIET_RESTRICTIONS, + CONFIRMATION_TYPES, + CONFIRMATION_TYPE_INVITE, + CONFIRMATION_TYPE_ORGANIC }; diff --git a/constants/settings.constant.ts b/constants/settings.constant.ts new file mode 100644 index 00000000..ee0df49b --- /dev/null +++ b/constants/settings.constant.ts @@ -0,0 +1,39 @@ +const APP_NOT_YET_OPEN = { + openTime: new Date(Date.now() + 100000000000), + closeTime: new Date(Date.now() + 10000000000000000), + confirmTime: new Date(Date.now() + 100000000000000000) +}; + +const APP_OPEN = { + openTime: new Date(Date.now() - 100), + closeTime: new Date(Date.now() + 10000000000), + confirmTime: new Date(Date.now() + 100000000000000) +}; + +const APP_CLOSED = { + openTime: new Date(Date.now() - 100), + closeTime: new Date(Date.now() - 1000), + confirmTime: new Date(Date.now() + 100000000000000) +}; + +const CONFIRM_CLOSED = { + openTime: new Date(Date.now() - 10000), + closeTime: new Date(Date.now() - 1000), + confirmTime: new Date(Date.now() - 100) +}; + +const REMOTE_HACKATHON = { + openTime: new Date(Date.now() - 100), + closeTime: new Date(Date.now() + 10000000000), + confirmTime: new Date(Date.now() + 100000000000000), + isRemote: true +}; + +// Some utility dates that are used in tests and seed script +module.exports = { + APP_NOT_YET_OPEN: APP_NOT_YET_OPEN, + APP_OPEN: APP_OPEN, + APP_CLOSED: APP_CLOSED, + CONFIRM_CLOSED: CONFIRM_CLOSED, + REMOTE_HACKATHON: REMOTE_HACKATHON +}; From e27eedca28592fb829746f175a90dd189ef2baf0 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Sun, 26 Dec 2021 19:13:47 -0500 Subject: [PATCH 28/72] refactor: create and move relevant files to 'src' folder to help with codebase organization. --- app.ts => src/app.ts | 0 .../assets}/email/AccountConfirmation.mjml | 0 {assets => src/assets}/email/Footer.mjml | 0 {assets => src/assets}/email/HackingPolicy.mjml | 0 {assets => src/assets}/email/Header.mjml | 0 {assets => src/assets}/email/ResetPassword.mjml | 0 {assets => src/assets}/email/SocialMedia.mjml | 0 {assets => src/assets}/email/Ticket.mjml | 0 {assets => src/assets}/email/Welcome.mjml | 0 .../assets}/email/marketingEmail/3Days.mjml | 0 .../assets}/email/marketingEmail/EmailBlast.mjml | 0 .../assets}/email/statusEmail/Accepted.mjml | 0 .../assets}/email/statusEmail/Applied.mjml | 0 .../assets}/email/statusEmail/Checked-In.mjml | 0 .../assets}/email/statusEmail/Confirmed.mjml | 0 .../assets}/email/statusEmail/Declined.mjml | 0 {assets => src/assets}/email/statusEmail/None.mjml | 0 .../assets}/email/statusEmail/Waitlisted.mjml | 0 .../assets}/email/statusEmail/Withdrawn.mjml | 0 {assets => src/assets}/email/test.mjml | 0 .../constants}/authorization-level.constant.ts | 0 {constants => src/constants}/error.constant.ts | 0 {constants => src/constants}/general.constant.ts | 0 {constants => src/constants}/settings.constant.ts | 0 {constants => src/constants}/success.constant.ts | 0 .../controllers}/account.controller.ts | 0 .../controllers}/authentication.controller.ts | 0 .../controllers}/hacker.controller.ts | 0 .../controllers}/search.controller.ts | 0 .../controllers}/sponsor.controller.ts | 0 {controllers => src/controllers}/team.controller.ts | 0 .../controllers}/travel.controller.ts | 0 .../middlewares}/authenticated.middleware.ts | 0 .../middlewares}/authorization.middleware.ts | 0 .../middlewares}/multer.middleware.ts | 0 {models => src/models}/account.model.ts | 0 .../models}/accountConfirmationToken.model.ts | 0 {models => src/models}/application.model.ts | 0 {models => src/models}/bus.model.ts | 0 {models => src/models}/hacker.model.ts | 0 {models => src/models}/passwordResetToken.model.ts | 0 {models => src/models}/sponsor.model.ts | 0 {models => src/models}/team.model.ts | 0 {models => src/models}/travel.model.ts | 0 .../services}/account-confirmation.service.ts | 0 {services => src/services}/account.service.ts | 0 {services => src/services}/database.service.ts | 0 {services => src/services}/email.service.ts | 0 {services => src/services}/env.service.ts | 0 {services => src/services}/hacker.service.ts | 0 {services => src/services}/logger.service.ts | 0 .../services}/password-reset.service.ts | 0 {services => src/services}/search.service.ts | 0 {services => src/services}/sponsor.service.ts | 0 {services => src/services}/storage.service.ts | 0 {services => src/services}/team.service.ts | 0 {services => src/services}/travel.service.ts | 0 .../strategy}/emailAndPassword.strategy.ts | 0 {tests => src/tests}/account.test.js | 0 {tests => src/tests}/auth.service.spec.js | 0 {tests => src/tests}/auth.test.js | 0 {tests => src/tests}/email.service.spec.js | 0 {tests => src/tests}/hacker.test.js | 0 {tests => src/tests}/role.test.js | 0 {tests => src/tests}/search.service.spec.js | 0 {tests => src/tests}/settings.test.js | 0 {tests => src/tests}/setup.spec.js | 0 {tests => src/tests}/sponsor.test.js | 0 {tests => src/tests}/storage.spec.js | 0 {tests => src/tests}/team.test.js | 0 {tests => src/tests}/testResume.pdf | Bin {tests => src/tests}/util/account.test.util.js | 0 .../tests}/util/accountConfirmation.test.util.js | 0 {tests => src/tests}/util/auth.test.util.js | 0 {tests => src/tests}/util/bus.test.util.js | 0 {tests => src/tests}/util/hacker.test.util.js | 0 .../tests}/util/resetPassword.test.util.js | 0 {tests => src/tests}/util/role.test.util.js | 0 {tests => src/tests}/util/roleBinding.test.util.js | 0 {tests => src/tests}/util/settings.test.util.js | 0 {tests => src/tests}/util/sponsor.test.util.js | 0 {tests => src/tests}/util/staff.test.util.js | 0 {tests => src/tests}/util/team.test.util.js | 0 {tests => src/tests}/util/volunteer.test.util.js | 0 {tests => src/tests}/volunteer.test.js | 0 tsconfig.json | 4 ++-- 86 files changed, 2 insertions(+), 2 deletions(-) rename app.ts => src/app.ts (100%) rename {assets => src/assets}/email/AccountConfirmation.mjml (100%) rename {assets => src/assets}/email/Footer.mjml (100%) rename {assets => src/assets}/email/HackingPolicy.mjml (100%) rename {assets => src/assets}/email/Header.mjml (100%) rename {assets => src/assets}/email/ResetPassword.mjml (100%) rename {assets => src/assets}/email/SocialMedia.mjml (100%) rename {assets => src/assets}/email/Ticket.mjml (100%) rename {assets => src/assets}/email/Welcome.mjml (100%) rename {assets => src/assets}/email/marketingEmail/3Days.mjml (100%) rename {assets => src/assets}/email/marketingEmail/EmailBlast.mjml (100%) rename {assets => src/assets}/email/statusEmail/Accepted.mjml (100%) rename {assets => src/assets}/email/statusEmail/Applied.mjml (100%) rename {assets => src/assets}/email/statusEmail/Checked-In.mjml (100%) rename {assets => src/assets}/email/statusEmail/Confirmed.mjml (100%) rename {assets => src/assets}/email/statusEmail/Declined.mjml (100%) rename {assets => src/assets}/email/statusEmail/None.mjml (100%) rename {assets => src/assets}/email/statusEmail/Waitlisted.mjml (100%) rename {assets => src/assets}/email/statusEmail/Withdrawn.mjml (100%) rename {assets => src/assets}/email/test.mjml (100%) rename {constants => src/constants}/authorization-level.constant.ts (100%) rename {constants => src/constants}/error.constant.ts (100%) rename {constants => src/constants}/general.constant.ts (100%) rename {constants => src/constants}/settings.constant.ts (100%) rename {constants => src/constants}/success.constant.ts (100%) rename {controllers => src/controllers}/account.controller.ts (100%) rename {controllers => src/controllers}/authentication.controller.ts (100%) rename {controllers => src/controllers}/hacker.controller.ts (100%) rename {controllers => src/controllers}/search.controller.ts (100%) rename {controllers => src/controllers}/sponsor.controller.ts (100%) rename {controllers => src/controllers}/team.controller.ts (100%) rename {controllers => src/controllers}/travel.controller.ts (100%) rename {middlewares => src/middlewares}/authenticated.middleware.ts (100%) rename {middlewares => src/middlewares}/authorization.middleware.ts (100%) rename {middlewares => src/middlewares}/multer.middleware.ts (100%) rename {models => src/models}/account.model.ts (100%) rename {models => src/models}/accountConfirmationToken.model.ts (100%) rename {models => src/models}/application.model.ts (100%) rename {models => src/models}/bus.model.ts (100%) rename {models => src/models}/hacker.model.ts (100%) rename {models => src/models}/passwordResetToken.model.ts (100%) rename {models => src/models}/sponsor.model.ts (100%) rename {models => src/models}/team.model.ts (100%) rename {models => src/models}/travel.model.ts (100%) rename {services => src/services}/account-confirmation.service.ts (100%) rename {services => src/services}/account.service.ts (100%) rename {services => src/services}/database.service.ts (100%) rename {services => src/services}/email.service.ts (100%) rename {services => src/services}/env.service.ts (100%) rename {services => src/services}/hacker.service.ts (100%) rename {services => src/services}/logger.service.ts (100%) rename {services => src/services}/password-reset.service.ts (100%) rename {services => src/services}/search.service.ts (100%) rename {services => src/services}/sponsor.service.ts (100%) rename {services => src/services}/storage.service.ts (100%) rename {services => src/services}/team.service.ts (100%) rename {services => src/services}/travel.service.ts (100%) rename {strategy => src/strategy}/emailAndPassword.strategy.ts (100%) rename {tests => src/tests}/account.test.js (100%) rename {tests => src/tests}/auth.service.spec.js (100%) rename {tests => src/tests}/auth.test.js (100%) rename {tests => src/tests}/email.service.spec.js (100%) rename {tests => src/tests}/hacker.test.js (100%) rename {tests => src/tests}/role.test.js (100%) rename {tests => src/tests}/search.service.spec.js (100%) rename {tests => src/tests}/settings.test.js (100%) rename {tests => src/tests}/setup.spec.js (100%) rename {tests => src/tests}/sponsor.test.js (100%) rename {tests => src/tests}/storage.spec.js (100%) rename {tests => src/tests}/team.test.js (100%) rename {tests => src/tests}/testResume.pdf (100%) rename {tests => src/tests}/util/account.test.util.js (100%) rename {tests => src/tests}/util/accountConfirmation.test.util.js (100%) rename {tests => src/tests}/util/auth.test.util.js (100%) rename {tests => src/tests}/util/bus.test.util.js (100%) rename {tests => src/tests}/util/hacker.test.util.js (100%) rename {tests => src/tests}/util/resetPassword.test.util.js (100%) rename {tests => src/tests}/util/role.test.util.js (100%) rename {tests => src/tests}/util/roleBinding.test.util.js (100%) rename {tests => src/tests}/util/settings.test.util.js (100%) rename {tests => src/tests}/util/sponsor.test.util.js (100%) rename {tests => src/tests}/util/staff.test.util.js (100%) rename {tests => src/tests}/util/team.test.util.js (100%) rename {tests => src/tests}/util/volunteer.test.util.js (100%) rename {tests => src/tests}/volunteer.test.js (100%) diff --git a/app.ts b/src/app.ts similarity index 100% rename from app.ts rename to src/app.ts diff --git a/assets/email/AccountConfirmation.mjml b/src/assets/email/AccountConfirmation.mjml similarity index 100% rename from assets/email/AccountConfirmation.mjml rename to src/assets/email/AccountConfirmation.mjml diff --git a/assets/email/Footer.mjml b/src/assets/email/Footer.mjml similarity index 100% rename from assets/email/Footer.mjml rename to src/assets/email/Footer.mjml diff --git a/assets/email/HackingPolicy.mjml b/src/assets/email/HackingPolicy.mjml similarity index 100% rename from assets/email/HackingPolicy.mjml rename to src/assets/email/HackingPolicy.mjml diff --git a/assets/email/Header.mjml b/src/assets/email/Header.mjml similarity index 100% rename from assets/email/Header.mjml rename to src/assets/email/Header.mjml diff --git a/assets/email/ResetPassword.mjml b/src/assets/email/ResetPassword.mjml similarity index 100% rename from assets/email/ResetPassword.mjml rename to src/assets/email/ResetPassword.mjml diff --git a/assets/email/SocialMedia.mjml b/src/assets/email/SocialMedia.mjml similarity index 100% rename from assets/email/SocialMedia.mjml rename to src/assets/email/SocialMedia.mjml diff --git a/assets/email/Ticket.mjml b/src/assets/email/Ticket.mjml similarity index 100% rename from assets/email/Ticket.mjml rename to src/assets/email/Ticket.mjml diff --git a/assets/email/Welcome.mjml b/src/assets/email/Welcome.mjml similarity index 100% rename from assets/email/Welcome.mjml rename to src/assets/email/Welcome.mjml diff --git a/assets/email/marketingEmail/3Days.mjml b/src/assets/email/marketingEmail/3Days.mjml similarity index 100% rename from assets/email/marketingEmail/3Days.mjml rename to src/assets/email/marketingEmail/3Days.mjml diff --git a/assets/email/marketingEmail/EmailBlast.mjml b/src/assets/email/marketingEmail/EmailBlast.mjml similarity index 100% rename from assets/email/marketingEmail/EmailBlast.mjml rename to src/assets/email/marketingEmail/EmailBlast.mjml diff --git a/assets/email/statusEmail/Accepted.mjml b/src/assets/email/statusEmail/Accepted.mjml similarity index 100% rename from assets/email/statusEmail/Accepted.mjml rename to src/assets/email/statusEmail/Accepted.mjml diff --git a/assets/email/statusEmail/Applied.mjml b/src/assets/email/statusEmail/Applied.mjml similarity index 100% rename from assets/email/statusEmail/Applied.mjml rename to src/assets/email/statusEmail/Applied.mjml diff --git a/assets/email/statusEmail/Checked-In.mjml b/src/assets/email/statusEmail/Checked-In.mjml similarity index 100% rename from assets/email/statusEmail/Checked-In.mjml rename to src/assets/email/statusEmail/Checked-In.mjml diff --git a/assets/email/statusEmail/Confirmed.mjml b/src/assets/email/statusEmail/Confirmed.mjml similarity index 100% rename from assets/email/statusEmail/Confirmed.mjml rename to src/assets/email/statusEmail/Confirmed.mjml diff --git a/assets/email/statusEmail/Declined.mjml b/src/assets/email/statusEmail/Declined.mjml similarity index 100% rename from assets/email/statusEmail/Declined.mjml rename to src/assets/email/statusEmail/Declined.mjml diff --git a/assets/email/statusEmail/None.mjml b/src/assets/email/statusEmail/None.mjml similarity index 100% rename from assets/email/statusEmail/None.mjml rename to src/assets/email/statusEmail/None.mjml diff --git a/assets/email/statusEmail/Waitlisted.mjml b/src/assets/email/statusEmail/Waitlisted.mjml similarity index 100% rename from assets/email/statusEmail/Waitlisted.mjml rename to src/assets/email/statusEmail/Waitlisted.mjml diff --git a/assets/email/statusEmail/Withdrawn.mjml b/src/assets/email/statusEmail/Withdrawn.mjml similarity index 100% rename from assets/email/statusEmail/Withdrawn.mjml rename to src/assets/email/statusEmail/Withdrawn.mjml diff --git a/assets/email/test.mjml b/src/assets/email/test.mjml similarity index 100% rename from assets/email/test.mjml rename to src/assets/email/test.mjml diff --git a/constants/authorization-level.constant.ts b/src/constants/authorization-level.constant.ts similarity index 100% rename from constants/authorization-level.constant.ts rename to src/constants/authorization-level.constant.ts diff --git a/constants/error.constant.ts b/src/constants/error.constant.ts similarity index 100% rename from constants/error.constant.ts rename to src/constants/error.constant.ts diff --git a/constants/general.constant.ts b/src/constants/general.constant.ts similarity index 100% rename from constants/general.constant.ts rename to src/constants/general.constant.ts diff --git a/constants/settings.constant.ts b/src/constants/settings.constant.ts similarity index 100% rename from constants/settings.constant.ts rename to src/constants/settings.constant.ts diff --git a/constants/success.constant.ts b/src/constants/success.constant.ts similarity index 100% rename from constants/success.constant.ts rename to src/constants/success.constant.ts diff --git a/controllers/account.controller.ts b/src/controllers/account.controller.ts similarity index 100% rename from controllers/account.controller.ts rename to src/controllers/account.controller.ts diff --git a/controllers/authentication.controller.ts b/src/controllers/authentication.controller.ts similarity index 100% rename from controllers/authentication.controller.ts rename to src/controllers/authentication.controller.ts diff --git a/controllers/hacker.controller.ts b/src/controllers/hacker.controller.ts similarity index 100% rename from controllers/hacker.controller.ts rename to src/controllers/hacker.controller.ts diff --git a/controllers/search.controller.ts b/src/controllers/search.controller.ts similarity index 100% rename from controllers/search.controller.ts rename to src/controllers/search.controller.ts diff --git a/controllers/sponsor.controller.ts b/src/controllers/sponsor.controller.ts similarity index 100% rename from controllers/sponsor.controller.ts rename to src/controllers/sponsor.controller.ts diff --git a/controllers/team.controller.ts b/src/controllers/team.controller.ts similarity index 100% rename from controllers/team.controller.ts rename to src/controllers/team.controller.ts diff --git a/controllers/travel.controller.ts b/src/controllers/travel.controller.ts similarity index 100% rename from controllers/travel.controller.ts rename to src/controllers/travel.controller.ts diff --git a/middlewares/authenticated.middleware.ts b/src/middlewares/authenticated.middleware.ts similarity index 100% rename from middlewares/authenticated.middleware.ts rename to src/middlewares/authenticated.middleware.ts diff --git a/middlewares/authorization.middleware.ts b/src/middlewares/authorization.middleware.ts similarity index 100% rename from middlewares/authorization.middleware.ts rename to src/middlewares/authorization.middleware.ts diff --git a/middlewares/multer.middleware.ts b/src/middlewares/multer.middleware.ts similarity index 100% rename from middlewares/multer.middleware.ts rename to src/middlewares/multer.middleware.ts diff --git a/models/account.model.ts b/src/models/account.model.ts similarity index 100% rename from models/account.model.ts rename to src/models/account.model.ts diff --git a/models/accountConfirmationToken.model.ts b/src/models/accountConfirmationToken.model.ts similarity index 100% rename from models/accountConfirmationToken.model.ts rename to src/models/accountConfirmationToken.model.ts diff --git a/models/application.model.ts b/src/models/application.model.ts similarity index 100% rename from models/application.model.ts rename to src/models/application.model.ts diff --git a/models/bus.model.ts b/src/models/bus.model.ts similarity index 100% rename from models/bus.model.ts rename to src/models/bus.model.ts diff --git a/models/hacker.model.ts b/src/models/hacker.model.ts similarity index 100% rename from models/hacker.model.ts rename to src/models/hacker.model.ts diff --git a/models/passwordResetToken.model.ts b/src/models/passwordResetToken.model.ts similarity index 100% rename from models/passwordResetToken.model.ts rename to src/models/passwordResetToken.model.ts diff --git a/models/sponsor.model.ts b/src/models/sponsor.model.ts similarity index 100% rename from models/sponsor.model.ts rename to src/models/sponsor.model.ts diff --git a/models/team.model.ts b/src/models/team.model.ts similarity index 100% rename from models/team.model.ts rename to src/models/team.model.ts diff --git a/models/travel.model.ts b/src/models/travel.model.ts similarity index 100% rename from models/travel.model.ts rename to src/models/travel.model.ts diff --git a/services/account-confirmation.service.ts b/src/services/account-confirmation.service.ts similarity index 100% rename from services/account-confirmation.service.ts rename to src/services/account-confirmation.service.ts diff --git a/services/account.service.ts b/src/services/account.service.ts similarity index 100% rename from services/account.service.ts rename to src/services/account.service.ts diff --git a/services/database.service.ts b/src/services/database.service.ts similarity index 100% rename from services/database.service.ts rename to src/services/database.service.ts diff --git a/services/email.service.ts b/src/services/email.service.ts similarity index 100% rename from services/email.service.ts rename to src/services/email.service.ts diff --git a/services/env.service.ts b/src/services/env.service.ts similarity index 100% rename from services/env.service.ts rename to src/services/env.service.ts diff --git a/services/hacker.service.ts b/src/services/hacker.service.ts similarity index 100% rename from services/hacker.service.ts rename to src/services/hacker.service.ts diff --git a/services/logger.service.ts b/src/services/logger.service.ts similarity index 100% rename from services/logger.service.ts rename to src/services/logger.service.ts diff --git a/services/password-reset.service.ts b/src/services/password-reset.service.ts similarity index 100% rename from services/password-reset.service.ts rename to src/services/password-reset.service.ts diff --git a/services/search.service.ts b/src/services/search.service.ts similarity index 100% rename from services/search.service.ts rename to src/services/search.service.ts diff --git a/services/sponsor.service.ts b/src/services/sponsor.service.ts similarity index 100% rename from services/sponsor.service.ts rename to src/services/sponsor.service.ts diff --git a/services/storage.service.ts b/src/services/storage.service.ts similarity index 100% rename from services/storage.service.ts rename to src/services/storage.service.ts diff --git a/services/team.service.ts b/src/services/team.service.ts similarity index 100% rename from services/team.service.ts rename to src/services/team.service.ts diff --git a/services/travel.service.ts b/src/services/travel.service.ts similarity index 100% rename from services/travel.service.ts rename to src/services/travel.service.ts diff --git a/strategy/emailAndPassword.strategy.ts b/src/strategy/emailAndPassword.strategy.ts similarity index 100% rename from strategy/emailAndPassword.strategy.ts rename to src/strategy/emailAndPassword.strategy.ts diff --git a/tests/account.test.js b/src/tests/account.test.js similarity index 100% rename from tests/account.test.js rename to src/tests/account.test.js diff --git a/tests/auth.service.spec.js b/src/tests/auth.service.spec.js similarity index 100% rename from tests/auth.service.spec.js rename to src/tests/auth.service.spec.js diff --git a/tests/auth.test.js b/src/tests/auth.test.js similarity index 100% rename from tests/auth.test.js rename to src/tests/auth.test.js diff --git a/tests/email.service.spec.js b/src/tests/email.service.spec.js similarity index 100% rename from tests/email.service.spec.js rename to src/tests/email.service.spec.js diff --git a/tests/hacker.test.js b/src/tests/hacker.test.js similarity index 100% rename from tests/hacker.test.js rename to src/tests/hacker.test.js diff --git a/tests/role.test.js b/src/tests/role.test.js similarity index 100% rename from tests/role.test.js rename to src/tests/role.test.js diff --git a/tests/search.service.spec.js b/src/tests/search.service.spec.js similarity index 100% rename from tests/search.service.spec.js rename to src/tests/search.service.spec.js diff --git a/tests/settings.test.js b/src/tests/settings.test.js similarity index 100% rename from tests/settings.test.js rename to src/tests/settings.test.js diff --git a/tests/setup.spec.js b/src/tests/setup.spec.js similarity index 100% rename from tests/setup.spec.js rename to src/tests/setup.spec.js diff --git a/tests/sponsor.test.js b/src/tests/sponsor.test.js similarity index 100% rename from tests/sponsor.test.js rename to src/tests/sponsor.test.js diff --git a/tests/storage.spec.js b/src/tests/storage.spec.js similarity index 100% rename from tests/storage.spec.js rename to src/tests/storage.spec.js diff --git a/tests/team.test.js b/src/tests/team.test.js similarity index 100% rename from tests/team.test.js rename to src/tests/team.test.js diff --git a/tests/testResume.pdf b/src/tests/testResume.pdf similarity index 100% rename from tests/testResume.pdf rename to src/tests/testResume.pdf diff --git a/tests/util/account.test.util.js b/src/tests/util/account.test.util.js similarity index 100% rename from tests/util/account.test.util.js rename to src/tests/util/account.test.util.js diff --git a/tests/util/accountConfirmation.test.util.js b/src/tests/util/accountConfirmation.test.util.js similarity index 100% rename from tests/util/accountConfirmation.test.util.js rename to src/tests/util/accountConfirmation.test.util.js diff --git a/tests/util/auth.test.util.js b/src/tests/util/auth.test.util.js similarity index 100% rename from tests/util/auth.test.util.js rename to src/tests/util/auth.test.util.js diff --git a/tests/util/bus.test.util.js b/src/tests/util/bus.test.util.js similarity index 100% rename from tests/util/bus.test.util.js rename to src/tests/util/bus.test.util.js diff --git a/tests/util/hacker.test.util.js b/src/tests/util/hacker.test.util.js similarity index 100% rename from tests/util/hacker.test.util.js rename to src/tests/util/hacker.test.util.js diff --git a/tests/util/resetPassword.test.util.js b/src/tests/util/resetPassword.test.util.js similarity index 100% rename from tests/util/resetPassword.test.util.js rename to src/tests/util/resetPassword.test.util.js diff --git a/tests/util/role.test.util.js b/src/tests/util/role.test.util.js similarity index 100% rename from tests/util/role.test.util.js rename to src/tests/util/role.test.util.js diff --git a/tests/util/roleBinding.test.util.js b/src/tests/util/roleBinding.test.util.js similarity index 100% rename from tests/util/roleBinding.test.util.js rename to src/tests/util/roleBinding.test.util.js diff --git a/tests/util/settings.test.util.js b/src/tests/util/settings.test.util.js similarity index 100% rename from tests/util/settings.test.util.js rename to src/tests/util/settings.test.util.js diff --git a/tests/util/sponsor.test.util.js b/src/tests/util/sponsor.test.util.js similarity index 100% rename from tests/util/sponsor.test.util.js rename to src/tests/util/sponsor.test.util.js diff --git a/tests/util/staff.test.util.js b/src/tests/util/staff.test.util.js similarity index 100% rename from tests/util/staff.test.util.js rename to src/tests/util/staff.test.util.js diff --git a/tests/util/team.test.util.js b/src/tests/util/team.test.util.js similarity index 100% rename from tests/util/team.test.util.js rename to src/tests/util/team.test.util.js diff --git a/tests/util/volunteer.test.util.js b/src/tests/util/volunteer.test.util.js similarity index 100% rename from tests/util/volunteer.test.util.js rename to src/tests/util/volunteer.test.util.js diff --git a/tests/volunteer.test.js b/src/tests/volunteer.test.js similarity index 100% rename from tests/volunteer.test.js rename to src/tests/volunteer.test.js diff --git a/tsconfig.json b/tsconfig.json index 9bba37af..ba9ed9ad 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,6 +17,6 @@ "resolveJsonModule": true, "emitDecoratorMetadata": true }, - "include": ["./**/*", ".env"], - "exclude": ["node_modules", "**/*.spec.ts", ".vscode", ".github", ".idea", "docs", "scripts", "tests"] + "include": ["./src/**/*", "./.env"], + "exclude": ["node_modules", "**/*.spec.ts", ".vscode", ".github", "docs", "scripts", "./src/tests"] } From 8e59ea4cf6c081445a8bd0c1dbc9ed6a8fe42b1a Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Sun, 26 Dec 2021 19:35:05 -0500 Subject: [PATCH 29/72] refactor: update dependencies, and remove unneeded ones, transpile to ES6 and fix small directory bug for .env file. --- package-lock.json | 2817 ++++++++++++++--------------------- package.json | 20 +- src/services/env.service.ts | 2 +- tsconfig.json | 4 +- 4 files changed, 1109 insertions(+), 1734 deletions(-) diff --git a/package-lock.json b/package-lock.json index c930b3ef..91a0c0e9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,22 +7,19 @@ "": { "name": "hackerAPI", "version": "3.1.3", + "license": "MIT", "dependencies": { "@decorators/di": "^1.0.3", "@decorators/express": "^2.6.0", "@google-cloud/storage": "^5.10.0", - "@sendgrid/mail": "^7.4.5", "bcrypt": "^5.0.1", "class-transformer": "^0.5.1", "class-validator": "^0.13.2", "cookie-parser": "^1.4.5", "cookie-session": "^2.0.0-rc.1", "cors": "^2.8.5", - "cryptiles": "^4.1.3", - "debug": "~4.3.2", "dotenv": "^10.0.0", "express": "~4.17.1", - "express-validator": "^6.12.0", "express-winston": "^4.2.0", "handlebars": "^4.7.7", "jsonwebtoken": "^8.5.1", @@ -34,10 +31,9 @@ "passport": "^0.4.1", "passport-local": "^1.0.0", "pg": "^8.7.1", - "promise.allsettled": "^1.0.4", - "q": "^1.5.1", "qrcode": "^1.4.4", "reflect-metadata": "^0.1.13", + "ts-node-dev": "^1.1.8", "tsyringe": "^4.6.0", "typeorm": "^0.2.41", "typescript": "^4.5.2", @@ -50,8 +46,6 @@ "@types/google-cloud__storage": "^1.7.2", "@types/jsonwebtoken": "^8.5.6", "@types/mjml": "^4.7.0", - "@types/mongodb": "^3.6.20", - "@types/mongoose": "^5.11.97", "@types/multer": "^1.4.7", "@types/nodemailer": "^6.4.4", "@types/passport": "^1.0.7", @@ -66,9 +60,7 @@ "eslint-config-prettier": "8.3.0", "eslint-plugin-prettier": "3.4.0", "mocha": "^9.0.3", - "nodemon": "^2.0.12", - "prettier": "1.19.1", - "rimraf": "^3.0.2" + "prettier": "1.19.1" } }, "node_modules/@babel/code-frame": { @@ -238,6 +230,29 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "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/@google-cloud/common": { "version": "3.8.1", "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-3.8.1.tgz", @@ -286,9 +301,9 @@ } }, "node_modules/@google-cloud/storage": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-5.16.0.tgz", - "integrity": "sha512-I/1lA78v9c5EbOM/KfcYsjzA7YlHQmhpzHYdKLKdYC8X5fFaQrw5nK+FU8GbEwdPxmREAF2qPbN7Ccq+A/ndWA==", + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-5.16.1.tgz", + "integrity": "sha512-C2li/2PUfLSGEetebLL70uQRwqm6PS+kBtFEjr5AnAn/Qv0UnD8V+rI9Y4RmwxWFvhlPAgg+ZRqa4bkK4eUxlA==", "dependencies": { "@google-cloud/common": "^3.8.1", "@google-cloud/paginator": "^3.0.0", @@ -299,7 +314,7 @@ "date-and-time": "^2.0.0", "duplexify": "^4.0.0", "extend": "^3.0.2", - "gcs-resumable-upload": "^3.5.1", + "gcs-resumable-upload": "^3.6.0", "get-stream": "^6.0.0", "hash-stream-validation": "^0.2.2", "mime": "^3.0.0", @@ -328,6 +343,29 @@ "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/config-array/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "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/object-schema": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", @@ -335,16 +373,16 @@ "dev": true }, "node_modules/@mapbox/node-pre-gyp": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.7.tgz", - "integrity": "sha512-PplSvl4pJ5N3BkVjAdDzpPhVUPdC73JgttkR+LnBx2OORC1GCQsBjUeEuipf9uOaAM1SbxcdZFfR3KDTKm2S0A==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.8.tgz", + "integrity": "sha512-CMGKi28CF+qlbXh26hDe6NxCd7amqeAzEqnS6IHeO6LoaKyM/n+Xw3HT1COdq8cuioOdlKdqn/hCmqPUOMOywg==", "dependencies": { "detect-libc": "^1.0.3", "https-proxy-agent": "^5.0.0", "make-dir": "^3.1.0", "node-fetch": "^2.6.5", "nopt": "^5.0.0", - "npmlog": "^6.0.0", + "npmlog": "^5.0.1", "rimraf": "^3.0.2", "semver": "^7.3.5", "tar": "^6.1.11" @@ -353,41 +391,6 @@ "node-pre-gyp": "bin/node-pre-gyp" } }, - "node_modules/@sendgrid/client": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@sendgrid/client/-/client-7.6.0.tgz", - "integrity": "sha512-cpBVZKLlMTO+vpE18krTixubYmZa98oTbLkqBDuTiA3zRkW+urrxg7pDR24TkI35Mid0Zru8jDHwnOiqrXu0TA==", - "dependencies": { - "@sendgrid/helpers": "^7.6.0", - "axios": "^0.21.4" - }, - "engines": { - "node": "6.* || 8.* || >=10.*" - } - }, - "node_modules/@sendgrid/helpers": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@sendgrid/helpers/-/helpers-7.6.0.tgz", - "integrity": "sha512-0uWD+HSXLl4Z/X3cN+UMQC20RE7xwAACgppnfjDyvKG0KvJcUgDGz7HDdQkiMUdcVWfmyk6zKSg7XKfKzBjTwA==", - "dependencies": { - "deepmerge": "^4.2.2" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/@sendgrid/mail": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@sendgrid/mail/-/mail-7.6.0.tgz", - "integrity": "sha512-0KdaSZzflJD/vUAZjB3ALBIuaVGoLq22hrb2fvQXZHRepU/yhRNlEOqrr05MfKBnKskzq1blnD1J0fHxiwaolw==", - "dependencies": { - "@sendgrid/client": "^7.6.0", - "@sendgrid/helpers": "^7.6.0" - }, - "engines": { - "node": "6.* || 8.* || >=10.*" - } - }, "node_modules/@sindresorhus/is": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", @@ -442,12 +445,11 @@ } }, "node_modules/@types/bson": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.2.0.tgz", - "integrity": "sha512-ELCPqAdroMdcuxqwMgUpifQyRoTpyYCNr1V9xKyF40VsBobsj+BbWNRvwGchMgBPGqkw655ypkjj2MEF5ywVwg==", - "deprecated": "This is a stub types definition. bson provides its own type definitions, so you do not need this installed.", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.5.tgz", + "integrity": "sha512-vVLwMUqhYJSQ/WKcE60eFqcyuWse5fGH+NMAXHuKrUAPoryq3ATxk5o4bgYNtg5aOM4APVg7Hnb3ASqUYG0PKg==", "dependencies": { - "bson": "*" + "@types/node": "*" } }, "node_modules/@types/caseless": { @@ -457,9 +459,9 @@ "dev": true }, "node_modules/@types/chai": { - "version": "4.2.22", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.22.tgz", - "integrity": "sha512-tFfcE+DSTzWAgifkjik9AySNqIyNoYwmR+uecPwwD/XRNfvOjmC/FjCxpiUGDkDVDphPfCUecSQVFw+lN3M3kQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.0.tgz", + "integrity": "sha512-/ceqdqeRraGolFTcfoXNiqjyQhZzbINDngeoAq9GoHa8PPK1yNzTaxWjA6BFWp5Ua9JpXEMSS4s5i9tS0hOJtw==", "dev": true }, "node_modules/@types/connect": { @@ -490,9 +492,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.25", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.25.tgz", - "integrity": "sha512-OUJIVfRMFijZukGGwTpKNFprqCCXk5WjNGvUgB/CxxBR40QWSjsNK86+yvGKlCOGc7sbwfHLaXhkG+NsytwBaQ==", + "version": "4.17.27", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.27.tgz", + "integrity": "sha512-e/sVallzUTPdyOTiqi8O8pMdBBphscvI6E4JYaKlja4Lm+zh7UFSSdW5VMkRbhDtmrONqOUHOXRguPsDckzxNA==", "dev": true, "dependencies": { "@types/node": "*", @@ -559,16 +561,6 @@ "@types/node": "*" } }, - "node_modules/@types/mongoose": { - "version": "5.11.97", - "resolved": "https://registry.npmjs.org/@types/mongoose/-/mongoose-5.11.97.tgz", - "integrity": "sha512-cqwOVYT3qXyLiGw7ueU2kX9noE8DPGRY6z8eUxudhXY8NZ7DMKYAxyZkLSevGfhCX3dO/AoX5/SO9lAzfjon0Q==", - "deprecated": "Mongoose publishes its own types, so you do not need to install this package.", - "dev": true, - "dependencies": { - "mongoose": "*" - } - }, "node_modules/@types/multer": { "version": "1.4.7", "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.7.tgz", @@ -579,9 +571,9 @@ } }, "node_modules/@types/node": { - "version": "16.11.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.10.tgz", - "integrity": "sha512-3aRnHa1KlOEEhJ6+CvyHKK5vE9BcLGjtUpwvqYLRvYNQKMfabu3BwfJaA/SLW8dxe28LsNDjtHwePTuzn3gmOA==" + "version": "17.0.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.5.tgz", + "integrity": "sha512-w3mrvNXLeDYV1GKTZorGJQivK6XLCoGwpnyJFbJVK/aTBQUxOCaa/GlFAAN3OTDFcb7h5tiFG+YXCO2By+riZw==" }, "node_modules/@types/nodemailer": { "version": "6.4.4", @@ -665,6 +657,16 @@ "@types/node": "*" } }, + "node_modules/@types/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I=" + }, + "node_modules/@types/strip-json-comments": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", + "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==" + }, "node_modules/@types/superagent": { "version": "4.1.13", "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-4.1.13.tgz", @@ -682,9 +684,9 @@ "dev": true }, "node_modules/@types/validator": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.0.tgz", - "integrity": "sha512-+jBxVvXVuggZOrm04NR8z+5+bgoW4VZyLzUO+hmPPW1mVFL/HaitLAkizfv4yg9TbG8lkfHWVMQ11yDqrVVCzA==", + "version": "13.7.1", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.1.tgz", + "integrity": "sha512-I6OUIZ5cYRk5lp14xSOAiXjWrfVoMZVjDuevBYgQDYzZIjsf2CAISpEcXOkFAtpAHbmWIDLcZObejqny/9xq5Q==", "dev": true }, "node_modules/@types/zen-observable": { @@ -758,6 +760,27 @@ "node": ">= 6.0.0" } }, + "node_modules/agent-base/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/agent-base/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/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -899,6 +922,11 @@ "node": ">=10" } }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + }, "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -913,24 +941,6 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, - "node_modules/array.prototype.map": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.4.tgz", - "integrity": "sha512-Qds9QnX7A0qISY7JT5WuJO0NJPE9CMlC6JzHQfhpqAAQQzufVRoeH7EzUY5GcPTx72voG8LV/5eo+b8Qi8hmhA==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "es-array-method-boxes-properly": "^1.0.0", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/arrify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", @@ -985,14 +995,6 @@ "node": ">= 4.0.0" } }, - "node_modules/axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "dependencies": { - "follow-redirects": "^1.14.0" - } - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1031,9 +1033,9 @@ } }, "node_modules/bignumber.js": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", - "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", + "integrity": "sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw==", "engines": { "node": "*" } @@ -1055,11 +1057,6 @@ "safe-buffer": "^5.1.1" } }, - "node_modules/bl/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, "node_modules/bl/node_modules/readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -1093,20 +1090,20 @@ "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" }, "node_modules/body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.1.tgz", + "integrity": "sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA==", "dependencies": { - "bytes": "3.1.0", + "bytes": "3.1.1", "content-type": "~1.0.4", "debug": "2.6.9", "depd": "~1.1.2", - "http-errors": "1.7.2", + "http-errors": "1.8.1", "iconv-lite": "0.4.24", "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" + "qs": "6.9.6", + "raw-body": "2.4.2", + "type-is": "~1.6.18" }, "engines": { "node": ">= 0.8" @@ -1145,11 +1142,14 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "node_modules/body-parser/node_modules/qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==", "engines": { "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/boolbase": { @@ -1157,15 +1157,6 @@ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" }, - "node_modules/boom": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-7.3.0.tgz", - "integrity": "sha512-Swpoyi2t5+GhOEGw8rEsKvTxFLIDiiKoUc2gsoV6Lyr43LHBIzch3k2MvYUs8RTROrIkVJ3Al0TkaOGjnb+B6A==", - "deprecated": "This module has moved and is now available at @hapi/boom. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues.", - "dependencies": { - "hoek": "6.x.x" - } - }, "node_modules/boxen": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", @@ -1215,20 +1206,17 @@ "dev": true }, "node_modules/bson": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.0.tgz", - "integrity": "sha512-8jw1NU1hglS+Da1jDOUYuNcBJ4cNHCFIqzlwoFNnsTOg2R/ox0aTYcTiBN4dzRa9q7Cvy6XErh3L8ReTEb9AQQ==", - "dependencies": { - "buffer": "^5.6.0" - }, + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", + "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==", "engines": { - "node": ">=6.9.0" + "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==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "funding": [ { "type": "github", @@ -1245,7 +1233,7 @@ ], "dependencies": { "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "ieee754": "^1.2.1" } }, "node_modules/buffer-equal-constant-time": { @@ -1300,9 +1288,9 @@ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" }, "node_modules/bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz", + "integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==", "engines": { "node": ">= 0.8" } @@ -1353,6 +1341,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, "dependencies": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -1495,11 +1484,6 @@ "url": "https://github.com/sponsors/fb55" } }, - "node_modules/cheerio/node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" - }, "node_modules/chokidar": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", @@ -1591,6 +1575,11 @@ "npm": ">=5.0.0" } }, + "node_modules/cli-highlight/node_modules/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" + }, "node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -1636,9 +1625,9 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/color-string": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.7.4.tgz", - "integrity": "sha512-nVdUvPVgZMpRQad5dcsCMOSB5BXLljklTiaxS6ehhKxDsAI5sD7k5VmFuBt1y3Rlym8uulc/ANUN/bMWtBu6Sg==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz", + "integrity": "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==", "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" @@ -1665,6 +1654,14 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "engines": { + "node": ">=0.1.90" + } + }, "node_modules/colorspace": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", @@ -1727,11 +1724,6 @@ "typedarray": "^0.0.6" } }, - "node_modules/concat-stream/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, "node_modules/concat-stream/node_modules/readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -1768,11 +1760,6 @@ "proto-list": "~1.2.1" } }, - "node_modules/config-chain/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, "node_modules/configstore": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", @@ -1795,21 +1782,16 @@ "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, "node_modules/content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "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.1.2" + "safe-buffer": "5.2.1" }, "engines": { "node": ">= 0.6" } }, - "node_modules/content-disposition/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/content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", @@ -1839,28 +1821,19 @@ } }, "node_modules/cookie-session": { - "version": "2.0.0-rc.1", - "resolved": "https://registry.npmjs.org/cookie-session/-/cookie-session-2.0.0-rc.1.tgz", - "integrity": "sha512-zg80EsLe7S1J4y0XxV7SZ8Fbi90ZZoampuX2bfYDOvJfc//98sSlZC41YDzTTjtVbeU1VlVdBbldXOOyi5xzEw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cookie-session/-/cookie-session-2.0.0.tgz", + "integrity": "sha512-hKvgoThbw00zQOleSlUr2qpvuNweoqBtxrmx0UFosx6AGi9lYtLoA+RbsvknrEX8Pr6MDbdWAb2j6SnMn+lPsg==", "dependencies": { "cookies": "0.8.0", - "debug": "3.2.6", + "debug": "3.2.7", "on-headers": "~1.0.2", - "safe-buffer": "5.2.0" + "safe-buffer": "5.2.1" }, "engines": { "node": ">= 0.10" } }, - "node_modules/cookie-session/node_modules/debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", - "dependencies": { - "ms": "^2.1.1" - } - }, "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", @@ -1901,6 +1874,11 @@ "node": ">= 0.10" } }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -1915,15 +1893,6 @@ "node": ">= 8" } }, - "node_modules/cryptiles": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-4.1.3.tgz", - "integrity": "sha512-gT9nyTMSUC1JnziQpPbxKGBbUg8VL7Zn2NB4E1cJYvuXdElHrwxrV9bmltZGDzet45zSDGyYceueke1TjynGzw==", - "deprecated": "This module has moved and is now available at @hapi/cryptiles. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues.", - "dependencies": { - "boom": "7.x.x" - } - }, "node_modules/crypto-random-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", @@ -1933,9 +1902,9 @@ } }, "node_modules/css-select": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.0.tgz", - "integrity": "sha512-6YVG6hsH9yIb/si3Th/is8Pex7qnVHO6t7q7U6TIUnkQASGbS8tnUDBftnPynLNnuUl/r2+PTd0ekiiq7R0zJw==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", + "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", "dependencies": { "boolbase": "^1.0.0", "css-what": "^5.1.0", @@ -1964,19 +1933,11 @@ "integrity": "sha512-O7Xe5dLaqvY/aF/MFWArsAM1J4j7w1CSZlPCX9uHgmb+6SbkPd8Q4YOvfvH/cZGvFlJFfHOZKxQtmMUOoZhc/w==" }, "node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "ms": "^2.1.1" } }, "node_modules/decamelize": { @@ -2030,31 +1991,12 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/defer-to-connect": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", "dev": true }, - "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dependencies": { - "object-keys": "^1.0.12" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -2252,6 +2194,14 @@ "stream-shift": "^1.0.0" } }, + "node_modules/dynamic-dedupe": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", + "integrity": "sha1-BuRMIj9eTpTXjvnbI6ZRXOL5YqE=", + "dependencies": { + "xtend": "^4.0.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", @@ -2354,78 +2304,6 @@ "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==" }, - "node_modules/es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", - "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-array-method-boxes-properly": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", - "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" - }, - "node_modules/es-get-iterator": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", - "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.0", - "has-symbols": "^1.0.1", - "is-arguments": "^1.1.0", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.5", - "isarray": "^2.0.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -2596,22 +2474,45 @@ "node": ">=10" } }, - "node_modules/espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "node_modules/eslint/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", "dev": true, "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" + "ms": "2.1.2" }, "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "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/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "1.3.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true, @@ -2709,16 +2610,16 @@ } }, "node_modules/express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.2.tgz", + "integrity": "sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg==", "dependencies": { "accepts": "~1.3.7", "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", + "body-parser": "1.19.1", + "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.0", + "cookie": "0.4.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "~1.1.2", @@ -2732,13 +2633,13 @@ "on-finished": "~2.3.0", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", + "proxy-addr": "~2.0.7", + "qs": "6.9.6", "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", "statuses": "~1.5.0", "type-is": "~1.6.18", "utils-merge": "1.0.1", @@ -2748,18 +2649,6 @@ "node": ">= 0.10.0" } }, - "node_modules/express-validator": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-6.13.0.tgz", - "integrity": "sha512-gvLqMFPwEm+C1CQlF3l695ubY1Shd3AtfI5JDYXM0Ju0A2GsGX+VjjQN7TcHXF6cO8wPgU8hSSFqWecBR0Gx1g==", - "dependencies": { - "lodash": "^4.17.21", - "validator": "^13.6.0" - }, - "engines": { - "node": ">= 8.0.0" - } - }, "node_modules/express-winston": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/express-winston/-/express-winston-4.2.0.tgz", @@ -2839,14 +2728,6 @@ "node": ">=4" } }, - "node_modules/express/node_modules/cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/express/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -2869,18 +2750,16 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "node_modules/express/node_modules/qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==", "engines": { "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/express/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/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -3022,25 +2901,6 @@ "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, - "node_modules/follow-redirects": { - "version": "1.14.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz", - "integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, "node_modules/form-data": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", @@ -3137,22 +2997,22 @@ "dev": true }, "node_modules/gauge": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.0.tgz", - "integrity": "sha512-F8sU45yQpjQjxKkm1UOAhf0U/O0aFt//Fl7hsrNVto+patMHjs7dPI9mFOGUKbhrgKm0S3EjW3scMFuQmWSROw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", "dependencies": { - "ansi-regex": "^5.0.1", "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.2", "console-control-strings": "^1.0.0", "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", "signal-exit": "^3.0.0", "string-width": "^4.2.3", "strip-ansi": "^6.0.1", "wide-align": "^1.1.2" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": ">=10" } }, "node_modules/gaxios": { @@ -3224,6 +3084,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dev": true, "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -3244,21 +3105,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -3304,6 +3150,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/global-dirs/node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/globals": { "version": "13.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", @@ -3320,9 +3175,9 @@ } }, "node_modules/google-auth-library": { - "version": "7.10.2", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.10.2.tgz", - "integrity": "sha512-M37o9Kxa/TLvOLgF71SXvLeVEP5sbSTmKl1zlIgl72SFy5PtsU3pOdu8G8MIHHpQ3/NZabDI8rQkA9DvQVKkPA==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.11.0.tgz", + "integrity": "sha512-3S5jn2quRumvh9F/Ubf7GFrIq71HZ5a6vqosgdIu105kkk0WtSqc2jGCRqtWWOLRS8SX3AHACMOEDxhyWAQIcg==", "dependencies": { "arrify": "^2.0.0", "base64-js": "^1.3.0", @@ -3444,14 +3299,6 @@ "node": ">= 0.4.0" } }, - "node_modules/has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -3464,20 +3311,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dependencies": { - "has-symbols": "^1.0.2" - }, + "dev": true, "engines": { "node": ">= 0.4" }, @@ -3520,12 +3354,6 @@ "node": "*" } }, - "node_modules/hoek": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz", - "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==", - "deprecated": "This module has moved and is now available at @hapi/hoek. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues." - }, "node_modules/html-minifier": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-4.0.0.tgz", @@ -3571,15 +3399,15 @@ "dev": true }, "node_modules/http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "dependencies": { "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "toidentifier": "1.0.1" }, "engines": { "node": ">= 0.6" @@ -3593,11 +3421,6 @@ "node": ">= 0.6" } }, - "node_modules/http-errors/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, "node_modules/http-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", @@ -3611,6 +3434,27 @@ "node": ">= 6" } }, + "node_modules/http-proxy-agent/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/http-proxy-agent/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/https-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", @@ -3623,6 +3467,27 @@ "node": ">= 6" } }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/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/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -3717,26 +3582,9 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, "node_modules/ip-regex": { "version": "2.1.0", @@ -3755,37 +3603,11 @@ "node": ">= 0.10" } }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-arrayish": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -3797,32 +3619,6 @@ "node": ">=8" } }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-ci": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", @@ -3835,15 +3631,12 @@ "is-ci": "bin.js" } }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "node_modules/is-core-module": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", + "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" + "has": "^1.0.3" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3904,25 +3697,6 @@ "node": ">=4" } }, - "node_modules/is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-npm": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", @@ -3943,20 +3717,6 @@ "node": ">=0.12.0" } }, - "node_modules/is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-obj": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", @@ -3983,37 +3743,6 @@ "node": ">=8" } }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -4025,34 +3754,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -4070,17 +3771,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-weakref": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", - "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", - "dependencies": { - "call-bind": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-yarn-global": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", @@ -4088,9 +3778,9 @@ "dev": true }, "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "node_modules/isexe": { "version": "2.0.0", @@ -4098,26 +3788,6 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "node_modules/iterate-iterator": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.2.tgz", - "integrity": "sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/iterate-value": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz", - "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==", - "dependencies": { - "es-get-iterator": "^1.0.2", - "iterate-iterator": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/js-beautify": { "version": "1.14.0", "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.0.tgz", @@ -4352,9 +4022,9 @@ } }, "node_modules/libphonenumber-js": { - "version": "1.9.43", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.43.tgz", - "integrity": "sha512-tNB87ZutAiAkl3DE/Bo0Mxqn/XZbNxhPg4v9bYBwQQW4dlhBGqXl1vtmPxeDWbrijzwOA9vRjOOFm5V9SK/W3w==" + "version": "1.9.44", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.44.tgz", + "integrity": "sha512-zhw8nUMJuQf7jG1dZfEOKKOS6M3QYIv3HnvB/vGohNd0QfxIQcObH3a6Y6s350H+9xgBeOXClOJkS0hJ0yvS3g==" }, "node_modules/linkify-it": { "version": "3.0.3", @@ -4460,14 +4130,6 @@ "triple-beam": "^1.3.0" } }, - "node_modules/logform/node_modules/colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "engines": { - "node": ">=0.1.90" - } - }, "node_modules/lower-case": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", @@ -4515,6 +4177,11 @@ "semver": "bin/semver.js" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" + }, "node_modules/markdown-it": { "version": "11.0.1", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-11.0.1.tgz", @@ -4630,9 +4297,9 @@ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" }, "node_modules/minipass": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.5.tgz", - "integrity": "sha512-+8NzxD82XQoNKNrl1d/FSi+X8wAEWR+sbYAfIvub4Nz0d22plFG72CEVVaufV8PNf4qSslFTD8VMOxNVhHCjTw==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz", + "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", "dependencies": { "yallist": "^4.0.0" }, @@ -5165,12 +4832,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/mocha/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/mocha/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -5224,14 +4885,6 @@ } } }, - "node_modules/mongodb/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/mongodb/node_modules/optional-require": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.1.8.tgz", @@ -5271,22 +4924,6 @@ "url": "https://opencollective.com/mongoose" } }, - "node_modules/mongoose/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/mongoose/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/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", @@ -5295,24 +4932,10 @@ "mongoose": "*" } }, - "node_modules/mongoose/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/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", @@ -5356,14 +4979,14 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "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==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/multer": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.3.tgz", - "integrity": "sha512-np0YLKncuZoTzufbkM6wEKp68EhWJXcU6fq6QqrSwkckd2LlMgd1UqhUJLj6NS/5sZ8dE8LYDWslsltJznnXlg==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4.tgz", + "integrity": "sha512-2wY2+xD4udX612aMqMcB8Ws2Voq6NIUPEtD1be6m411T4uDH/VtL9i//xvcyFlTVfRdaBsk7hV5tgrGQqhuBiw==", "dependencies": { "append-field": "^1.0.0", "busboy": "^0.2.11", @@ -5488,15 +5111,6 @@ "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/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -5559,17 +5173,14 @@ } }, "node_modules/npmlog": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.0.tgz", - "integrity": "sha512-03ppFRGlsyUaQFbGC2C8QWJN/C/K7PsfyD9aQdhVKAQIH4sQBc8WASqFBP7O+Ut4d2oo5LoeoboB3cGdBZSp6Q==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", "dependencies": { "are-we-there-yet": "^2.0.0", "console-control-strings": "^1.1.0", - "gauge": "^4.0.0", + "gauge": "^3.0.0", "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" } }, "node_modules/nth-check": { @@ -5592,34 +5203,10 @@ } }, "node_modules/object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", - "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/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", + "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5780,9 +5367,9 @@ } }, "node_modules/parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" }, "node_modules/parse5-htmlparser2-tree-adapter": { "version": "6.0.1", @@ -5792,11 +5379,6 @@ "parse5": "^6.0.1" } }, - "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" - }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -5861,6 +5443,11 @@ "node": ">=8" } }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -5947,11 +5534,11 @@ } }, "node_modules/pgpass": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.4.tgz", - "integrity": "sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", "dependencies": { - "split2": "^3.1.1" + "split2": "^4.1.0" } }, "node_modules/picomatch": { @@ -6060,27 +5647,8 @@ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/promise.allsettled": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.5.tgz", - "integrity": "sha512-tVDqeZPoBC0SlzJHzWGZ2NKAguVq2oiYj7gbggbiTvH2itHohijTp7njOUA0aQ/nl+0lr/r6egmhoYu63UZ/pQ==", - "dependencies": { - "array.prototype.map": "^1.0.4", - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", - "get-intrinsic": "^1.1.1", - "iterate-value": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=0.4.0" } }, "node_modules/proto-list": { @@ -6151,15 +5719,6 @@ "node": ">=8" } }, - "node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, "node_modules/qrcode": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.0.tgz", @@ -6303,9 +5862,9 @@ } }, "node_modules/qs": { - "version": "6.10.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", - "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.2.tgz", + "integrity": "sha512-mSIdjzqznWgfd4pMii7sHtaYF8rx8861hBO80SraY5GT0XQibWZWJSid0avzHGkDIZLImux2S5mXO0Hfct2QCw==", "dev": true, "dependencies": { "side-channel": "^1.0.4" @@ -6335,12 +5894,12 @@ } }, "node_modules/raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.2.tgz", + "integrity": "sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==", "dependencies": { - "bytes": "3.1.0", - "http-errors": "1.7.2", + "bytes": "3.1.1", + "http-errors": "1.8.1", "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, @@ -6374,12 +5933,6 @@ "rc": "cli.js" } }, - "node_modules/rc/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, "node_modules/rc/node_modules/strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -6502,6 +6055,18 @@ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" }, + "node_modules/resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dependencies": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -6540,6 +6105,27 @@ "node": ">=8.10.0" } }, + "node_modules/retry-request/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/retry-request/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/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -6555,9 +6141,23 @@ } }, "node_modules/safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + "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-stable-stringify": { "version": "1.1.1", @@ -6622,9 +6222,9 @@ } }, "node_modules/send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", "dependencies": { "debug": "2.6.9", "depd": "~1.1.2", @@ -6633,9 +6233,9 @@ "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.7.2", + "http-errors": "1.8.1", "mime": "1.6.0", - "ms": "2.1.1", + "ms": "2.1.3", "on-finished": "~2.3.0", "range-parser": "~1.2.1", "statuses": "~1.5.0" @@ -6676,11 +6276,6 @@ "node": ">=4" } }, - "node_modules/send/node_modules/ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - }, "node_modules/serialize-javascript": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", @@ -6691,14 +6286,14 @@ } }, "node_modules/serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", + "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.1" + "send": "0.17.2" }, "engines": { "node": ">= 0.8.0" @@ -6710,9 +6305,9 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "node_modules/setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "node_modules/sha.js": { "version": "2.4.11", @@ -6751,6 +6346,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, "dependencies": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -6826,6 +6422,15 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "node_modules/sparse-bitfield": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", @@ -6836,11 +6441,11 @@ } }, "node_modules/split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "dependencies": { - "readable-stream": "^3.0.0" + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", + "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==", + "engines": { + "node": ">= 10.x" } }, "node_modules/sprintf-js": { @@ -6907,30 +6512,6 @@ "node": ">=8" } }, - "node_modules/string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -6942,6 +6523,14 @@ "node": ">=8" } }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "engines": { + "node": ">=4" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -6980,21 +6569,6 @@ "node": ">= 4.0" } }, - "node_modules/superagent/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/superagent/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, "node_modules/superagent/node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -7049,9 +6623,9 @@ } }, "node_modules/table": { - "version": "6.7.3", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.3.tgz", - "integrity": "sha512-5DkIxeA7XERBqMwJq0aHZOdMadBx4e6eDoFRuyT5VR82J0Ycg2DwM6GfA/EQAhJ+toRTaS1lIdSQCqgrmhPnlw==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.5.tgz", + "integrity": "sha512-LFNeryOqiQHqCVKzhkymKwt6ozeRhlm8IL1mE8rNUurkir4heF6PzMyRgaTa4tlyPTGGgXuvVOF/OLWiH09Lqw==", "dev": true, "dependencies": { "ajv": "^8.0.1", @@ -7179,9 +6753,9 @@ } }, "node_modules/toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "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" } @@ -7218,11 +6792,126 @@ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "bin": { + "tree-kill": "cli.js" + } + }, "node_modules/triple-beam": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" }, + "node_modules/ts-node": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", + "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", + "dependencies": { + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "typescript": ">=2.7" + } + }, + "node_modules/ts-node-dev": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-1.1.8.tgz", + "integrity": "sha512-Q/m3vEwzYwLZKmV6/0VlFxcZzVV/xcgOt+Tx/VjaaRHyiBcFlV0541yrT09QjzzCxlDZ34OzKjrFAynlmtflEg==", + "dependencies": { + "chokidar": "^3.5.1", + "dynamic-dedupe": "^0.3.0", + "minimist": "^1.2.5", + "mkdirp": "^1.0.4", + "resolve": "^1.0.0", + "rimraf": "^2.6.1", + "source-map-support": "^0.5.12", + "tree-kill": "^1.2.2", + "ts-node": "^9.0.0", + "tsconfig": "^7.0.0" + }, + "bin": { + "ts-node-dev": "lib/bin.js", + "tsnd": "lib/bin.js" + }, + "engines": { + "node": ">=0.8.0" + }, + "peerDependencies": { + "node-notifier": "*", + "typescript": "*" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/ts-node-dev/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-node-dev/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tsconfig": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", + "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", + "dependencies": { + "@types/strip-bom": "^3.0.0", + "@types/strip-json-comments": "0.0.30", + "strip-bom": "^3.0.0", + "strip-json-comments": "^2.0.0" + } + }, + "node_modules/tsconfig/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/tslib": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", @@ -7408,27 +7097,20 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, - "node_modules/typeorm/node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "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/typeorm/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/typeorm/node_modules/dotenv": { @@ -7461,27 +7143,40 @@ "node": ">=10" } }, + "node_modules/typeorm/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/typeorm/node_modules/yargs": { - "version": "17.2.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.2.1.tgz", - "integrity": "sha512-XfR8du6ua4K6uLGm5S6fA+FIJom/MdJcFNVY8geLlp2v8GYbOXD4EB1tPNZsRn4vBzKGMgb5DRZMeWuFc2GO8Q==", + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz", + "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==", "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.0.0" }, "engines": { "node": ">=12" } }, + "node_modules/typeorm/node_modules/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==", + "engines": { + "node": ">=12" + } + }, "node_modules/typescript": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz", - "integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==", + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz", + "integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -7497,9 +7192,9 @@ "dev": true }, "node_modules/uglify-js": { - "version": "3.14.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.3.tgz", - "integrity": "sha512-mic3aOdiq01DuSVx0TseaEzMIVqebMZ0Z3vaeDhFEh9bsc24hV1TFvN74reA2vs08D0ZWfNjAcJ3UbVLaBss+g==", + "version": "3.14.5", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.5.tgz", + "integrity": "sha512-qZukoSxOG0urUTvjc2ERMTcAy+BiFh3weWAkeurLwjrCba73poHmG3E36XEjd/JGukMzwTL7uCxZiAexj8ppvQ==", "bin": { "uglifyjs": "bin/uglifyjs" }, @@ -7507,20 +7202,6 @@ "node": ">=0.8.0" } }, - "node_modules/unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dependencies": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", @@ -7752,21 +7433,6 @@ "node": ">= 8" } }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", @@ -7812,47 +7478,16 @@ } }, "node_modules/winston-transport": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", - "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==", - "dependencies": { - "readable-stream": "^2.3.7", - "triple-beam": "^1.2.0" - }, - "engines": { - "node": ">= 6.4.0" - } - }, - "node_modules/winston-transport/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "node_modules/winston-transport/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/winston-transport/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/winston-transport/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==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.1.tgz", + "integrity": "sha512-ciZRlU4CSjHqHe8RQG1iPxKMRVwv6ZJ0RC7DxStKWd0KjpAhPDy5gVYSCpIUq+5CUsP+IyNOTZy1X0tO2QZqjg==", "dependencies": { - "safe-buffer": "~5.1.0" + "logform": "^2.2.0", + "readable-stream": "^3.4.0", + "triple-beam": "^1.2.0" + }, + "engines": { + "node": ">= 6.4.0" } }, "node_modules/word-wrap": { @@ -7996,6 +7631,14 @@ "node": ">=10" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -8154,6 +7797,23 @@ "js-yaml": "^3.13.1", "minimatch": "^3.0.4", "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "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 + } } }, "@google-cloud/common": { @@ -8192,9 +7852,9 @@ "integrity": "sha512-j8yRSSqswWi1QqUGKVEKOG03Q7qOoZP6/h2zN2YO+F5h2+DHU0bSrHCK9Y7lo2DI9fBd8qGAw795sf+3Jva4yA==" }, "@google-cloud/storage": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-5.16.0.tgz", - "integrity": "sha512-I/1lA78v9c5EbOM/KfcYsjzA7YlHQmhpzHYdKLKdYC8X5fFaQrw5nK+FU8GbEwdPxmREAF2qPbN7Ccq+A/ndWA==", + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-5.16.1.tgz", + "integrity": "sha512-C2li/2PUfLSGEetebLL70uQRwqm6PS+kBtFEjr5AnAn/Qv0UnD8V+rI9Y4RmwxWFvhlPAgg+ZRqa4bkK4eUxlA==", "requires": { "@google-cloud/common": "^3.8.1", "@google-cloud/paginator": "^3.0.0", @@ -8205,7 +7865,7 @@ "date-and-time": "^2.0.0", "duplexify": "^4.0.0", "extend": "^3.0.2", - "gcs-resumable-upload": "^3.5.1", + "gcs-resumable-upload": "^3.6.0", "get-stream": "^6.0.0", "hash-stream-validation": "^0.2.2", "mime": "^3.0.0", @@ -8226,6 +7886,23 @@ "@humanwhocodes/object-schema": "^1.2.0", "debug": "^4.1.1", "minimatch": "^3.0.4" + }, + "dependencies": { + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "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/object-schema": { @@ -8235,47 +7912,21 @@ "dev": true }, "@mapbox/node-pre-gyp": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.7.tgz", - "integrity": "sha512-PplSvl4pJ5N3BkVjAdDzpPhVUPdC73JgttkR+LnBx2OORC1GCQsBjUeEuipf9uOaAM1SbxcdZFfR3KDTKm2S0A==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.8.tgz", + "integrity": "sha512-CMGKi28CF+qlbXh26hDe6NxCd7amqeAzEqnS6IHeO6LoaKyM/n+Xw3HT1COdq8cuioOdlKdqn/hCmqPUOMOywg==", "requires": { "detect-libc": "^1.0.3", "https-proxy-agent": "^5.0.0", "make-dir": "^3.1.0", "node-fetch": "^2.6.5", "nopt": "^5.0.0", - "npmlog": "^6.0.0", + "npmlog": "^5.0.1", "rimraf": "^3.0.2", "semver": "^7.3.5", "tar": "^6.1.11" } }, - "@sendgrid/client": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@sendgrid/client/-/client-7.6.0.tgz", - "integrity": "sha512-cpBVZKLlMTO+vpE18krTixubYmZa98oTbLkqBDuTiA3zRkW+urrxg7pDR24TkI35Mid0Zru8jDHwnOiqrXu0TA==", - "requires": { - "@sendgrid/helpers": "^7.6.0", - "axios": "^0.21.4" - } - }, - "@sendgrid/helpers": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@sendgrid/helpers/-/helpers-7.6.0.tgz", - "integrity": "sha512-0uWD+HSXLl4Z/X3cN+UMQC20RE7xwAACgppnfjDyvKG0KvJcUgDGz7HDdQkiMUdcVWfmyk6zKSg7XKfKzBjTwA==", - "requires": { - "deepmerge": "^4.2.2" - } - }, - "@sendgrid/mail": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@sendgrid/mail/-/mail-7.6.0.tgz", - "integrity": "sha512-0KdaSZzflJD/vUAZjB3ALBIuaVGoLq22hrb2fvQXZHRepU/yhRNlEOqrr05MfKBnKskzq1blnD1J0fHxiwaolw==", - "requires": { - "@sendgrid/client": "^7.6.0", - "@sendgrid/helpers": "^7.6.0" - } - }, "@sindresorhus/is": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", @@ -8321,11 +7972,11 @@ } }, "@types/bson": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.2.0.tgz", - "integrity": "sha512-ELCPqAdroMdcuxqwMgUpifQyRoTpyYCNr1V9xKyF40VsBobsj+BbWNRvwGchMgBPGqkw655ypkjj2MEF5ywVwg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.5.tgz", + "integrity": "sha512-vVLwMUqhYJSQ/WKcE60eFqcyuWse5fGH+NMAXHuKrUAPoryq3ATxk5o4bgYNtg5aOM4APVg7Hnb3ASqUYG0PKg==", "requires": { - "bson": "*" + "@types/node": "*" } }, "@types/caseless": { @@ -8335,9 +7986,9 @@ "dev": true }, "@types/chai": { - "version": "4.2.22", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.22.tgz", - "integrity": "sha512-tFfcE+DSTzWAgifkjik9AySNqIyNoYwmR+uecPwwD/XRNfvOjmC/FjCxpiUGDkDVDphPfCUecSQVFw+lN3M3kQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.0.tgz", + "integrity": "sha512-/ceqdqeRraGolFTcfoXNiqjyQhZzbINDngeoAq9GoHa8PPK1yNzTaxWjA6BFWp5Ua9JpXEMSS4s5i9tS0hOJtw==", "dev": true }, "@types/connect": { @@ -8368,9 +8019,9 @@ } }, "@types/express-serve-static-core": { - "version": "4.17.25", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.25.tgz", - "integrity": "sha512-OUJIVfRMFijZukGGwTpKNFprqCCXk5WjNGvUgB/CxxBR40QWSjsNK86+yvGKlCOGc7sbwfHLaXhkG+NsytwBaQ==", + "version": "4.17.27", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.27.tgz", + "integrity": "sha512-e/sVallzUTPdyOTiqi8O8pMdBBphscvI6E4JYaKlja4Lm+zh7UFSSdW5VMkRbhDtmrONqOUHOXRguPsDckzxNA==", "dev": true, "requires": { "@types/node": "*", @@ -8436,15 +8087,6 @@ "@types/node": "*" } }, - "@types/mongoose": { - "version": "5.11.97", - "resolved": "https://registry.npmjs.org/@types/mongoose/-/mongoose-5.11.97.tgz", - "integrity": "sha512-cqwOVYT3qXyLiGw7ueU2kX9noE8DPGRY6z8eUxudhXY8NZ7DMKYAxyZkLSevGfhCX3dO/AoX5/SO9lAzfjon0Q==", - "dev": true, - "requires": { - "mongoose": "*" - } - }, "@types/multer": { "version": "1.4.7", "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.7.tgz", @@ -8455,9 +8097,9 @@ } }, "@types/node": { - "version": "16.11.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.10.tgz", - "integrity": "sha512-3aRnHa1KlOEEhJ6+CvyHKK5vE9BcLGjtUpwvqYLRvYNQKMfabu3BwfJaA/SLW8dxe28LsNDjtHwePTuzn3gmOA==" + "version": "17.0.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.5.tgz", + "integrity": "sha512-w3mrvNXLeDYV1GKTZorGJQivK6XLCoGwpnyJFbJVK/aTBQUxOCaa/GlFAAN3OTDFcb7h5tiFG+YXCO2By+riZw==" }, "@types/nodemailer": { "version": "6.4.4", @@ -8541,6 +8183,16 @@ "@types/node": "*" } }, + "@types/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I=" + }, + "@types/strip-json-comments": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", + "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==" + }, "@types/superagent": { "version": "4.1.13", "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-4.1.13.tgz", @@ -8558,9 +8210,9 @@ "dev": true }, "@types/validator": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.0.tgz", - "integrity": "sha512-+jBxVvXVuggZOrm04NR8z+5+bgoW4VZyLzUO+hmPPW1mVFL/HaitLAkizfv4yg9TbG8lkfHWVMQ11yDqrVVCzA==", + "version": "13.7.1", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.1.tgz", + "integrity": "sha512-I6OUIZ5cYRk5lp14xSOAiXjWrfVoMZVjDuevBYgQDYzZIjsf2CAISpEcXOkFAtpAHbmWIDLcZObejqny/9xq5Q==", "dev": true }, "@types/zen-observable": { @@ -8615,6 +8267,21 @@ "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "requires": { "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "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==" + } } }, "ajv": { @@ -8724,6 +8391,11 @@ "readable-stream": "^3.6.0" } }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -8738,18 +8410,6 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, - "array.prototype.map": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.4.tgz", - "integrity": "sha512-Qds9QnX7A0qISY7JT5WuJO0NJPE9CMlC6JzHQfhpqAAQQzufVRoeH7EzUY5GcPTx72voG8LV/5eo+b8Qi8hmhA==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "es-array-method-boxes-properly": "^1.0.0", - "is-string": "^1.0.7" - } - }, "arrify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", @@ -8792,14 +8452,6 @@ "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true }, - "axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "requires": { - "follow-redirects": "^1.14.0" - } - }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -8820,9 +8472,9 @@ } }, "bignumber.js": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", - "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==" + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", + "integrity": "sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw==" }, "binary-extensions": { "version": "2.2.0", @@ -8838,11 +8490,6 @@ "safe-buffer": "^5.1.1" }, "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -8878,20 +8525,20 @@ "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" }, "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.1.tgz", + "integrity": "sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA==", "requires": { - "bytes": "3.1.0", + "bytes": "3.1.1", "content-type": "~1.0.4", "debug": "2.6.9", "depd": "~1.1.2", - "http-errors": "1.7.2", + "http-errors": "1.8.1", "iconv-lite": "0.4.24", "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" + "qs": "6.9.6", + "raw-body": "2.4.2", + "type-is": "~1.6.18" }, "dependencies": { "debug": { @@ -8921,9 +8568,9 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==" } } }, @@ -8932,14 +8579,6 @@ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" }, - "boom": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-7.3.0.tgz", - "integrity": "sha512-Swpoyi2t5+GhOEGw8rEsKvTxFLIDiiKoUc2gsoV6Lyr43LHBIzch3k2MvYUs8RTROrIkVJ3Al0TkaOGjnb+B6A==", - "requires": { - "hoek": "6.x.x" - } - }, "boxen": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", @@ -8980,20 +8619,17 @@ "dev": true }, "bson": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.0.tgz", - "integrity": "sha512-8jw1NU1hglS+Da1jDOUYuNcBJ4cNHCFIqzlwoFNnsTOg2R/ox0aTYcTiBN4dzRa9q7Cvy6XErh3L8ReTEb9AQQ==", - "requires": { - "buffer": "^5.6.0" - } + "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==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "requires": { "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "ieee754": "^1.2.1" } }, "buffer-equal-constant-time": { @@ -9044,9 +8680,9 @@ } }, "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz", + "integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==" }, "cacheable-request": { "version": "6.1.0", @@ -9084,6 +8720,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, "requires": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -9178,13 +8815,6 @@ "parse5": "^6.0.1", "parse5-htmlparser2-tree-adapter": "^6.0.1", "tslib": "^2.2.0" - }, - "dependencies": { - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" - } } }, "cheerio-select": { @@ -9264,6 +8894,13 @@ "parse5": "^5.1.1", "parse5-htmlparser2-tree-adapter": "^6.0.0", "yargs": "^16.0.0" + }, + "dependencies": { + "parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" + } } }, "cliui": { @@ -9323,9 +8960,9 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "color-string": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.7.4.tgz", - "integrity": "sha512-nVdUvPVgZMpRQad5dcsCMOSB5BXLljklTiaxS6ehhKxDsAI5sD7k5VmFuBt1y3Rlym8uulc/ANUN/bMWtBu6Sg==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz", + "integrity": "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==", "requires": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" @@ -9336,6 +8973,11 @@ "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" + }, "colorspace": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", @@ -9389,11 +9031,6 @@ "typedarray": "^0.0.6" }, "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -9430,13 +9067,6 @@ "requires": { "ini": "^1.3.4", "proto-list": "~1.2.1" - }, - "dependencies": { - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - } } }, "configstore": { @@ -9458,18 +9088,11 @@ "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, "content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "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.1.2" - }, - "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==" - } + "safe-buffer": "5.2.1" } }, "content-type": { @@ -9492,24 +9115,14 @@ } }, "cookie-session": { - "version": "2.0.0-rc.1", - "resolved": "https://registry.npmjs.org/cookie-session/-/cookie-session-2.0.0-rc.1.tgz", - "integrity": "sha512-zg80EsLe7S1J4y0XxV7SZ8Fbi90ZZoampuX2bfYDOvJfc//98sSlZC41YDzTTjtVbeU1VlVdBbldXOOyi5xzEw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cookie-session/-/cookie-session-2.0.0.tgz", + "integrity": "sha512-hKvgoThbw00zQOleSlUr2qpvuNweoqBtxrmx0UFosx6AGi9lYtLoA+RbsvknrEX8Pr6MDbdWAb2j6SnMn+lPsg==", "requires": { "cookies": "0.8.0", - "debug": "3.2.6", + "debug": "3.2.7", "on-headers": "~1.0.2", - "safe-buffer": "5.2.0" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "requires": { - "ms": "^2.1.1" - } - } + "safe-buffer": "5.2.1" } }, "cookie-signature": { @@ -9546,6 +9159,11 @@ "vary": "^1" } }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -9557,23 +9175,15 @@ "which": "^2.0.1" } }, - "cryptiles": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-4.1.3.tgz", - "integrity": "sha512-gT9nyTMSUC1JnziQpPbxKGBbUg8VL7Zn2NB4E1cJYvuXdElHrwxrV9bmltZGDzet45zSDGyYceueke1TjynGzw==", - "requires": { - "boom": "7.x.x" - } - }, "crypto-random-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" }, "css-select": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.0.tgz", - "integrity": "sha512-6YVG6hsH9yIb/si3Th/is8Pex7qnVHO6t7q7U6TIUnkQASGbS8tnUDBftnPynLNnuUl/r2+PTd0ekiiq7R0zJw==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", + "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", "requires": { "boolbase": "^1.0.0", "css-what": "^5.1.0", @@ -9593,11 +9203,11 @@ "integrity": "sha512-O7Xe5dLaqvY/aF/MFWArsAM1J4j7w1CSZlPCX9uHgmb+6SbkPd8Q4YOvfvH/cZGvFlJFfHOZKxQtmMUOoZhc/w==" }, "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "requires": { - "ms": "2.1.2" + "ms": "^2.1.1" } }, "decamelize": { @@ -9636,25 +9246,12 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" - }, "defer-to-connect": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", "dev": true }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "requires": { - "object-keys": "^1.0.12" - } - }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -9806,6 +9403,14 @@ "stream-shift": "^1.0.0" } }, + "dynamic-dedupe": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", + "integrity": "sha1-BuRMIj9eTpTXjvnbI6ZRXOL5YqE=", + "requires": { + "xtend": "^4.0.0" + } + }, "ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -9898,63 +9503,6 @@ "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==" }, - "es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", - "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - } - }, - "es-array-method-boxes-properly": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", - "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" - }, - "es-get-iterator": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", - "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.0", - "has-symbols": "^1.0.1", - "is-arguments": "^1.1.0", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.5", - "isarray": "^2.0.5" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -10023,6 +9571,23 @@ "table": "^6.0.9", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "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 + } } }, "eslint-config-prettier": { @@ -10156,16 +9721,16 @@ "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" }, "express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.2.tgz", + "integrity": "sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg==", "requires": { "accepts": "~1.3.7", "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", + "body-parser": "1.19.1", + "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.0", + "cookie": "0.4.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "~1.1.2", @@ -10179,24 +9744,19 @@ "on-finished": "~2.3.0", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", + "proxy-addr": "~2.0.7", + "qs": "6.9.6", "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", "statuses": "~1.5.0", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" }, "dependencies": { - "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" - }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -10216,26 +9776,12 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" - }, - "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==" + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==" } } }, - "express-validator": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-6.13.0.tgz", - "integrity": "sha512-gvLqMFPwEm+C1CQlF3l695ubY1Shd3AtfI5JDYXM0Ju0A2GsGX+VjjQN7TcHXF6cO8wPgU8hSSFqWecBR0Gx1g==", - "requires": { - "lodash": "^4.17.21", - "validator": "^13.6.0" - } - }, "express-winston": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/express-winston/-/express-winston-4.2.0.tgz", @@ -10418,11 +9964,6 @@ "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, - "follow-redirects": { - "version": "1.14.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz", - "integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==" - }, "form-data": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", @@ -10493,15 +10034,15 @@ "dev": true }, "gauge": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.0.tgz", - "integrity": "sha512-F8sU45yQpjQjxKkm1UOAhf0U/O0aFt//Fl7hsrNVto+patMHjs7dPI9mFOGUKbhrgKm0S3EjW3scMFuQmWSROw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", "requires": { - "ansi-regex": "^5.0.1", "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.2", "console-control-strings": "^1.0.0", "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", "signal-exit": "^3.0.0", "string-width": "^4.2.3", "strip-ansi": "^6.0.1", @@ -10559,6 +10100,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dev": true, "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -10570,15 +10112,6 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, "glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -10607,6 +10140,14 @@ "dev": true, "requires": { "ini": "2.0.0" + }, + "dependencies": { + "ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true + } } }, "globals": { @@ -10619,9 +10160,9 @@ } }, "google-auth-library": { - "version": "7.10.2", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.10.2.tgz", - "integrity": "sha512-M37o9Kxa/TLvOLgF71SXvLeVEP5sbSTmKl1zlIgl72SFy5PtsU3pOdu8G8MIHHpQ3/NZabDI8rQkA9DvQVKkPA==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.11.0.tgz", + "integrity": "sha512-3S5jn2quRumvh9F/Ubf7GFrIq71HZ5a6vqosgdIu105kkk0WtSqc2jGCRqtWWOLRS8SX3AHACMOEDxhyWAQIcg==", "requires": { "arrify": "^2.0.0", "base64-js": "^1.3.0", @@ -10713,11 +10254,6 @@ "function-bind": "^1.1.1" } }, - "has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -10726,15 +10262,8 @@ "has-symbols": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "requires": { - "has-symbols": "^1.0.2" - } + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "dev": true }, "has-unicode": { "version": "2.0.1", @@ -10762,11 +10291,6 @@ "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==" }, - "hoek": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz", - "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==" - }, "html-minifier": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-4.0.0.tgz", @@ -10799,26 +10323,21 @@ "dev": true }, "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "requires": { "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "toidentifier": "1.0.1" }, "dependencies": { "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" } } }, @@ -10830,6 +10349,21 @@ "@tootallnate/once": "2", "agent-base": "6", "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "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==" + } } }, "https-proxy-agent": { @@ -10839,6 +10373,21 @@ "requires": { "agent-base": "6", "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "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==" + } } }, "iconv-lite": { @@ -10903,20 +10452,9 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true - }, - "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, "ip-regex": { "version": "2.1.0", @@ -10929,28 +10467,11 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, - "is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, "is-arrayish": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "requires": { - "has-bigints": "^1.0.1" - } - }, "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -10959,20 +10480,6 @@ "binary-extensions": "^2.0.0" } }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" - }, "is-ci": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", @@ -10982,12 +10489,12 @@ "ci-info": "^2.0.0" } }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "is-core-module": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", + "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", "requires": { - "has-tostringtag": "^1.0.0" + "has": "^1.0.3" } }, "is-extglob": { @@ -11027,16 +10534,6 @@ "ip-regex": "^2.0.0" } }, - "is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==" - }, - "is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==" - }, "is-npm": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", @@ -11048,14 +10545,6 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, - "is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, "is-obj": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", @@ -11073,46 +10562,11 @@ "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", "dev": true }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==" - }, - "is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==" - }, "is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "requires": { - "has-symbols": "^1.0.2" - } - }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -11124,14 +10578,6 @@ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true }, - "is-weakref": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", - "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", - "requires": { - "call-bind": "^1.0.0" - } - }, "is-yarn-global": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", @@ -11139,9 +10585,9 @@ "dev": true }, "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "isexe": { "version": "2.0.0", @@ -11149,20 +10595,6 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "iterate-iterator": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.2.tgz", - "integrity": "sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw==" - }, - "iterate-value": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz", - "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==", - "requires": { - "es-get-iterator": "^1.0.2", - "iterate-iterator": "^1.0.1" - } - }, "js-beautify": { "version": "1.14.0", "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.0.tgz", @@ -11363,9 +10795,9 @@ } }, "libphonenumber-js": { - "version": "1.9.43", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.43.tgz", - "integrity": "sha512-tNB87ZutAiAkl3DE/Bo0Mxqn/XZbNxhPg4v9bYBwQQW4dlhBGqXl1vtmPxeDWbrijzwOA9vRjOOFm5V9SK/W3w==" + "version": "1.9.44", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.44.tgz", + "integrity": "sha512-zhw8nUMJuQf7jG1dZfEOKKOS6M3QYIv3HnvB/vGohNd0QfxIQcObH3a6Y6s350H+9xgBeOXClOJkS0hJ0yvS3g==" }, "linkify-it": { "version": "3.0.3", @@ -11457,13 +10889,6 @@ "ms": "^2.1.1", "safe-stable-stringify": "^1.1.0", "triple-beam": "^1.3.0" - }, - "dependencies": { - "colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" - } } }, "lower-case": { @@ -11500,6 +10925,11 @@ } } }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" + }, "markdown-it": { "version": "11.0.1", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-11.0.1.tgz", @@ -11588,9 +11018,9 @@ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" }, "minipass": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.5.tgz", - "integrity": "sha512-+8NzxD82XQoNKNrl1d/FSi+X8wAEWR+sbYAfIvub4Nz0d22plFG72CEVVaufV8PNf4qSslFTD8VMOxNVhHCjTw==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz", + "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", "requires": { "yallist": "^4.0.0" } @@ -12075,12 +11505,6 @@ "argparse": "^2.0.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 - }, "supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -12105,11 +11529,6 @@ "saslprep": "^1.0.0" }, "dependencies": { - "bson": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", - "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==" - }, "optional-require": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.1.8.tgz", @@ -12141,29 +11560,16 @@ "sliced": "1.0.1" }, "dependencies": { - "@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": "*" - } - }, - "bson": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", - "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==" - }, "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": {} }, - "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==" + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" } } }, @@ -12205,14 +11611,14 @@ } }, "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "multer": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.3.tgz", - "integrity": "sha512-np0YLKncuZoTzufbkM6wEKp68EhWJXcU6fq6QqrSwkckd2LlMgd1UqhUJLj6NS/5sZ8dE8LYDWslsltJznnXlg==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4.tgz", + "integrity": "sha512-2wY2+xD4udX612aMqMcB8Ws2Voq6NIUPEtD1be6m411T4uDH/VtL9i//xvcyFlTVfRdaBsk7hV5tgrGQqhuBiw==", "requires": { "append-field": "^1.0.0", "busboy": "^0.2.11", @@ -12305,15 +11711,6 @@ "update-notifier": "^5.1.0" }, "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" - } - }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -12357,13 +11754,13 @@ "dev": true }, "npmlog": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.0.tgz", - "integrity": "sha512-03ppFRGlsyUaQFbGC2C8QWJN/C/K7PsfyD9aQdhVKAQIH4sQBc8WASqFBP7O+Ut4d2oo5LoeoboB3cGdBZSp6Q==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", "requires": { "are-we-there-yet": "^2.0.0", "console-control-strings": "^1.1.0", - "gauge": "^4.0.0", + "gauge": "^3.0.0", "set-blocking": "^2.0.0" } }, @@ -12381,25 +11778,10 @@ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==" - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - }, - "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - } + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", + "dev": true }, "on-finished": { "version": "2.3.0", @@ -12520,9 +11902,9 @@ } }, "parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" }, "parse5-htmlparser2-tree-adapter": { "version": "6.0.1", @@ -12530,13 +11912,6 @@ "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", "requires": { "parse5": "^6.0.1" - }, - "dependencies": { - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" - } } }, "parseurl": { @@ -12582,6 +11957,11 @@ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -12646,11 +12026,11 @@ } }, "pgpass": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.4.tgz", - "integrity": "sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", "requires": { - "split2": "^3.1.1" + "split2": "^4.1.0" } }, "picomatch": { @@ -12724,19 +12104,6 @@ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, - "promise.allsettled": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.5.tgz", - "integrity": "sha512-tVDqeZPoBC0SlzJHzWGZ2NKAguVq2oiYj7gbggbiTvH2itHohijTp7njOUA0aQ/nl+0lr/r6egmhoYu63UZ/pQ==", - "requires": { - "array.prototype.map": "^1.0.4", - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", - "get-intrinsic": "^1.1.1", - "iterate-value": "^1.0.2" - } - }, "proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", @@ -12796,11 +12163,6 @@ "escape-goat": "^2.0.0" } }, - "q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" - }, "qrcode": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.0.tgz", @@ -12910,9 +12272,9 @@ } }, "qs": { - "version": "6.10.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", - "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.2.tgz", + "integrity": "sha512-mSIdjzqznWgfd4pMii7sHtaYF8rx8861hBO80SraY5GT0XQibWZWJSid0avzHGkDIZLImux2S5mXO0Hfct2QCw==", "dev": true, "requires": { "side-channel": "^1.0.4" @@ -12933,12 +12295,12 @@ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.2.tgz", + "integrity": "sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==", "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", + "bytes": "3.1.1", + "http-errors": "1.8.1", "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, @@ -12965,12 +12327,6 @@ "strip-json-comments": "~2.0.1" }, "dependencies": { - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -13062,6 +12418,15 @@ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" }, + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -13089,6 +12454,21 @@ "requires": { "debug": "^4.1.1", "extend": "^3.0.2" + }, + "dependencies": { + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "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==" + } } }, "rimraf": { @@ -13100,9 +12480,9 @@ } }, "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, "safe-stable-stringify": { "version": "1.1.1", @@ -13154,9 +12534,9 @@ } }, "send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", "requires": { "debug": "2.6.9", "depd": "~1.1.2", @@ -13165,9 +12545,9 @@ "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.7.2", + "http-errors": "1.8.1", "mime": "1.6.0", - "ms": "2.1.1", + "ms": "2.1.3", "on-finished": "~2.3.0", "range-parser": "~1.2.1", "statuses": "~1.5.0" @@ -13197,11 +12577,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" } } }, @@ -13215,14 +12590,14 @@ } }, "serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", + "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", "requires": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.1" + "send": "0.17.2" } }, "set-blocking": { @@ -13231,9 +12606,9 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "sha.js": { "version": "2.4.11", @@ -13263,6 +12638,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, "requires": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -13323,6 +12699,15 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "sparse-bitfield": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", @@ -13333,12 +12718,9 @@ } }, "split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "requires": { - "readable-stream": "^3.0.0" - } + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", + "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==" }, "sprintf-js": { "version": "1.0.3", @@ -13392,24 +12774,6 @@ "strip-ansi": "^6.0.1" } }, - "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -13418,6 +12782,11 @@ "ansi-regex": "^5.0.1" } }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" + }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -13447,21 +12816,6 @@ "readable-stream": "^2.3.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" - } - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -13509,9 +12863,9 @@ } }, "table": { - "version": "6.7.3", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.3.tgz", - "integrity": "sha512-5DkIxeA7XERBqMwJq0aHZOdMadBx4e6eDoFRuyT5VR82J0Ycg2DwM6GfA/EQAhJ+toRTaS1lIdSQCqgrmhPnlw==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.5.tgz", + "integrity": "sha512-LFNeryOqiQHqCVKzhkymKwt6ozeRhlm8IL1mE8rNUurkir4heF6PzMyRgaTa4tlyPTGGgXuvVOF/OLWiH09Lqw==", "dev": true, "requires": { "ajv": "^8.0.1", @@ -13615,9 +12969,9 @@ } }, "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + "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", @@ -13644,11 +12998,86 @@ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" }, + "tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==" + }, "triple-beam": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" }, + "ts-node": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", + "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", + "requires": { + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" + } + } + }, + "ts-node-dev": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-1.1.8.tgz", + "integrity": "sha512-Q/m3vEwzYwLZKmV6/0VlFxcZzVV/xcgOt+Tx/VjaaRHyiBcFlV0541yrT09QjzzCxlDZ34OzKjrFAynlmtflEg==", + "requires": { + "chokidar": "^3.5.1", + "dynamic-dedupe": "^0.3.0", + "minimist": "^1.2.5", + "mkdirp": "^1.0.4", + "resolve": "^1.0.0", + "rimraf": "^2.6.1", + "source-map-support": "^0.5.12", + "tree-kill": "^1.2.2", + "ts-node": "^9.0.0", + "tsconfig": "^7.0.0" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "tsconfig": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", + "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", + "requires": { + "@types/strip-bom": "^3.0.0", + "@types/strip-json-comments": "0.0.30", + "strip-bom": "^3.0.0", + "strip-json-comments": "^2.0.0" + }, + "dependencies": { + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + } + } + }, "tslib": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", @@ -13745,13 +13174,12 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, - "buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" + "ms": "2.1.2" } }, "dotenv": { @@ -13772,26 +13200,36 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "yargs": { - "version": "17.2.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.2.1.tgz", - "integrity": "sha512-XfR8du6ua4K6uLGm5S6fA+FIJom/MdJcFNVY8geLlp2v8GYbOXD4EB1tPNZsRn4vBzKGMgb5DRZMeWuFc2GO8Q==", + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz", + "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==", "requires": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.0.0" } + }, + "yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==" } } }, "typescript": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz", - "integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==" + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz", + "integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==" }, "uc.micro": { "version": "1.0.6", @@ -13800,20 +13238,9 @@ "dev": true }, "uglify-js": { - "version": "3.14.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.3.tgz", - "integrity": "sha512-mic3aOdiq01DuSVx0TseaEzMIVqebMZ0Z3vaeDhFEh9bsc24hV1TFvN74reA2vs08D0ZWfNjAcJ3UbVLaBss+g==" - }, - "unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - } + "version": "3.14.5", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.5.tgz", + "integrity": "sha512-qZukoSxOG0urUTvjc2ERMTcAy+BiFh3weWAkeurLwjrCba73poHmG3E36XEjd/JGukMzwTL7uCxZiAexj8ppvQ==" }, "undefsafe": { "version": "2.0.5", @@ -13988,18 +13415,6 @@ "isexe": "^2.0.0" } }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, "which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", @@ -14039,46 +13454,13 @@ } }, "winston-transport": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", - "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.1.tgz", + "integrity": "sha512-ciZRlU4CSjHqHe8RQG1iPxKMRVwv6ZJ0RC7DxStKWd0KjpAhPDy5gVYSCpIUq+5CUsP+IyNOTZy1X0tO2QZqjg==", "requires": { - "readable-stream": "^2.3.7", + "logform": "^2.2.0", + "readable-stream": "^3.4.0", "triple-beam": "^1.2.0" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "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" - } - }, - "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==" - }, - "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" - } - } } }, "word-wrap": { @@ -14189,6 +13571,11 @@ "is-plain-obj": "^2.1.0" } }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" + }, "yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 0ed1fc7e..3653ea9f 100644 --- a/package.json +++ b/package.json @@ -2,13 +2,12 @@ "name": "hackerAPI", "version": "3.1.3", "private": true, + "license": "MIT", "scripts": { - "start": "DEBUG=hackboard:* NODE_ENV=test rimraf dist/ && tsc && cp .env ./dist/.env && cp -R assets/ ./dist/assets && nodemon --ignore gcp_creds.json ./dist/app.js", - "start-windows": "set DEBUG=hackboard:* && set NODE_ENV=test && nodemon --ignore gcp_creds.json ./bin/www.js", + "start": "DEBUG=hackboard:* NODE_ENV=test ts-node-dev --respawn --pretty --transpile-only src/app.ts", + "start-windows": "set DEBUG=hackboard:* && set NODE_ENV=test && ts-node-dev --respawn --pretty --transpile-only src/app.ts", "deploy": "NODE_ENV=deployment node ./bin/www.js", - "debug": "DEBUG=hackboard:* NODE_ENV=test nodemon --ignore gcp_creds.json ./bin/www.js", "test": "DEBUG=hackboard:* NODE_ENV=test mocha --parallel --reporter spec tests/**.js --exit", - "seed": "NODE_ENV=test node ./seed/index.js", "docs": "apidoc -i ./routes -o ./docs/api/", "format": "prettier --write '**/*.js'", "lint": "eslint --fix '**/*.js'" @@ -17,18 +16,14 @@ "@decorators/di": "^1.0.3", "@decorators/express": "^2.6.0", "@google-cloud/storage": "^5.10.0", - "@sendgrid/mail": "^7.4.5", "bcrypt": "^5.0.1", "class-transformer": "^0.5.1", "class-validator": "^0.13.2", "cookie-parser": "^1.4.5", "cookie-session": "^2.0.0-rc.1", "cors": "^2.8.5", - "cryptiles": "^4.1.3", - "debug": "~4.3.2", "dotenv": "^10.0.0", "express": "~4.17.1", - "express-validator": "^6.12.0", "express-winston": "^4.2.0", "handlebars": "^4.7.7", "jsonwebtoken": "^8.5.1", @@ -40,10 +35,9 @@ "passport": "^0.4.1", "passport-local": "^1.0.0", "pg": "^8.7.1", - "promise.allsettled": "^1.0.4", - "q": "^1.5.1", "qrcode": "^1.4.4", "reflect-metadata": "^0.1.13", + "ts-node-dev": "^1.1.8", "tsyringe": "^4.6.0", "typeorm": "^0.2.41", "typescript": "^4.5.2", @@ -56,8 +50,6 @@ "@types/google-cloud__storage": "^1.7.2", "@types/jsonwebtoken": "^8.5.6", "@types/mjml": "^4.7.0", - "@types/mongodb": "^3.6.20", - "@types/mongoose": "^5.11.97", "@types/multer": "^1.4.7", "@types/nodemailer": "^6.4.4", "@types/passport": "^1.0.7", @@ -72,8 +64,6 @@ "eslint-config-prettier": "8.3.0", "eslint-plugin-prettier": "3.4.0", "mocha": "^9.0.3", - "nodemon": "^2.0.12", - "prettier": "1.19.1", - "rimraf": "^3.0.2" + "prettier": "1.19.1" } } diff --git a/src/services/env.service.ts b/src/services/env.service.ts index 84d84998..da8695c7 100644 --- a/src/services/env.service.ts +++ b/src/services/env.service.ts @@ -21,7 +21,7 @@ interface GoogleCloudPlatformCredentials { export class EnvService { constructor() { const result: DotenvConfigOutput = config({ - path: join(__dirname, "../.env") + path: join(__dirname, "../../.env") }); if (result.error) throw result.error; this.createGoogleCloudPlatformFile(); diff --git a/tsconfig.json b/tsconfig.json index ba9ed9ad..2764dcb6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { "experimentalDecorators": true, - "target": "ES5", + "target": "ES6", "lib": ["ES6", "ES2017"], "noImplicitAny": true, "strictNullChecks": true, @@ -10,8 +10,6 @@ "preserveConstEnums": true, "sourceMap": true, "outDir": "dist/", - "allowJs": true, - //"checkJs": true, "esModuleInterop": true, "moduleResolution": "node", "resolveJsonModule": true, From 2532510209fe434e39c87efe53bacbd6b18ab89d Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Mon, 3 Jan 2022 00:30:49 -0500 Subject: [PATCH 30/72] refactor: delete old scripts for hacker related actions. --- scripts/accept_script.py | 470 --------------------------------------- scripts/batch_scripts.py | 427 ----------------------------------- 2 files changed, 897 deletions(-) delete mode 100644 scripts/accept_script.py delete mode 100644 scripts/batch_scripts.py diff --git a/scripts/accept_script.py b/scripts/accept_script.py deleted file mode 100644 index f76f445e..00000000 --- a/scripts/accept_script.py +++ /dev/null @@ -1,470 +0,0 @@ -#!/bin/bash/python3 -import base64 -from bson import ObjectId -import csv -import getpass -import json -import os -import readline -import requests -import subprocess -from typing import Any, Callable, List -import sys - -# Constants -VALID_STATUSES = { - '1': 'Applied', - '2': 'Accepted', - '3': 'Waitlisted', - '4': 'Declined', - '5': 'Confirmed', - '6': 'Withdrawn', - '7': 'Checked-in' -} -BATCH_ACTIONS = { - '1': 'updateStatus', - '2': 'dayOf', - '3': 'weekOf', - '4': 'downloadResume', - '5': 'inviteUsers', - '6': 'getHackers', - '7': 'acceptHackers' -} -LOG_VERBOSITIES = { - '0': 'None', - '1': 'Error', - '2': 'Warning', - '3': 'Info' -} - -CHOSEN_VERBOSITY = 3 - - -API_URL = 'https://api.mchacks.ca' - - -s = requests.Session() - - -def _print(msg, msgType=3, index=None, total=None): - """ - Wrapper around print function such that we only print to the granularity that the user wants. - Also, allow for formatting of sequential print statements ex: (10/114) - """ - global CHOSEN_VERBOSITY - if msgType <= CHOSEN_VERBOSITY: - out_file = sys.stdout if msgType > 1 else sys.stderr - if index is None or total is None: - print('{0}: {1}'.format( - LOG_VERBOSITIES[str(msgType)], msg), file=out_file) - else: - print('({0}/{1}) {2}: {3}'.format(index, total, - LOG_VERBOSITIES[str(msgType)], msg), file=out_file) - - -def requestUntilSuccess( - string: str, - invalid_msg: str = 'Invalid input', - validInput: Callable[[Any], bool] = lambda x: x is not None, - transformInput: Callable[[str], Any] = lambda x: x -) -> str: - """ - Requests user input until validInput predicate is satisfied. - Returns the output of transformInput. - """ - user_input = None - while not validInput(user_input): - print('=====================================') - user_input = input(string) - if not validInput(user_input): - print(invalid_msg) - return transformInput(user_input) - - -def login(session=requests.Session()): - """ - Logs in a user to the inputted session, and returns the session. - """ - global API_URL - user_input = requestUntilSuccess( - 'Enter Target API (Default {0}): '.format(API_URL)) - if user_input != '': - API_URL = user_input - # Get credentials - username = requestUntilSuccess( - 'Enter credentials for {0}: '.format(API_URL)) - logged_in = False - - while not logged_in: - password = getpass.getpass("Password: ") - credentials = { - 'email': username, - 'password': password - } - r = session.post('{0}/api/auth/login'.format(API_URL), credentials) - if r.status_code != 200: - print("Incorrect password, please try again.") - else: - print('Logged in as {0}'.format(username)) - logged_in = True - return session - - -def chooseLogVerbosity(): - global CHOSEN_VERBOSITY - verbosity_list = ['{0}: {1}\n'.format(k, v) - for k, v in LOG_VERBOSITIES.items()] - chosen_verbosity = requestUntilSuccess( - 'Input log verbosity (default {0}):\n{1}'.format( - CHOSEN_VERBOSITY, ''.join(verbosity_list)), - 'Invalid verbosity', - lambda x: x == '' or x in LOG_VERBOSITIES.keys(), - lambda x: CHOSEN_VERBOSITY if x == '' else int(x) - ) - CHOSEN_VERBOSITY = chosen_verbosity - - -def loadInvites() -> List[str]: - """ - Load the list of invites provided by user inputted file path. - """ - # Get information about batch actions - invite_file = requestUntilSuccess( - 'Path to Invite CSV: ', - 'Invalid file', - lambda x: x is not None and os.path.isfile(x) and os.access(x, os.R_OK) - ) - - invites = [] - with open(invite_file, 'r') as csvfile: - reader = csv.DictReader(csvfile) - index = 1 - for row in reader: - index = index + 1 - email = row['email'] - accountType = row['accountType'] - if email is not None and accountType is not None: - invites.append({ - 'email': email, - 'accountType': accountType - }) - else: - _print('{2} is not a valid invite format'.format( - row), 1, index, len(reader)) - return invites - - -def loadIDs() -> List[str]: - """ - Load the list of IDs provided by user inputted file path. - """ - # Get information about batch actions - id_file = requestUntilSuccess( - 'Path to file to MongoIDs: ', - 'Invalid file', - lambda x: x is not None and os.path.isfile(x) and os.access(x, os.R_OK) - ) - - ids = [] - with open(id_file, 'r') as f: - rows = f.readlines() - for index, r in enumerate(rows): - index = index + 1 - r = r.strip() - if ObjectId.is_valid(r): - ids.append(r) - else: - _print('{2} is not a valid ObjectID'.format( - r), 1, index, len(rows)) - # remove duplicates - ids = list(set(ids)) - return ids - - -def getDownloadDirectory() -> str: - directory = requestUntilSuccess( - 'Directory to download files to: ', - 'Invalid directory', - lambda x: x is not None and os.path.isdir(x) and os.access(x, os.W_OK) - ) - directory.rstrip('/') - return directory - - -def status(prefixStr) -> str: - status_list = ['{0}: {1}\n'.format(k, v) - for k, v in VALID_STATUSES.items()] - initial_status = requestUntilSuccess( - 'Input {0} status:\n{1}'.format(prefixStr, ''.join(status_list)), - 'Invalid {0} status'.format(prefixStr), - lambda x: x in VALID_STATUSES.keys(), - lambda x: VALID_STATUSES[x] - ) - return initial_status - - -def batchAction() -> str: - status_list = ['{0}: {1}\n'.format(k, v) for k, v in BATCH_ACTIONS.items()] - batch_action = requestUntilSuccess( - 'Batch Action desired:\n{0}'.format(''.join(status_list)), - 'Invalid batch action', - lambda x: x in BATCH_ACTIONS.keys(), - lambda x: BATCH_ACTIONS[x] - ) - return batch_action - - -def getHacker(ID): - r = s.get('{0}/api/hacker/{1}'.format(API_URL, ID)) - if r.status_code != 200: - return None - else: - hackerInfo = json.loads(r.content)['data'] - return hackerInfo - - -def hasValidStatus(status, hackerInfo): - if hackerInfo is not None and hackerInfo['status'] == status: - return True - else: - return False - - -def search(model: str = 'hacker', query=[], expand: bool = True): - q = json.dumps(query) - expand = 'true' if expand else 'false' - r = s.get( - '{0}/api/search?model={1}&q={2}&expand={3}'.format(API_URL, model, q, expand)) - if r.status_code != 200: - _print('Could not perform search (Status code {0})'.format( - r.status_code), 1) - return [] - else: - results = json.loads(r.content)['data'] - return results - -def loadEmails(): - """ - Load the list of emails provided by user inputted file path. - """ - # Get information about batch actions - emails_file = requestUntilSuccess( - 'Path to file to Emails: ', - 'Invalid file', - lambda x: x is not None and os.path.isfile(x) and os.access(x, os.R_OK) - ) - - emails = [] - with open(emails_file, 'r') as f: - rows = f.readlines() - for index, r in enumerate(rows): - index = index + 1 - r = r.strip() - emails.append(r) - # remove duplicates - emails = list(set(emails)) - print(emails) - return emails - -def getIdList(): - list_of_ids = [] - HACKER_EMAILS = loadEmails() - for index, EMAIL in enumerate(HACKER_EMAILS): - # so that we aren't 0-based index - index = index + 1 - - a = s.get('{0}/api/hacker/email/{1}'.format(API_URL,EMAIL)) - if a.status_code != 200: - _print('cannot find hacker for {0}'.format( - EMAIL), 1, index, len(HACKER_EMAILS)) - else: - _print('{0} {1}'.format( - "FOUND HACKER FROM ", EMAIL), 3, index, len(HACKER_EMAILS)) - hacker = json.loads(a.text) - list_of_ids.append(hacker['data']['id']) - return list_of_ids - -def updateStatus(): - INITIAL_STATUS = status('initial') - NEW_STATUS = status('new') - HACKER_IDs = getIdList() - for index, ID in enumerate(HACKER_IDs): - # so that we aren't 0-based index - index = index + 1 - hacker = getHacker(ID) - validStatus = hasValidStatus(INITIAL_STATUS, hacker) - if validStatus: - r = s.patch('{0}/api/hacker/status/{1}'.format(API_URL, ID), - {"status": NEW_STATUS}) - if r.status_code != 200: - _print('cannot update status for {0}'.format( - ID), 1, index, len(HACKER_IDs)) - else: - _print('{0} {1}'.format( - NEW_STATUS, ID), 3, index, len(HACKER_IDs)) - elif hacker is not None: - _print('invalid status for {0}'.format( - ID), 1, index, len(HACKER_IDs)) - else: - _print('could not find {0}'.format( - ID), 1, index, len(HACKER_IDs)) - - -def sendDayOfEmail(): - INITIAL_STATUS = status('initial') - HACKER_IDs = loadIDs() - for index, ID in enumerate(HACKER_IDs): - # so that we aren't 0-based index - index = index + 1 - hacker = getHacker(ID) - validStatus = hasValidStatus(INITIAL_STATUS, hacker) - if validStatus: - r = s.post( - '{0}/api/hacker/email/dayOf/{1}'.format(API_URL, ID)) - if r.status_code != 200: - _print('cannot send email to {0}'.format( - ID), 1, index, len(HACKER_IDs)) - else: - _print('Sent email to {0}'.format( - ID), 3, index, len(HACKER_IDs)) - elif hacker is not None: - _print('Sent invalid status for {0}'.format( - ID), 1, index, len(HACKER_IDs)) - else: - _print('Could not find {0}'.format( - ID), 1, index, len(HACKER_IDs)) - - -def sendWeekOfEmail(): - INITIAL_STATUS = status('initial') - HACKER_IDs = loadIDs() - for index, ID in enumerate(HACKER_IDs): - # so that we aren't 0-based index - index = index + 1 - hacker = getHacker(ID) - validStatus = hasValidStatus(INITIAL_STATUS, hacker) - if validStatus: - r = s.post( - '{0}/api/hacker/email/weekOf/{1}'.format(API_URL, ID)) - if r.status_code != 200: - _print('Cannot send email to {0}'.format( - ID), 1, index, len(HACKER_IDs)) - else: - _print('Sent email to {0}'.format( - ID), 3, index, len(HACKER_IDs)) - elif hacker is not None: - _print('Invalid status for {0}'.format( - ID), 1, index, len(HACKER_IDs)) - else: - _print('Could not find {0}'.format( - ID), 1, index, len(HACKER_IDs)) - - -def downloadResume(): - INITIAL_STATUS = status('initial') - HACKER_IDs = loadIDs() - DOWNLOAD_DIR = getDownloadDirectory() - - for index, ID in enumerate(HACKER_IDs): - # so that we aren't 0-based index - index = index + 1 - hacker = getHacker(ID) - validStatus = hasValidStatus(INITIAL_STATUS, hacker) - if validStatus: - r = s.get( - '{0}/api/hacker/resume/{1}'.format(API_URL, ID)) - if r.status_code != 200: - _print('Could not find resume for {0}'.format( - ID), 1, index, len(HACKER_IDs)) - else: - resume = json.loads(r.content)['data']['resume'][0]['data'] - download_path = "{0}/{1}.pdf".format(DOWNLOAD_DIR, ID) - with open(download_path, "wb") as fh: - byte_data = bytearray(resume) - fh.write(byte_data) - _print('Downloaded resume for {0} to {1}'.format( - ID, download_path), 3, index, len(HACKER_IDs)) - elif hacker is not None: - _print('invalid status for {0}'.format( - ID), 3, index, len(HACKER_IDs)) - else: - _print('Could not find hacker {0}'.format( - ID), 1, index, len(HACKER_IDs)) - - -def inviteUsers(): - INVITES = loadInvites() - for index, invite in enumerate(INVITES): - index = index + 1 - r = s.post( - '{0}/api/account/invite/'.format(API_URL), invite) - if r.status_code != 200: - _print('Could not invite {0}, {1}'.format( - invite['email'], invite['accountType']), 1, index, len(INVITES)) - else: - _print('Invited {0}, {1}'.format( - invite['email'], invite['accountType']), 3, index, len(INVITES)) - - -def getHackers(): - CUR_STATUS = status('current') - DOWNLOAD_DIR = getDownloadDirectory() - results = search( - 'hacker', - [{'param': 'status', 'operation': 'equals', 'value': CUR_STATUS}] - ) - with open('{0}/hackerIDs_{1}.csv'.format(DOWNLOAD_DIR, CUR_STATUS), 'w') as out_file: - fieldnames = [ - 'id', - 'First Name', - 'Last Name', - 'Email', - 'School', - 'Degree', - 'Graduation Year', - 'Job Interest', - 'Github', - 'LinkedIn' - ] - csv_writer = csv.DictWriter(out_file, fieldnames=fieldnames) - csv_writer.writeheader() - for result in results: - csv_writer.writerow({ - 'id': result['id'], - 'First Name': result['accountId']['firstName'], - 'Last Name': result['accountId']['lastName'], - 'Email': result['accountId']['email'], - 'School': result['application']['general']['school'], - 'Degree': result['application']['general']['degree'], - 'Graduation Year': result['application']['general']['graduationYear'], - 'Job Interest': result['application']['general']['jobInterest'], - 'Github': result['application']['general']['URL']['github'], - 'LinkedIn': result['application']['general']['URL']['linkedIn'], - }) - - -if __name__ == "__main__": - # execute only if run as a script - chooseLogVerbosity() - login(s) - while True: - BATCH_ACTION = batchAction() - try: - if BATCH_ACTION == 'weekOf': - sendWeekOfEmail() - elif BATCH_ACTION == 'dayOf': - sendDayOfEmail() - elif BATCH_ACTION == 'updateStatus': - updateStatus() - elif BATCH_ACTION == 'downloadResume': - downloadResume() - elif BATCH_ACTION == 'inviteUsers': - inviteUsers() - elif BATCH_ACTION == 'getHackers': - getHackers() - elif BATCH_ACTION == 'acceptHackers': - acceptFromEmails() - print('Finished {0}'.format(BATCH_ACTION)) - except Exception as e: - _print('Failed to perform action {0}: {1}'.format( - BATCH_ACTION, e), 1) diff --git a/scripts/batch_scripts.py b/scripts/batch_scripts.py deleted file mode 100644 index 387aa51b..00000000 --- a/scripts/batch_scripts.py +++ /dev/null @@ -1,427 +0,0 @@ -#!/bin/bash/python3 -import base64 -from bson import ObjectId -import csv -import getpass -import json -import os -import readline -import requests -import subprocess -from typing import Any, Callable, List -import sys - -# Constants -VALID_STATUSES = { - '1': 'Applied', - '2': 'Accepted', - '3': 'Waitlisted', - '4': 'Declined', - '5': 'Confirmed', - '6': 'Withdrawn', - '7': 'Checked-in' -} -BATCH_ACTIONS = { - '1': 'updateStatus', - '2': 'dayOf', - '3': 'weekOf', - '4': 'downloadResume', - '5': 'inviteUsers', - '6': 'getHackers' -} -LOG_VERBOSITIES = { - '0': 'None', - '1': 'Error', - '2': 'Warning', - '3': 'Info' -} - -CHOSEN_VERBOSITY = 3 - - -API_URL = 'https://api.mchacks.ca' - - -s = requests.Session() - - -def _print(msg, msgType=3, index=None, total=None): - """ - Wrapper around print function such that we only print to the granularity that the user wants. - Also, allow for formatting of sequential print statements ex: (10/114) - """ - global CHOSEN_VERBOSITY - if msgType <= CHOSEN_VERBOSITY: - out_file = sys.stdout if msgType > 1 else sys.stderr - if index is None or total is None: - print('{0}: {1}'.format( - LOG_VERBOSITIES[str(msgType)], msg), file=out_file) - else: - print('({0}/{1}) {2}: {3}'.format(index, total, - LOG_VERBOSITIES[str(msgType)], msg), file=out_file) - - -def requestUntilSuccess( - string: str, - invalid_msg: str = 'Invalid input', - validInput: Callable[[Any], bool] = lambda x: x is not None, - transformInput: Callable[[str], Any] = lambda x: x -) -> str: - """ - Requests user input until validInput predicate is satisfied. - Returns the output of transformInput. - """ - user_input = None - while not validInput(user_input): - print('=====================================') - user_input = input(string) - if not validInput(user_input): - print(invalid_msg) - return transformInput(user_input) - - -def login(session=requests.Session()): - """ - Logs in a user to the inputted session, and returns the session. - """ - global API_URL - user_input = requestUntilSuccess( - 'Enter Target API (Default {0}): '.format(API_URL)) - if user_input != '': - API_URL = user_input - # Get credentials - username = requestUntilSuccess( - 'Enter credentials for {0}: '.format(API_URL)) - logged_in = False - - while not logged_in: - password = getpass.getpass("Password: ") - credentials = { - 'email': username, - 'password': password - } - r = session.post('{0}/api/auth/login'.format(API_URL), credentials) - if r.status_code != 200: - print("Incorrect password, please try again.") - else: - print('Logged in as {0}'.format(username)) - logged_in = True - return session - - -def chooseLogVerbosity(): - global CHOSEN_VERBOSITY - verbosity_list = ['{0}: {1}\n'.format(k, v) - for k, v in LOG_VERBOSITIES.items()] - chosen_verbosity = requestUntilSuccess( - 'Input log verbosity (default {0}):\n{1}'.format( - CHOSEN_VERBOSITY, ''.join(verbosity_list)), - 'Invalid verbosity', - lambda x: x == '' or x in LOG_VERBOSITIES.keys(), - lambda x: CHOSEN_VERBOSITY if x == '' else int(x) - ) - CHOSEN_VERBOSITY = chosen_verbosity - - -def loadInvites() -> List[str]: - """ - Load the list of invites provided by user inputted file path. - """ - # Get information about batch actions - invite_file = requestUntilSuccess( - 'Path to Invite CSV: ', - 'Invalid file', - lambda x: x is not None and os.path.isfile(x) and os.access(x, os.R_OK) - ) - - invites = [] - with open(invite_file, 'r') as csvfile: - reader = csv.DictReader(csvfile) - index = 1 - for row in reader: - index = index + 1 - email = row['email'] - accountType = row['accountType'] - if email is not None and accountType is not None: - invites.append({ - 'email': email, - 'accountType': accountType - }) - else: - _print('{2} is not a valid invite format'.format( - row), 1, index, len(reader)) - return invites - - -def loadIDs() -> List[str]: - """ - Load the list of IDs provided by user inputted file path. - """ - # Get information about batch actions - id_file = requestUntilSuccess( - 'Path to file to MongoIDs: ', - 'Invalid file', - lambda x: x is not None and os.path.isfile(x) and os.access(x, os.R_OK) - ) - - ids = [] - with open(id_file, 'r') as f: - rows = f.readlines() - for index, r in enumerate(rows): - index = index + 1 - r = r.strip() - if ObjectId.is_valid(r): - ids.append(r) - else: - _print('{2} is not a valid ObjectID'.format( - r), 1, index, len(rows)) - # remove duplicates - ids = list(set(ids)) - return ids - - -def getDownloadDirectory() -> str: - directory = requestUntilSuccess( - 'Directory to download files to: ', - 'Invalid directory', - lambda x: x is not None and os.path.isdir(x) and os.access(x, os.W_OK) - ) - directory.rstrip('/') - return directory - - -def status(prefixStr) -> str: - status_list = ['{0}: {1}\n'.format(k, v) - for k, v in VALID_STATUSES.items()] - initial_status = requestUntilSuccess( - 'Input {0} status:\n{1}'.format(prefixStr, ''.join(status_list)), - 'Invalid {0} status'.format(prefixStr), - lambda x: x in VALID_STATUSES.keys(), - lambda x: VALID_STATUSES[x] - ) - return initial_status - - -def batchAction() -> str: - status_list = ['{0}: {1}\n'.format(k, v) for k, v in BATCH_ACTIONS.items()] - batch_action = requestUntilSuccess( - 'Batch Action desired:\n{0}'.format(''.join(status_list)), - 'Invalid batch action', - lambda x: x in BATCH_ACTIONS.keys(), - lambda x: BATCH_ACTIONS[x] - ) - return batch_action - - -def getHacker(ID): - r = s.get('{0}/api/hacker/{1}'.format(API_URL, ID)) - if r.status_code != 200: - return None - else: - hackerInfo = json.loads(r.content)['data'] - return hackerInfo - - -def hasValidStatus(status, hackerInfo): - if hackerInfo is not None and hackerInfo['status'] == status: - return True - else: - return False - - -def search(model: str = 'hacker', query=[], expand: bool = True): - q = json.dumps(query) - expand = 'true' if expand else 'false' - r = s.get( - '{0}/api/search?model={1}&q={2}&expand={3}'.format(API_URL, model, q, expand)) - if r.status_code != 200: - _print('Could not perform search (Status code {0})'.format( - r.status_code), 1) - return [] - else: - results = json.loads(r.content)['data'] - return results - - -def updateStatus(): - INITIAL_STATUS = status('initial') - NEW_STATUS = status('new') - HACKER_IDs = loadIDs() - for index, ID in enumerate(HACKER_IDs): - # so that we aren't 0-based index - index = index + 1 - hacker = getHacker(ID) - validStatus = hasValidStatus(INITIAL_STATUS, hacker) - if validStatus: - r = s.patch('{0}/api/hacker/status/{1}'.format(API_URL, ID), - {"status": NEW_STATUS}) - if r.status_code != 200: - _print('cannot update status for {0}'.format( - ID), 1, index, len(HACKER_IDs)) - else: - _print('{0} {1}'.format( - NEW_STATUS, ID), 3, index, len(HACKER_IDs)) - elif hacker is not None: - _print('invalid status for {0}'.format( - ID), 1, index, len(HACKER_IDs)) - else: - _print('could not find {0}'.format( - ID), 1, index, len(HACKER_IDs)) - - -def sendDayOfEmail(): - INITIAL_STATUS = status('initial') - HACKER_IDs = loadIDs() - for index, ID in enumerate(HACKER_IDs): - # so that we aren't 0-based index - index = index + 1 - hacker = getHacker(ID) - validStatus = hasValidStatus(INITIAL_STATUS, hacker) - if validStatus: - r = s.post( - '{0}/api/hacker/email/dayOf/{1}'.format(API_URL, ID)) - if r.status_code != 200: - _print('cannot send email to {0}'.format( - ID), 1, index, len(HACKER_IDs)) - else: - _print('Sent email to {0}'.format( - ID), 3, index, len(HACKER_IDs)) - elif hacker is not None: - _print('Sent invalid status for {0}'.format( - ID), 1, index, len(HACKER_IDs)) - else: - _print('Could not find {0}'.format( - ID), 1, index, len(HACKER_IDs)) - - -def sendWeekOfEmail(): - INITIAL_STATUS = status('initial') - HACKER_IDs = loadIDs() - for index, ID in enumerate(HACKER_IDs): - # so that we aren't 0-based index - index = index + 1 - hacker = getHacker(ID) - validStatus = hasValidStatus(INITIAL_STATUS, hacker) - if validStatus: - r = s.post( - '{0}/api/hacker/email/weekOf/{1}'.format(API_URL, ID)) - if r.status_code != 200: - _print('Cannot send email to {0}'.format( - ID), 1, index, len(HACKER_IDs)) - else: - _print('Sent email to {0}'.format( - ID), 3, index, len(HACKER_IDs)) - elif hacker is not None: - _print('Invalid status for {0}'.format( - ID), 1, index, len(HACKER_IDs)) - else: - _print('Could not find {0}'.format( - ID), 1, index, len(HACKER_IDs)) - - -def downloadResume(): - INITIAL_STATUS = status('initial') - HACKER_IDs = loadIDs() - DOWNLOAD_DIR = getDownloadDirectory() - - for index, ID in enumerate(HACKER_IDs): - # so that we aren't 0-based index - index = index + 1 - hacker = getHacker(ID) - validStatus = hasValidStatus(INITIAL_STATUS, hacker) - if validStatus: - r = s.get( - '{0}/api/hacker/resume/{1}'.format(API_URL, ID)) - if r.status_code != 200: - _print('Could not find resume for {0}'.format( - ID), 1, index, len(HACKER_IDs)) - else: - resume = json.loads(r.content)['data']['resume'][0]['data'] - download_path = "{0}/{1}.pdf".format(DOWNLOAD_DIR, ID) - with open(download_path, "wb") as fh: - byte_data = bytearray(resume) - fh.write(byte_data) - _print('Downloaded resume for {0} to {1}'.format( - ID, download_path), 3, index, len(HACKER_IDs)) - elif hacker is not None: - _print('invalid status for {0}'.format( - ID), 3, index, len(HACKER_IDs)) - else: - _print('Could not find hacker {0}'.format( - ID), 1, index, len(HACKER_IDs)) - - -def inviteUsers(): - INVITES = loadInvites() - for index, invite in enumerate(INVITES): - index = index + 1 - r = s.post( - '{0}/api/account/invite/'.format(API_URL), invite) - if r.status_code != 200: - _print('Could not invite {0}, {1}'.format( - invite['email'], invite['accountType']), 1, index, len(INVITES)) - else: - _print('Invited {0}, {1}'.format( - invite['email'], invite['accountType']), 3, index, len(INVITES)) - - -def getHackers(): - CUR_STATUS = status('current') - DOWNLOAD_DIR = getDownloadDirectory() - results = search( - 'hacker', - [{'param': 'status', 'operation': 'equals', 'value': CUR_STATUS}] - ) - with open('{0}/hackerIDs_{1}.csv'.format(DOWNLOAD_DIR, CUR_STATUS), 'w') as out_file: - fieldnames = [ - 'id', - 'First Name', - 'Last Name', - 'Email', - 'School', - 'Degree', - 'Graduation Year', - 'Job Interest', - 'Github', - 'LinkedIn' - ] - csv_writer = csv.DictWriter(out_file, fieldnames=fieldnames) - csv_writer.writeheader() - for result in results: - csv_writer.writerow({ - 'id': result['id'], - 'First Name': result['accountId']['firstName'], - 'Last Name': result['accountId']['lastName'], - 'Email': result['accountId']['email'], - 'School': result['application']['general']['school'], - 'Degree': result['application']['general']['degree'], - 'Graduation Year': result['application']['general']['graduationYear'], - 'Job Interest': result['application']['general']['jobInterest'], - 'Github': result['application']['general']['URL']['github'], - 'LinkedIn': result['application']['general']['URL']['linkedIn'], - }) - - -if __name__ == "__main__": - # execute only if run as a script - chooseLogVerbosity() - login(s) - while True: - BATCH_ACTION = batchAction() - try: - if BATCH_ACTION == 'weekOf': - sendWeekOfEmail() - elif BATCH_ACTION == 'dayOf': - sendDayOfEmail() - elif BATCH_ACTION == 'updateStatus': - updateStatus() - elif BATCH_ACTION == 'downloadResume': - downloadResume() - elif BATCH_ACTION == 'inviteUsers': - inviteUsers() - elif BATCH_ACTION == 'getHackers': - getHackers() - print('Finished {0}'.format(BATCH_ACTION)) - except Exception as e: - _print('Failed to perform action {0}: {1}'.format( - BATCH_ACTION, e), 1) From bbeb3490a56893bdc9f421770577f9cc41ae23f4 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Mon, 3 Jan 2022 00:33:32 -0500 Subject: [PATCH 31/72] refactor: add linting rules for typescript and aliases for folders. - add typescript-eslint to allow linting of typescript code. - use the array-type rule to enforce the usage of Array instead of Type[]. - use the no-require-imports to enforce the usage of the ES6 import (you can no longer call require() without the app throwing an error). - disable the no explicit any rule temporarily (we should be passing unknown, but for now we will keep it this way until we come up with better solutions to where any is declared as a type explicity). - add aliases for folders - TODO: allow the usage of this feature. - although the aliases exist when compiling with ts-node-dev an error is thrown. - a likely solution is using the module-alias package to declare the appropriate paths in the compiled javascript. --- .eslintrc | 19 +- .prettierrc | 4 +- package-lock.json | 905 +++++++++++++++++++++++++++++++++++++++++++++- package.json | 9 +- tsconfig.json | 15 +- 5 files changed, 927 insertions(+), 25 deletions(-) diff --git a/.eslintrc b/.eslintrc index bc137efb..2e85da1f 100644 --- a/.eslintrc +++ b/.eslintrc @@ -5,15 +5,26 @@ "node": true, "mocha": true }, + "parser": "@typescript-eslint/parser", "parserOptions": { - "ecmaVersion": 2017, + "ecmaVersion": 2019, "sourceType": "module" }, "plugins": [ - "prettier" + "prettier", + "@typescript-eslint" ], "extends": [ "eslint:recommended", - "prettier" - ] + "prettier", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + "@typescript-eslint/no-require-imports": ["error"], + "@typescript-eslint/array-type": ["error", { + "default": "generic" + }], + "@typescript-eslint/no-explicit-any": "off" + } } diff --git a/.prettierrc b/.prettierrc index 6577547b..12750752 100644 --- a/.prettierrc +++ b/.prettierrc @@ -4,5 +4,7 @@ "singleQuote": false, "semi": true, "arrowParens": "always", - "jsxBracketSameLine": false + "jsxBracketSameLine": false, + "bracketSpacing": true, + "trailingComma": "none" } diff --git a/package-lock.json b/package-lock.json index 91a0c0e9..c84afc0c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,6 +41,9 @@ }, "devDependencies": { "@types/bcrypt": "^5.0.0", + "@types/cookie-parser": "^1.4.2", + "@types/cookie-session": "^2.0.44", + "@types/cors": "^2.8.12", "@types/express": "^4.17.13", "@types/express-winston": "^4.0.0", "@types/google-cloud__storage": "^1.7.2", @@ -53,6 +56,8 @@ "@types/qrcode": "^1.4.2", "@types/superagent": "^4.1.13", "@types/validator": "^13.7.0", + "@typescript-eslint/eslint-plugin": "^5.8.1", + "@typescript-eslint/parser": "^5.8.1", "apidoc": "^0.28.1", "chai": "^4.3.4", "chai-http": "^4.3.0", @@ -73,21 +78,21 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.0.tgz", - "integrity": "sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz", + "integrity": "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.15.7", + "@babel/helper-validator-identifier": "^7.16.7", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -391,6 +396,41 @@ "node-pre-gyp": "bin/node-pre-gyp" } }, + "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/@sindresorhus/is": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", @@ -473,12 +513,37 @@ "@types/node": "*" } }, + "node_modules/@types/cookie-parser": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.2.tgz", + "integrity": "sha512-uwcY8m6SDQqciHsqcKDGbo10GdasYsPCYkH3hVegj9qAah6pX5HivOnOuI3WYmyQMnOATV39zv/Ybs0bC/6iVg==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/cookie-session": { + "version": "2.0.44", + "resolved": "https://registry.npmjs.org/@types/cookie-session/-/cookie-session-2.0.44.tgz", + "integrity": "sha512-3DheOZ41pql6raSIkqEPphJdhA2dX2bkS+s2Qacv8YMKkoCbAIEXbsDil7351ARzMqvfyDUGNeHGiRZveIzhqQ==", + "dev": true, + "dependencies": { + "@types/express": "*", + "@types/keygrip": "*" + } + }, "node_modules/@types/cookiejar": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.2.tgz", "integrity": "sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==", "dev": true }, + "node_modules/@types/cors": { + "version": "2.8.12", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", + "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", + "dev": true + }, "node_modules/@types/express": { "version": "4.17.13", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", @@ -522,6 +587,12 @@ "@types/request": "*" } }, + "node_modules/@types/json-schema": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", + "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", + "dev": true + }, "node_modules/@types/jsonwebtoken": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.6.tgz", @@ -531,6 +602,12 @@ "@types/node": "*" } }, + "node_modules/@types/keygrip": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/keygrip/-/keygrip-1.0.2.tgz", + "integrity": "sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw==", + "dev": true + }, "node_modules/@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -694,6 +771,268 @@ "resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.3.tgz", "integrity": "sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw==" }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.8.1.tgz", + "integrity": "sha512-wTZ5oEKrKj/8/366qTM366zqhIKAp6NCMweoRONtfuC07OAU9nVI2GZZdqQ1qD30WAAtcPdkH+npDwtRFdp4Rw==", + "dev": true, + "dependencies": { + "@typescript-eslint/experimental-utils": "5.8.1", + "@typescript-eslint/scope-manager": "5.8.1", + "debug": "^4.3.2", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.1.8", + "regexpp": "^3.2.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/experimental-utils": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.8.1.tgz", + "integrity": "sha512-fbodVnjIDU4JpeXWRDsG5IfIjYBxEvs8EBO8W1+YVdtrc2B9ppfof5sZhVEDOtgTfFHnYQJDI8+qdqLYO4ceww==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.8.1", + "@typescript-eslint/types": "5.8.1", + "@typescript-eslint/typescript-estree": "5.8.1", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/experimental-utils/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/@typescript-eslint/eslint-plugin/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/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/@typescript-eslint/parser": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.8.1.tgz", + "integrity": "sha512-K1giKHAjHuyB421SoXMXFHHVI4NdNY603uKw92++D3qyxSeYvC10CBJ/GE5Thpo4WTUvu1mmJI2/FFkz38F2Gw==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.8.1", + "@typescript-eslint/types": "5.8.1", + "@typescript-eslint/typescript-estree": "5.8.1", + "debug": "^4.3.2" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/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/@typescript-eslint/scope-manager": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.8.1.tgz", + "integrity": "sha512-DGxJkNyYruFH3NIZc3PwrzwOQAg7vvgsHsHCILOLvUpupgkwDZdNq/cXU3BjF4LNrCsVg0qxEyWasys5AiJ85Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.8.1", + "@typescript-eslint/visitor-keys": "5.8.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.8.1.tgz", + "integrity": "sha512-L/FlWCCgnjKOLefdok90/pqInkomLnAcF9UAzNr+DSqMC3IffzumHTQTrINXhP1gVp9zlHiYYjvozVZDPleLcA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.8.1.tgz", + "integrity": "sha512-26lQ8l8tTbG7ri7xEcCFT9ijU5Fk+sx/KRRyyzCv7MQ+rZZlqiDPtMKWLC8P7o+dtCnby4c+OlxuX1tp8WfafQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.8.1", + "@typescript-eslint/visitor-keys": "5.8.1", + "debug": "^4.3.2", + "globby": "^11.0.4", + "is-glob": "^4.0.3", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/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/@typescript-eslint/visitor-keys": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.8.1.tgz", + "integrity": "sha512-SWgiWIwocK6NralrJarPZlWdr0hZnj5GXHIgfdm8hNkyKvpeQuFyLP6YjSIe9kf3YBIfU6OHSZLYkQ+smZwtNg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.8.1", + "eslint-visitor-keys": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz", + "integrity": "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/@ungap/promise-all-settled": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", @@ -941,6 +1280,15 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/arrify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", @@ -2095,6 +2443,18 @@ "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.2.tgz", "integrity": "sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg==" }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -2777,6 +3137,22 @@ "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", "dev": true }, + "node_modules/fast-glob": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", + "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8" + } + }, "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", @@ -2794,6 +3170,15 @@ "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig==" }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, "node_modules/fecha": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz", @@ -3174,6 +3559,35 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globby": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", + "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/google-auth-library": { "version": "7.11.0", "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.11.0.tgz", @@ -4233,12 +4647,34 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", "engines": { - "node": ">= 0.6" + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + }, + "engines": { + "node": ">=8.6" } }, "node_modules/mime": { @@ -5453,6 +5889,15 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/pathval": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", @@ -5876,6 +6321,26 @@ "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/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -6126,6 +6591,16 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "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", @@ -6140,6 +6615,29 @@ "url": "https://github.com/sponsors/isaacs" } }, + "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", @@ -6379,6 +6877,15 @@ "is-arrayish": "^0.3.1" } }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/slice-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", @@ -6925,6 +7432,27 @@ "node": ">=0.6.x" } }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, "node_modules/tsyringe": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.6.0.tgz", @@ -7676,18 +8204,18 @@ } }, "@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", "dev": true }, "@babel/highlight": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.0.tgz", - "integrity": "sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz", + "integrity": "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.15.7", + "@babel/helper-validator-identifier": "^7.16.7", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -7927,6 +8455,32 @@ "tar": "^6.1.11" } }, + "@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" + } + }, "@sindresorhus/is": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", @@ -8000,12 +8554,37 @@ "@types/node": "*" } }, + "@types/cookie-parser": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.2.tgz", + "integrity": "sha512-uwcY8m6SDQqciHsqcKDGbo10GdasYsPCYkH3hVegj9qAah6pX5HivOnOuI3WYmyQMnOATV39zv/Ybs0bC/6iVg==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, + "@types/cookie-session": { + "version": "2.0.44", + "resolved": "https://registry.npmjs.org/@types/cookie-session/-/cookie-session-2.0.44.tgz", + "integrity": "sha512-3DheOZ41pql6raSIkqEPphJdhA2dX2bkS+s2Qacv8YMKkoCbAIEXbsDil7351ARzMqvfyDUGNeHGiRZveIzhqQ==", + "dev": true, + "requires": { + "@types/express": "*", + "@types/keygrip": "*" + } + }, "@types/cookiejar": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.2.tgz", "integrity": "sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==", "dev": true }, + "@types/cors": { + "version": "2.8.12", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", + "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", + "dev": true + }, "@types/express": { "version": "4.17.13", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", @@ -8048,6 +8627,12 @@ "@types/request": "*" } }, + "@types/json-schema": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", + "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", + "dev": true + }, "@types/jsonwebtoken": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.6.tgz", @@ -8057,6 +8642,12 @@ "@types/node": "*" } }, + "@types/keygrip": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/keygrip/-/keygrip-1.0.2.tgz", + "integrity": "sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw==", + "dev": true + }, "@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -8220,6 +8811,165 @@ "resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.3.tgz", "integrity": "sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw==" }, + "@typescript-eslint/eslint-plugin": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.8.1.tgz", + "integrity": "sha512-wTZ5oEKrKj/8/366qTM366zqhIKAp6NCMweoRONtfuC07OAU9nVI2GZZdqQ1qD30WAAtcPdkH+npDwtRFdp4Rw==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "5.8.1", + "@typescript-eslint/scope-manager": "5.8.1", + "debug": "^4.3.2", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.1.8", + "regexpp": "^3.2.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "dependencies": { + "@typescript-eslint/experimental-utils": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.8.1.tgz", + "integrity": "sha512-fbodVnjIDU4JpeXWRDsG5IfIjYBxEvs8EBO8W1+YVdtrc2B9ppfof5sZhVEDOtgTfFHnYQJDI8+qdqLYO4ceww==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.8.1", + "@typescript-eslint/types": "5.8.1", + "@typescript-eslint/typescript-estree": "5.8.1", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "dependencies": { + "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" + } + } + } + }, + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "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 + } + } + }, + "@typescript-eslint/parser": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.8.1.tgz", + "integrity": "sha512-K1giKHAjHuyB421SoXMXFHHVI4NdNY603uKw92++D3qyxSeYvC10CBJ/GE5Thpo4WTUvu1mmJI2/FFkz38F2Gw==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.8.1", + "@typescript-eslint/types": "5.8.1", + "@typescript-eslint/typescript-estree": "5.8.1", + "debug": "^4.3.2" + }, + "dependencies": { + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "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 + } + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.8.1.tgz", + "integrity": "sha512-DGxJkNyYruFH3NIZc3PwrzwOQAg7vvgsHsHCILOLvUpupgkwDZdNq/cXU3BjF4LNrCsVg0qxEyWasys5AiJ85Q==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.8.1", + "@typescript-eslint/visitor-keys": "5.8.1" + } + }, + "@typescript-eslint/types": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.8.1.tgz", + "integrity": "sha512-L/FlWCCgnjKOLefdok90/pqInkomLnAcF9UAzNr+DSqMC3IffzumHTQTrINXhP1gVp9zlHiYYjvozVZDPleLcA==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.8.1.tgz", + "integrity": "sha512-26lQ8l8tTbG7ri7xEcCFT9ijU5Fk+sx/KRRyyzCv7MQ+rZZlqiDPtMKWLC8P7o+dtCnby4c+OlxuX1tp8WfafQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.8.1", + "@typescript-eslint/visitor-keys": "5.8.1", + "debug": "^4.3.2", + "globby": "^11.0.4", + "is-glob": "^4.0.3", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "dependencies": { + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "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 + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.8.1.tgz", + "integrity": "sha512-SWgiWIwocK6NralrJarPZlWdr0hZnj5GXHIgfdm8hNkyKvpeQuFyLP6YjSIe9kf3YBIfU6OHSZLYkQ+smZwtNg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.8.1", + "eslint-visitor-keys": "^3.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz", + "integrity": "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==", + "dev": true + } + } + }, "@ungap/promise-all-settled": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", @@ -8410,6 +9160,12 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, "arrify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", @@ -9331,6 +10087,15 @@ "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.2.tgz", "integrity": "sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg==" }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -9859,6 +10624,19 @@ "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", "dev": true }, + "fast-glob": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", + "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, "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", @@ -9876,6 +10654,15 @@ "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig==" }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, "fecha": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz", @@ -10159,6 +10946,28 @@ "type-fest": "^0.20.2" } }, + "globby": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", + "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + }, + "dependencies": { + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + } + } + }, "google-auth-library": { "version": "7.11.0", "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.11.0.tgz", @@ -10975,11 +11784,27 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" }, + "micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, "mime": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", @@ -11967,6 +12792,12 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, "pathval": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", @@ -12280,6 +13111,12 @@ "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 + }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -12471,6 +13308,12 @@ } } }, + "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", @@ -12479,6 +13322,15 @@ "glob": "^7.1.3" } }, + "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", @@ -12668,6 +13520,12 @@ "is-arrayish": "^0.3.1" } }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, "slice-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", @@ -13088,6 +13946,23 @@ "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==" }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, "tsyringe": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.6.0.tgz", diff --git a/package.json b/package.json index 3653ea9f..70954f3d 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,8 @@ "deploy": "NODE_ENV=deployment node ./bin/www.js", "test": "DEBUG=hackboard:* NODE_ENV=test mocha --parallel --reporter spec tests/**.js --exit", "docs": "apidoc -i ./routes -o ./docs/api/", - "format": "prettier --write '**/*.js'", - "lint": "eslint --fix '**/*.js'" + "format": "prettier --write 'src/**/*.ts'", + "lint": "eslint --fix 'src/**/*.ts'" }, "dependencies": { "@decorators/di": "^1.0.3", @@ -45,6 +45,9 @@ }, "devDependencies": { "@types/bcrypt": "^5.0.0", + "@types/cookie-parser": "^1.4.2", + "@types/cookie-session": "^2.0.44", + "@types/cors": "^2.8.12", "@types/express": "^4.17.13", "@types/express-winston": "^4.0.0", "@types/google-cloud__storage": "^1.7.2", @@ -57,6 +60,8 @@ "@types/qrcode": "^1.4.2", "@types/superagent": "^4.1.13", "@types/validator": "^13.7.0", + "@typescript-eslint/eslint-plugin": "^5.8.1", + "@typescript-eslint/parser": "^5.8.1", "apidoc": "^0.28.1", "chai": "^4.3.4", "chai-http": "^4.3.0", diff --git a/tsconfig.json b/tsconfig.json index 2764dcb6..a4887de7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,12 +9,21 @@ "removeComments": true, "preserveConstEnums": true, "sourceMap": true, - "outDir": "dist/", "esModuleInterop": true, "moduleResolution": "node", "resolveJsonModule": true, - "emitDecoratorMetadata": true + "emitDecoratorMetadata": true, + "baseUrl": "src/", + "paths": { + "@models/*": ["models/*"], + "@controllers/*": ["controllers/*"], + "@services/*": ["services/*"], + "@middlewares/*": ["middlewares/*"], + "@strategies/*": ["strategies/*"], + "@constants/*": ["constants/*"], + "@assets/*": ["assets/*"] + } }, "include": ["./src/**/*", "./.env"], - "exclude": ["node_modules", "**/*.spec.ts", ".vscode", ".github", "docs", "scripts", "./src/tests"] + "exclude": ["node_modules", "src/**/*.spec.ts", ".vscode", ".github", "docs", "scripts", "./src/tests"] } From 99c4737c22aad0662d955ca2974ec1aa376be791 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Mon, 3 Jan 2022 01:01:54 -0500 Subject: [PATCH 32/72] fix: bug fixes in the team, logging, search, and hacker services. - team service: - amend hackers (team members) to result on #findByIdentifier and #findByName. - add explicit return definitions to methods that did not have them. - fix bug where the removeMember function does not work due to the query. - the previous code should work logically, we should investigate further. - consider opening an issue on the typeorm github repository? - search service: - rename parameters to param per the frontend specification. - remove limit and skipping for now. - load relation identifiers to allow relation querying for accounts and teams on the frontend. - add return type definition. - logger service: - change express winston request logging output from: - request method - request url to: - response status code - request method - response time - request url - hacker service: - change #findByIdentifier method to use query builder. - this is to allow the loading of the team as a relation identifier instead of the team object itself. --- src/services/hacker.service.ts | 19 ++++++++---- src/services/logger.service.ts | 9 +++--- src/services/search.service.ts | 41 ++++++++++---------------- src/services/team.service.ts | 53 +++++++++++++++------------------- 4 files changed, 59 insertions(+), 63 deletions(-) diff --git a/src/services/hacker.service.ts b/src/services/hacker.service.ts index 871db7f6..c30c9ee2 100644 --- a/src/services/hacker.service.ts +++ b/src/services/hacker.service.ts @@ -18,10 +18,19 @@ export class HackerService { public async findByIdentifier( identifier: number ): Promise { - return await this.hackerRepository.findOne({ - relations: ["account"], - where: { account: { identifier: identifier } } - }); + /** + * This code finds the hacker by it's identifier, loads the account data, and + * instead of loading the team as a json, simply returns the identifier. + * This approach gives us the best of both worlds. + */ + return await this.hackerRepository + .createQueryBuilder("hacker") + .where("hacker.identifier = :identifier", { + identifier: identifier + }) + .loadAllRelationIds({ relations: ["team"] }) + .leftJoinAndSelect("hacker.account", "account") + .getOne(); } public async save(hacker: Hacker): Promise { @@ -46,7 +55,7 @@ export class HackerService { .set({ application: () => `jsonb_set(application,${key},${value})` }) - .where("accountIdentifier = :identifier", { + .where("identifier = :identifier", { identifier: identifier }) .execute(); diff --git a/src/services/logger.service.ts b/src/services/logger.service.ts index 785cbe11..63e7e736 100755 --- a/src/services/logger.service.ts +++ b/src/services/logger.service.ts @@ -27,9 +27,9 @@ export class LoggerService { winston.format.timestamp({ format: "MM/D/YYYY HH:MM:SS" }), - winston.format.printf((info) => { - return `${info.timestamp} [${info.level}] : ${info.message}`; - }) + winston.format.printf( + (info) => `${info.timestamp} [${info.level}] : ${info.message}` + ) ); this.logger = winston.createLogger({ @@ -40,7 +40,8 @@ export class LoggerService { this.requestLogger = expressWinston.logger({ transports: [new winston.transports.Console()], format: format, - colorize: !envService.isProduction() + colorize: !envService.isProduction(), + msg: `{{res.statusCode}} {{req.method}} {{res.responseTime}}ms {{req.url}}` }); this.errorLogger = expressWinston.errorLogger({ diff --git a/src/services/search.service.ts b/src/services/search.service.ts index 4cdbe9e5..1931e098 100644 --- a/src/services/search.service.ts +++ b/src/services/search.service.ts @@ -8,39 +8,30 @@ export class SearchService { this.connection = getConnection(); } - public executeQuery( - model: any, - query: Array, - page: number, - limit: number, - sort: string, - sort_by: string, - shouldExpand: boolean = false - ) { - var builder = this.connection - .createQueryBuilder() - .relation(model) - .select(); + public async executeQuery( + model: string, + query: any + ): Promise> { + const metadata = this.connection.getMetadata(model).target; + let builder = this.connection + .getRepository(metadata) + .createQueryBuilder(model) + .loadAllRelationIds(); + for (const element in query) { const { - parameter, + param, value, operation - }: { parameter: any; value: any; operation: string } = query[ - element - ]; + }: { param: any; value: any; operation: string } = query[element]; //TODO: Ensure santitized input for operation and value? - builder = builder.where(`:${parameter}${operation}${value}`, { - parameter, - value + builder = builder.andWhere(`${param} ${operation} :value`, { + value: value }); } - //TODO: Implement sorting by ascending, descending. - return builder - .limit(limit) - .skip(limit * page) - .getMany(); + //TODO: Implement limits (limit()), skipping (skip()), and sorting by ascending, descending (orderBy()). + return builder.getMany(); } } diff --git a/src/services/team.service.ts b/src/services/team.service.ts index 29dd635e..0084d8f9 100644 --- a/src/services/team.service.ts +++ b/src/services/team.service.ts @@ -12,20 +12,28 @@ export class TeamService { this.teamRepository = getRepository(Team); } - public async findByIdentifier(identifier: number) { - return await this.teamRepository.findOne(identifier); + public async findByIdentifier( + identifier: number + ): Promise { + return await this.teamRepository.findOne(identifier, { + relations: ["members", "members.account"] + }); } - public async findByName(name: string) { - return await this.teamRepository.findOne({ where: { name: name } }); + public async findByName(name: string): Promise { + return await this.teamRepository.findOne({ + where: { name: name }, + relations: ["members", "members.account"] + }); } - public async findByHacker({ account }: Hacker) { - const identifier = account.identifier; + public async findByHacker({ + account: { identifier } + }: Hacker): Promise { return await this.teamRepository .createQueryBuilder("team") - .leftJoinAndSelect("team.hackers", "hacker") - .where("hacker.accountIdentifier = :identifier", { identifier }) + .leftJoinAndSelect("team.members", "hacker") + .where("hacker.identifier = :identifier", { identifier }) .getOne(); } @@ -35,10 +43,10 @@ export class TeamService { ): Promise { const team = await this.findByIdentifier(identifier); - if (team && team.hackers.length < 4) { + if (team && team.members.length < 4) { await this.teamRepository .createQueryBuilder() - .relation("hackers") + .relation("members") .of(team) .add(hacker); return true; @@ -47,25 +55,12 @@ export class TeamService { return false; } - public async removeMember( - identifier: number, - hacker: Hacker - ): Promise { - const team = await this.findByIdentifier(identifier); - - if (team) { - await this.teamRepository - .createQueryBuilder() - .relation("hackers") - .of(team) - .remove(hacker); - // This team had 1 hacker left, and we removed them just above, thus we delete it. - if (team.hackers.length == 1) - await this.teamRepository.remove(team); - return true; - } - - return false; + public async removeMember(hacker: Hacker): Promise { + await this.teamRepository + .createQueryBuilder("team") + .relation(Hacker, "team") + .of(hacker) + .set({ team: null }); } public async update( From 8b16effdcbfdbda311e0c074052b0c2930eaad81 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Mon, 3 Jan 2022 01:23:03 -0500 Subject: [PATCH 33/72] feat: hacker status and user type as enums in the constants file. --- src/constants/general.constant.ts | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/constants/general.constant.ts b/src/constants/general.constant.ts index 74f4d8cd..db62d44c 100644 --- a/src/constants/general.constant.ts +++ b/src/constants/general.constant.ts @@ -5,6 +5,18 @@ const HACKATHON_NAME = "McHacks"; const DEVPOST_REGEX = /^(http(s)?:(\/\/)?)?(www\.)?(([-a-zA-Z0-9@:%._\+~#=]{2,256}\.)?devpost\.com)\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/; // from https://emailregex.com const EMAIL_REGEX = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + +enum HackerStatus { + None = "None", + Applied = "Applied", + Accepted = "Accepted", + Waitlisted = "Waitlisted", + Declined = "Declined", + Confirmed = "Confirmed", + Withdrawn = "Withdrawn", + CheckedIn = "Checked-in" +} + const HACKER_STATUS_NONE = "None"; const HACKER_STATUS_APPLIED = "Applied"; const HACKER_STATUS_ACCEPTED = "Accepted"; @@ -91,6 +103,13 @@ enum AttendancePreference { InPerson = "In Person" } +enum UserType { + Staff = "Staff", + Sponsor = "Sponsor", + Volunteer = "Volunteer", + Hacker = "Hacker" +} + // Enums (must match with frontend) const JOB_INTERESTS = ["Internship", "Full Time", "None"]; const SHIRT_SIZES = ["XS", "S", "M", "L", "XL", "XXL"]; @@ -201,5 +220,10 @@ export { SAMPLE_DIET_RESTRICTIONS, CONFIRMATION_TYPES, CONFIRMATION_TYPE_INVITE, - CONFIRMATION_TYPE_ORGANIC + CONFIRMATION_TYPE_ORGANIC, + UserType, + HackerStatus, + JobInterest, + ShirtSize, + AttendancePreference }; From d0d4cc77e5321f67492102367e30bfb901c32231 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Mon, 3 Jan 2022 01:46:26 -0500 Subject: [PATCH 34/72] fix: linting errors, code cleanup, small relational fixes. - add column name to @JoinColumn() attribute. - fix linting error with array declarations. - code cleanup on unused method in the hacker model & remove the import of all constants when we can selectively perform it. - remove unused imports from typeorm & class-validator. --- src/models/account.model.ts | 25 +++++------------ src/models/application.model.ts | 10 +++---- src/models/bus.model.ts | 5 ++-- src/models/hacker.model.ts | 50 ++++++--------------------------- src/models/sponsor.model.ts | 4 +-- src/models/team.model.ts | 18 ++++++------ src/models/travel.model.ts | 11 ++++---- 7 files changed, 40 insertions(+), 83 deletions(-) diff --git a/src/models/account.model.ts b/src/models/account.model.ts index 34a6dd43..2e428d36 100644 --- a/src/models/account.model.ts +++ b/src/models/account.model.ts @@ -9,7 +9,7 @@ import { IsString, Length } from "class-validator"; -import * as Constants from "../constants/general.constant"; +import { UserType } from "../constants/general.constant"; import { classToPlain, Exclude } from "class-transformer"; @Entity() @@ -43,18 +43,17 @@ class Account { @Length(8, 255) password: string; - @Column() - @IsString() + @Column({ array: true }) dietaryRestrictions: string; @Column({ default: false }) confirmed: boolean; @Column({ - enum: Constants.EXTENDED_USER_TYPES, - default: Constants.HACKER + enum: UserType, + default: UserType.Hacker }) - @IsEnum(Constants.EXTENDED_USER_TYPES) + @IsEnum(UserType) accountType: string; @Column("date", { nullable: false }) @@ -78,23 +77,13 @@ class Account { return compareSync(password, this.password); } - /** - * Returns if the accountType corresponds to a sponsor - */ - isSponsor() { - return ( - Constants.SPONSOR_TIERS.includes(this.accountType) || - this.accountType == Constants.SPONSOR - ); - } - /** * Calculates the user's age */ getAge() { // birthday is a date - var ageDifMs = Date.now() - this.birthDate.getTime(); - var ageDate = new Date(ageDifMs); // miliseconds from epoch + const ageDifMs = Date.now() - this.birthDate.getTime(); + const ageDate = new Date(ageDifMs); // miliseconds from epoch return Math.abs(ageDate.getUTCFullYear() - 1970); } } diff --git a/src/models/application.model.ts b/src/models/application.model.ts index 4af86c0c..cba8c502 100644 --- a/src/models/application.model.ts +++ b/src/models/application.model.ts @@ -1,4 +1,4 @@ -import { IsInt, IsJSON, IsString, Max } from "class-validator"; +import { IsInt } from "class-validator"; import { Entity, PrimaryGeneratedColumn, @@ -12,7 +12,7 @@ export interface ApplicationSchema { general: { school: string; degree: string; - fieldOfStudy: string[]; + fieldOfStudy: Array; graduationYear: number; jobInterest: string; URL: { @@ -26,7 +26,7 @@ export interface ApplicationSchema { }; }; shortAnswer: { - skills: string[]; + skills: Array; //any miscelaneous comments that the user has comments: string; //"Why do you want to come to our hackathon?" @@ -36,7 +36,7 @@ export interface ApplicationSchema { previousHackathons: number; }; other: { - ethnicity: string[]; + ethnicity: Array; privacyPolicy: boolean; codeOfConduct: boolean; }; @@ -71,7 +71,7 @@ class Application { () => Hacker, (hacker: Hacker) => hacker.application ) - @JoinColumn() + @JoinColumn({ name: "identifier" }) hacker: Hacker; } diff --git a/src/models/bus.model.ts b/src/models/bus.model.ts index 2731370f..d4fc9f30 100644 --- a/src/models/bus.model.ts +++ b/src/models/bus.model.ts @@ -1,6 +1,5 @@ import { Entity, - BaseEntity, Column, ManyToOne, JoinColumn, @@ -29,8 +28,8 @@ class Bus { capacity: number; @ManyToOne(() => Hacker) - @JoinColumn() - hackers: Hacker[]; + @JoinColumn({ name: "identifier" }) + hackers: Array; } export default Bus; diff --git a/src/models/hacker.model.ts b/src/models/hacker.model.ts index 85ee345f..d4ea0128 100644 --- a/src/models/hacker.model.ts +++ b/src/models/hacker.model.ts @@ -1,26 +1,19 @@ -import * as Constants from "../constants/general.constant"; -import { - Column, - Entity, - JoinColumn, - OneToMany, - ManyToOne, - OneToOne -} from "typeorm"; +import { HackerStatus } from "../constants/general.constant"; +import { Column, Entity, JoinColumn, ManyToOne, OneToOne } from "typeorm"; import Account from "./account.model"; -import Application, { ApplicationSchema } from "./application.model"; +import { ApplicationSchema } from "./application.model"; import Team from "./team.model"; @Entity() class Hacker { - @OneToOne(() => Account, { primary: true }) - @JoinColumn() + @OneToOne(() => Account, { primary: true, cascade: true }) + @JoinColumn({ name: "identifier" }) account: Account; @Column({ - enum: Constants.HACKER_STATUSES, + enum: HackerStatus, nullable: false, - default: "None" + default: HackerStatus.None }) status: string; @@ -30,35 +23,10 @@ class Hacker { //TODO: Implement Team One To One @ManyToOne( () => Team, - (team) => team.hackers + (team) => team.members ) + @JoinColumn({ referencedColumnName: "identifier" }) team?: Team; - - toJSON() { - return this; - } - - isApplicationComplete() { - if (this.application == null) return false; - - const portfolioDone = !!this.application.general.URL.resume; - const jobInterestDone = !!this.application.general.jobInterest; - const questionOneDone = !!this.application.shortAnswer.question1; - const questionTwoDone = !!this.application.shortAnswer.question2; - const previousHackathonsDone = !!this.application.shortAnswer - .previousHackathons; - const attendancePreferenceDone = !!this.application.accommodation - .attendancePreference; - - return ( - portfolioDone && - jobInterestDone && - questionOneDone && - questionTwoDone && - previousHackathonsDone && - attendancePreferenceDone - ); - } } export default Hacker; diff --git a/src/models/sponsor.model.ts b/src/models/sponsor.model.ts index 785cb24c..b8e03f8b 100644 --- a/src/models/sponsor.model.ts +++ b/src/models/sponsor.model.ts @@ -26,10 +26,10 @@ class Sponsor { @ManyToMany(() => Hacker) @JoinTable() - nominees: Hacker[]; + nominees: Array; @OneToOne(() => Account, { primary: true }) - @JoinColumn() + @JoinColumn({ name: "identifier" }) account: Account; } diff --git a/src/models/team.model.ts b/src/models/team.model.ts index d44ba397..b46986ff 100644 --- a/src/models/team.model.ts +++ b/src/models/team.model.ts @@ -1,10 +1,10 @@ import { IsString } from "class-validator"; import { Entity, - BaseEntity, Column, OneToMany, - PrimaryGeneratedColumn + PrimaryGeneratedColumn, + JoinColumn } from "typeorm"; import Hacker from "./hacker.model"; @@ -20,17 +20,19 @@ class Team { //TODO: Implement max team size. @OneToMany( () => Hacker, - (hacker) => hacker.team + (hacker) => hacker.team, + { cascade: true, eager: true } ) - hackers: Hacker[]; + @JoinColumn() + members: Array; - @Column({ default: undefined }) + @Column({ nullable: true }) @IsString() - submission: string; + submission?: string; - @Column() + @Column({ nullable: true }) @IsString() - project: string; + project?: string; } export default Team; diff --git a/src/models/travel.model.ts b/src/models/travel.model.ts index 2f0bfc0d..ab7e52df 100644 --- a/src/models/travel.model.ts +++ b/src/models/travel.model.ts @@ -1,13 +1,12 @@ -import * as Constants from "../constants/general.constant"; -import { Entity, BaseEntity, OneToOne, JoinColumn, Column } from "typeorm"; +import { Entity, OneToOne, JoinColumn, Column } from "typeorm"; import Hacker from "./hacker.model"; import * as GeneralConstants from "../constants/general.constant"; -import { IsEnum, IsInt, IsNumber, IsString, Max, Min } from "class-validator"; +import { IsEnum, IsNumber, Max, Min } from "class-validator"; @Entity() -class Travel extends BaseEntity { +class Travel { @OneToOne(() => Hacker, { primary: true }) - @JoinColumn() + @JoinColumn({ name: "identifier" }) hacker: Hacker; @Column({ @@ -16,7 +15,7 @@ class Travel extends BaseEntity { default: "None" }) @IsEnum(GeneralConstants.TravelStatus) - status: String; + status: string; @Column({ nullable: false }) @IsNumber() From c8696eeb6878bcc164ca3de9997123d42f203298 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Mon, 3 Jan 2022 01:58:49 -0500 Subject: [PATCH 35/72] refactor: token & strategy model names to kebab case. --- src/controllers/authentication.controller.ts | 8 ++++---- ...Token.model.ts => account-confirmation-token.model.ts} | 3 +-- ...dResetToken.model.ts => password-reset-token.model.ts} | 3 +-- src/services/account-confirmation.service.ts | 2 +- src/services/password-reset.service.ts | 2 +- .../email-and-password.strategy.ts} | 0 6 files changed, 8 insertions(+), 10 deletions(-) rename src/models/{accountConfirmationToken.model.ts => account-confirmation-token.model.ts} (95%) rename src/models/{passwordResetToken.model.ts => password-reset-token.model.ts} (91%) rename src/{strategy/emailAndPassword.strategy.ts => strategies/email-and-password.strategy.ts} (100%) diff --git a/src/controllers/authentication.controller.ts b/src/controllers/authentication.controller.ts index a765cee0..5c3ed5d0 100644 --- a/src/controllers/authentication.controller.ts +++ b/src/controllers/authentication.controller.ts @@ -14,7 +14,7 @@ import { Request as ExpressRequest, Response as ExpressResponse } from "express"; -import { EmailAndPasswordStrategy } from "../strategy/emailAndPassword.strategy"; +import { EmailAndPasswordStrategy } from "../strategies/email-and-password.strategy"; import passport from "passport"; import Account from "../models/account.model"; import * as ErrorConstants from "../constants/error.constant"; @@ -22,13 +22,13 @@ import * as SuccessConstants from "../constants/success.constant"; import { EnsureAuthenticated } from "../middlewares/authenticated.middleware"; import { PasswordResetService } from "../services/password-reset.service"; import { AccountService } from "../services/account.service"; -import PasswordReset from "../models/passwordResetToken.model"; +import PasswordReset from "../models/password-reset-token.model"; import { EmailService } from "../services/email.service"; import { join } from "path"; import jwt from "jsonwebtoken"; import { EnvService } from "../services/env.service"; import { AccountConfirmationService } from "../services/account-confirmation.service"; -import AccountConfirmation from "../models/accountConfirmationToken.model"; +import AccountConfirmation from "../models/account-confirmation-token.model"; import { EnsureAuthorization } from "../middlewares/authorization.middleware"; import { AuthorizationLevel } from "../constants/authorization-level.constant"; @@ -137,7 +137,7 @@ export class AuthenticationController { @Post("/password/reset") async resetPassword( @Response() response: ExpressResponse, - @Headers("X-Reset-Token") token: string, + @Body("X-Reset-Token") token: string, @Body("password") password: string ) { // Check if the JWT is valid and provide deconstructed object of identifier and account identiifer. diff --git a/src/models/accountConfirmationToken.model.ts b/src/models/account-confirmation-token.model.ts similarity index 95% rename from src/models/accountConfirmationToken.model.ts rename to src/models/account-confirmation-token.model.ts index 0acc5c4f..d55988fb 100644 --- a/src/models/accountConfirmationToken.model.ts +++ b/src/models/account-confirmation-token.model.ts @@ -1,7 +1,6 @@ import { IsEmail, IsEnum } from "class-validator"; import { Entity, - BaseEntity, Column, JoinColumn, OneToOne, @@ -16,7 +15,7 @@ class AccountConfirmation { readonly identifier: number; @OneToOne(() => Account) - @JoinColumn() + @JoinColumn({ name: "identifier" }) account?: Account; @Column({ diff --git a/src/models/passwordResetToken.model.ts b/src/models/password-reset-token.model.ts similarity index 91% rename from src/models/passwordResetToken.model.ts rename to src/models/password-reset-token.model.ts index 0bdae6d5..229ddeeb 100644 --- a/src/models/passwordResetToken.model.ts +++ b/src/models/password-reset-token.model.ts @@ -1,7 +1,6 @@ import { IsDate } from "class-validator"; import { Entity, - BaseEntity, Column, JoinColumn, OneToOne, @@ -15,7 +14,7 @@ class PasswordReset { readonly identifier: number; @OneToOne(() => Account) - @JoinColumn() + @JoinColumn({ name: "identifier" }) account: Account; @Column({ nullable: false }) diff --git a/src/services/account-confirmation.service.ts b/src/services/account-confirmation.service.ts index d98ee8ce..e3a3cfe5 100644 --- a/src/services/account-confirmation.service.ts +++ b/src/services/account-confirmation.service.ts @@ -1,6 +1,6 @@ import { autoInjectable, singleton } from "tsyringe"; import { getRepository, Repository } from "typeorm"; -import AccountConfirmation from "../models/accountConfirmationToken.model"; +import AccountConfirmation from "../models/account-confirmation-token.model"; import jwt from "jsonwebtoken"; import { EnvService } from "./env.service"; diff --git a/src/services/password-reset.service.ts b/src/services/password-reset.service.ts index a2fffb03..60551915 100644 --- a/src/services/password-reset.service.ts +++ b/src/services/password-reset.service.ts @@ -1,7 +1,7 @@ import { autoInjectable } from "tsyringe"; import { DeleteResult, getRepository, Repository } from "typeorm"; import Account from "../models/account.model"; -import PasswordReset from "../models/passwordResetToken.model"; +import PasswordReset from "../models/password-reset-token.model"; import jwt from "jsonwebtoken"; import { EnvService } from "./env.service"; diff --git a/src/strategy/emailAndPassword.strategy.ts b/src/strategies/email-and-password.strategy.ts similarity index 100% rename from src/strategy/emailAndPassword.strategy.ts rename to src/strategies/email-and-password.strategy.ts From a1f02938dc5a08be3219f1f3445679ba05f06beb Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Mon, 3 Jan 2022 02:00:06 -0500 Subject: [PATCH 36/72] feat: add /self endpoint to account controller. --- src/controllers/account.controller.ts | 34 ++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/controllers/account.controller.ts b/src/controllers/account.controller.ts index f70282e6..27acf531 100644 --- a/src/controllers/account.controller.ts +++ b/src/controllers/account.controller.ts @@ -1,4 +1,7 @@ -import { Response as ExpressResponse } from "express"; +import { + Request as ExpressRequest, + Response as ExpressResponse +} from "express"; import { autoInjectable } from "tsyringe"; import { AccountService } from "../services/account.service"; import * as SuccessConstants from "../constants/success.constant"; @@ -10,6 +13,7 @@ import { Params, Patch, Post, + Request, Response } from "@decorators/express"; import Account from "../models/account.model"; @@ -53,6 +57,34 @@ export class AccountController { }); } + @Get("/self", [ + EnsureAuthenticated, + EnsureAuthorization([ + AuthorizationLevel.Staff, + AuthorizationLevel.Account + ]) + ]) + async getSelf( + @Request() request: ExpressRequest, + @Response() response: ExpressResponse + ) { + const account: + | Account + | undefined = await this.accountService.findByIdentifier( + //@ts-ignore + request.user?.identifier + ); + + return account + ? response.status(200).json({ + message: SuccessConstants.ACCOUNT_READ, + data: account + }) + : response.status(404).json({ + message: ErrorConstants.ACCOUNT_404_MESSAGE + }); + } + @Get("/:identifier", [ EnsureAuthenticated, EnsureAuthorization([ From 6f191e87b861d4170cafc2375375bfc344c73924 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Mon, 3 Jan 2022 02:00:25 -0500 Subject: [PATCH 37/72] feat: add temporary settings controller. - this allows the API to work the frontend while the refactor on the settings model is done. - new settings model? -> - key, value - Example: - key | value - APP_OPEN, - APP_CLOSE, TODO: - implement settings update route / action once the model is implemented. --- src/controllers/settings.controller.ts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/controllers/settings.controller.ts diff --git a/src/controllers/settings.controller.ts b/src/controllers/settings.controller.ts new file mode 100644 index 00000000..02295614 --- /dev/null +++ b/src/controllers/settings.controller.ts @@ -0,0 +1,24 @@ +import { Controller, Get, Response } from "@decorators/express"; +import { Response as ExpressResponse } from "express"; +import * as SuccessConstants from "../constants/success.constant"; + +@Controller("/settings") +export class SettingsController { + @Get("/") + getAll(@Response() response: ExpressResponse) { + response.status(200).send({ + message: SuccessConstants.SETTINGS_GET, + data: { + openTime: Date.now().toString(), + closeTime: (Date.now() + 31540000000 + 2628000000).toString(), + confirmTime: ( + Date.now() + + 31540000000 + + 2628000000 + + 2628000000 + ).toString(), + isRemote: false + } + }); + } +} From 770615edde24dad05376a156f37591a643102836 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Mon, 3 Jan 2022 02:04:42 -0500 Subject: [PATCH 38/72] fix: remove the usage of require from app.ts & register settings controller. --- src/app.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/app.ts b/src/app.ts index b9bb0e09..1c57b50d 100755 --- a/src/app.ts +++ b/src/app.ts @@ -10,12 +10,13 @@ import { SearchController } from "./controllers/search.controller"; import { SponsorController } from "./controllers/sponsor.controller"; import { TeamController } from "./controllers/team.controller"; import { TravelController } from "./controllers/travel.controller"; +import { SettingsController } from "./controllers/settings.controller"; import { DatabaseService } from "./services/database.service"; import { EnvService } from "./services/env.service"; import { LoggerService } from "./services/logger.service"; -const cookieParser = require("cookie-parser"); -const cookieSession = require("cookie-session"); -const cors = require("cors"); +import cookieParser from "cookie-parser"; +import cookieSession from "cookie-session"; +import cors from "cors"; (async () => { const application = express(); @@ -81,7 +82,8 @@ const cors = require("cors"); container.resolve(TeamController), container.resolve(SponsorController), container.resolve(TravelController), - container.resolve(SearchController) + container.resolve(SearchController), + container.resolve(SettingsController) ]); application.use("/api", router); From ff12bb5947e4c814818115fbfbaf5342dd4d946f Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Mon, 3 Jan 2022 02:07:36 -0500 Subject: [PATCH 39/72] feat: add /self endpoint to hacker controller. --- src/controllers/hacker.controller.ts | 31 +++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/controllers/hacker.controller.ts b/src/controllers/hacker.controller.ts index 7b8bde83..7399277f 100644 --- a/src/controllers/hacker.controller.ts +++ b/src/controllers/hacker.controller.ts @@ -31,6 +31,34 @@ export class HackerController { private readonly storageService: StorageService ) {} + @Get("/self", [ + EnsureAuthenticated, + EnsureAuthorization([ + AuthorizationLevel.Staff, + AuthorizationLevel.Hacker + ]) + ]) + async getSelf( + @Request() request: ExpressRequest, + @Response() response: ExpressResponse + ) { + const hacker: + | Hacker + | undefined = await this.hackerService.findByIdentifier( + //@ts-ignore + request.user?.identifier + ); + + return hacker + ? response.status(200).json({ + message: SuccessConstants.HACKER_READ, + data: hacker + }) + : response.status(404).json({ + message: ErrorConstants.HACKER_404_MESSAGE + }); + } + @Get("/:identifier", [ EnsureAuthenticated, EnsureAuthorization([ @@ -62,6 +90,7 @@ export class HackerController { @Body() hacker: Hacker ) { //TODO - Check if applications are open when hacker is created. + //TODO - Fix bug where Hacker status is None as it is passed into the API. (Maybe override the status variable somehow?) const result: Hacker = await this.hackerService.save(hacker); return result @@ -116,7 +145,7 @@ export class HackerController { | Hacker | undefined = await this.hackerService.findByIdentifier(identifier); const resume = await this.storageService.download( - hacker?.application.general.URL.resume! + hacker?.application.general.URL.resume ); resume From 0fec81892ee8c6412ca0ccf31d4fc64495e06926 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Mon, 3 Jan 2022 02:07:45 -0500 Subject: [PATCH 40/72] fix: parse json input for query in search service & remove old body interface. - fix bug where we were taking the query fields as a string and not as a JSON object. - fix bug where the data was being passed through the request body instead of the query. - TODO: - implement page & limit by skip(page * limit) and limit(limit). - implement sort by orderBy(). --- src/controllers/search.controller.ts | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/src/controllers/search.controller.ts b/src/controllers/search.controller.ts index b3e6cce6..62aa8de9 100644 --- a/src/controllers/search.controller.ts +++ b/src/controllers/search.controller.ts @@ -1,4 +1,4 @@ -import { Body, Controller, Get, Params, Response } from "@decorators/express"; +import { Controller, Get, Query, Response } from "@decorators/express"; import { autoInjectable } from "tsyringe"; import { AuthorizationLevel } from "../constants/authorization-level.constant"; import { EnsureAuthenticated } from "../middlewares/authenticated.middleware"; @@ -7,15 +7,6 @@ import { SearchService } from "../services/search.service"; import { Response as ExpressResponse } from "express"; import * as SuccessConstants from "../constants/success.constant"; -export interface SearchBody { - page?: number; - limit?: number; - sort?: string; - expand?: boolean; - model: string; - q: any; -} - @autoInjectable() @Controller("/search") export class SearchController { @@ -31,21 +22,12 @@ export class SearchController { ]) async execute( @Response() response: ExpressResponse, - @Body() body: SearchBody + @Query("model") model: string, + @Query("q") q: string ) { - if (!body.page) body.page = 0; - if (!body.limit) body.limit = 10000; - if (!body.sort) body.sort = ""; - if (!body.expand) body.expand = false; - const result = await this.searchService.executeQuery( - body.model, - body.q, - body.page, - body.limit, - body.sort, - "", - body.expand + model, + JSON.parse(q) ); response.status(200).send({ From cff114aa75005397b349e29a78661767cf3a96d0 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Mon, 3 Jan 2022 02:11:26 -0500 Subject: [PATCH 41/72] feat: add flag to allow identifier check to be skipped on authorization middleware. - the rationale behind this is that all resources don't have the identifiers corresponding to user types. - example: teams - the team identifier != the hacker identifier - the hacker relation stores the identifiers, and we can't check this without making the code very ugly. - TODO: - ensure that this is not a security risk. --- src/middlewares/authorization.middleware.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/middlewares/authorization.middleware.ts b/src/middlewares/authorization.middleware.ts index e221540c..8459da38 100644 --- a/src/middlewares/authorization.middleware.ts +++ b/src/middlewares/authorization.middleware.ts @@ -13,7 +13,10 @@ import { AccountService } from "../services/account.service"; // TODO - Find a better way to pass parameters rather than encapsulating middleware class. // Current solution found from https://github.com/serhiisol/node-decorators/issues/111 // Library Author Suggest's Dependency Injection. -export function EnsureAuthorization(roles: Array): any { +export function EnsureAuthorization( + roles: Array, + noIdentifierCheck?: boolean +): any { @injectable() class EnsureAuthorizationClass implements Middleware { constructor( @@ -56,8 +59,11 @@ export function EnsureAuthorization(roles: Array): any { | undefined = await this.accountService.findByIdentifier( parseInt(request.params["identifier"]) ); - //@ts-ignore - if (query?.identifier !== request.user?.identifier) + if ( + !noIdentifierCheck && + //@ts-ignore + query?.identifier !== request.user?.identifier + ) return response.status(403).json({ message: ErrorConstants.AUTH_403_MESSAGE, error: { route: request.originalUrl } From 7780c3cdc1cb1f7af13d6dc517b96cd9aa851983 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Mon, 3 Jan 2022 02:17:10 -0500 Subject: [PATCH 42/72] fix: bug fixes for team controller. - use no identifier check flag on authorization to allow hackers to retieve team data. - this could potentially be a security issue as other hackers not apart of the team could query and retrieve PII possibly? - i will investigate further tomorrow and see if custom middleware is needed for this portion. - EnsureAuthorizedTeam? - query relation and see if hacker identifier is exists? - create special type for team response where we omit the members. - return team members outside of the team object in special format. - we do this as the frontend requires that team member data be returned the following way: - outside the team object. - with only the firstName, lastName, school, and status. - this code is ugly, we should attempt to find a better way to perform this task. - fix bug where initial member is not added to the team. - this solution is also inelegant we should figure out why the cascade is not working. - omit team members from the update route as we want to ensure that validation parameters for relation / team size are not bypassed. - change routes for joining and leaving a team as they were conflicting with the get by identifier route. --- src/controllers/team.controller.ts | 58 +++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/src/controllers/team.controller.ts b/src/controllers/team.controller.ts index 15c8dd69..b453c480 100644 --- a/src/controllers/team.controller.ts +++ b/src/controllers/team.controller.ts @@ -22,6 +22,16 @@ import * as SuccessConstants from "../constants/success.constant"; import * as ErrorConstants from "../constants/error.constant"; import { HackerService } from "../services/hacker.service"; import Hacker from "../models/hacker.model"; +import { HackerStatus } from "@constants/general.constant"; + +interface MemberInfo { + firstName: string; + lastName: string; + status: string; + school: string; +} + +type TeamWithoutMembers = Omit; @autoInjectable() @Controller("/team") @@ -33,10 +43,10 @@ export class TeamController { @Get("/:identifier", [ EnsureAuthenticated, - EnsureAuthorization([ - AuthorizationLevel.Staff, - AuthorizationLevel.Hacker - ]) + EnsureAuthorization( + [AuthorizationLevel.Staff, AuthorizationLevel.Hacker], + true + ) ]) async getByIdentifier( @Response() response: ExpressResponse, @@ -46,10 +56,26 @@ export class TeamController { identifier ); + const teamWithoutMembers: TeamWithoutMembers = team as TeamWithoutMembers; + const members: Array = []; + + if (team) + team.members.forEach((member) => + members.push({ + firstName: member.account.firstName, + lastName: member.account.lastName, + school: member.application.general.school, + status: member.status + }) + ); + return team ? response.status(200).json({ message: SuccessConstants.TEAM_READ, - data: team + data: { + team: teamWithoutMembers, + members: members + } }) : response.status(404).json({ message: ErrorConstants.TEAM_404_MESSAGE @@ -66,6 +92,11 @@ export class TeamController { async create(@Response() response: ExpressResponse, @Body() team: Team) { const result = await this.teamService.save(team); + //TODO - Figure out why we do not automatically add the first member to the team. + // The cascade should be working and automatically adding the relationship, but it does not. + if (result) + this.teamService.addMember(result.identifier, team.members[0]); + //TODO - Change duplicate message from Account to Team. return result ? response.status(200).send({ @@ -87,7 +118,7 @@ export class TeamController { async update( @Response() response: ExpressResponse, @Params("hackerIdentifier") hackerIdentifier: number, - @Body() update: Partial> + @Body() update: Partial> ) { const team: Team | undefined = ( await this.hackerService.findByIdentifier(hackerIdentifier) @@ -107,7 +138,7 @@ export class TeamController { }); } - @Patch("/join", [ + @Patch("/members/join", [ EnsureAuthenticated, EnsureAuthorization([AuthorizationLevel.Hacker]) ]) @@ -150,10 +181,7 @@ export class TeamController { name: name } }); - await this.teamService.removeMember( - hacker?.team?.identifier, - hacker - ); + await this.teamService.removeMember(hacker); } if (!(await this.teamService.addMember(team?.identifier!, hacker!))) @@ -166,7 +194,7 @@ export class TeamController { }); } - @Patch("/leave", [ + @Patch("/members/leave", [ EnsureAuthenticated, EnsureAuthorization([AuthorizationLevel.Hacker]) ]) @@ -186,11 +214,7 @@ export class TeamController { message: ErrorConstants.HACKER_404_MESSAGE }); else { - if (hacker.team) - await this.teamService.removeMember( - hacker.team.identifier, - hacker - ); + if (hacker.team) await this.teamService.removeMember(hacker); else response.status(404).send({ message: ErrorConstants.TEAM_404_MESSAGE From e2f872850c0e5a8e11294ee3313913e47f3bc182 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Mon, 3 Jan 2022 09:24:43 -0500 Subject: [PATCH 43/72] feat: add typescript paths. - use tsconfig-paths to register the paths for us so they work when compiled. - replace every import statement that uses a internal project file with its appropriate path. --- package-lock.json | 60 ++++++++++++++++++- package.json | 5 +- src/app.ts | 22 +++---- src/controllers/account.controller.ts | 20 +++---- src/controllers/authentication.controller.ts | 28 ++++----- src/controllers/hacker.controller.ts | 18 +++--- src/controllers/search.controller.ts | 10 ++-- src/controllers/settings.controller.ts | 2 +- src/controllers/sponsor.controller.ts | 14 ++--- src/controllers/team.controller.ts | 19 +++--- src/controllers/travel.controller.ts | 14 ++--- src/middlewares/authenticated.middleware.ts | 2 +- src/middlewares/authorization.middleware.ts | 8 +-- .../account-confirmation-token.model.ts | 4 +- src/models/account.model.ts | 2 +- src/models/application.model.ts | 2 +- src/models/bus.model.ts | 2 +- src/models/hacker.model.ts | 8 +-- src/models/password-reset-token.model.ts | 2 +- src/models/sponsor.model.ts | 4 +- src/models/team.model.ts | 2 +- src/models/travel.model.ts | 4 +- src/services/account-confirmation.service.ts | 4 +- src/services/account.service.ts | 2 +- src/services/database.service.ts | 2 +- src/services/email.service.ts | 4 +- src/services/hacker.service.ts | 4 +- src/services/logger.service.ts | 4 +- src/services/password-reset.service.ts | 6 +- src/services/sponsor.service.ts | 3 +- src/services/storage.service.ts | 4 +- src/services/team.service.ts | 4 +- src/services/travel.service.ts | 4 +- src/strategies/email-and-password.strategy.ts | 4 +- 34 files changed, 177 insertions(+), 120 deletions(-) diff --git a/package-lock.json b/package-lock.json index c84afc0c..8e2963c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -65,7 +65,8 @@ "eslint-config-prettier": "8.3.0", "eslint-plugin-prettier": "3.4.0", "mocha": "^9.0.3", - "prettier": "1.19.1" + "prettier": "1.19.1", + "tsconfig-paths": "^3.12.0" } }, "node_modules/@babel/code-frame": { @@ -593,6 +594,12 @@ "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", "dev": true }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, "node_modules/@types/jsonwebtoken": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.6.tgz", @@ -4266,6 +4273,18 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -7411,6 +7430,18 @@ "strip-json-comments": "^2.0.0" } }, + "node_modules/tsconfig-paths": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz", + "integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + } + }, "node_modules/tsconfig/node_modules/strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -8633,6 +8664,12 @@ "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", "dev": true }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, "@types/jsonwebtoken": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.6.tgz", @@ -11457,6 +11494,15 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, "jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -13936,6 +13982,18 @@ } } }, + "tsconfig-paths": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz", + "integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + } + }, "tslib": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", diff --git a/package.json b/package.json index 70954f3d..8e31f870 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "private": true, "license": "MIT", "scripts": { - "start": "DEBUG=hackboard:* NODE_ENV=test ts-node-dev --respawn --pretty --transpile-only src/app.ts", + "start": "DEBUG=hackboard:* NODE_ENV=test ts-node-dev --respawn --pretty -r tsconfig-paths/register --transpile-only src/app.ts", "start-windows": "set DEBUG=hackboard:* && set NODE_ENV=test && ts-node-dev --respawn --pretty --transpile-only src/app.ts", "deploy": "NODE_ENV=deployment node ./bin/www.js", "test": "DEBUG=hackboard:* NODE_ENV=test mocha --parallel --reporter spec tests/**.js --exit", @@ -69,6 +69,7 @@ "eslint-config-prettier": "8.3.0", "eslint-plugin-prettier": "3.4.0", "mocha": "^9.0.3", - "prettier": "1.19.1" + "prettier": "1.19.1", + "tsconfig-paths": "^3.12.0" } } diff --git a/src/app.ts b/src/app.ts index 1c57b50d..7414da71 100755 --- a/src/app.ts +++ b/src/app.ts @@ -3,17 +3,17 @@ import express from "express"; import passport from "passport"; import { join } from "path"; import { container } from "tsyringe"; -import { AccountController } from "./controllers/account.controller"; -import { AuthenticationController } from "./controllers/authentication.controller"; -import { HackerController } from "./controllers/hacker.controller"; -import { SearchController } from "./controllers/search.controller"; -import { SponsorController } from "./controllers/sponsor.controller"; -import { TeamController } from "./controllers/team.controller"; -import { TravelController } from "./controllers/travel.controller"; -import { SettingsController } from "./controllers/settings.controller"; -import { DatabaseService } from "./services/database.service"; -import { EnvService } from "./services/env.service"; -import { LoggerService } from "./services/logger.service"; +import { AccountController } from "@controllers/account.controller"; +import { AuthenticationController } from "@controllers/authentication.controller"; +import { HackerController } from "@controllers/hacker.controller"; +import { SearchController } from "@controllers/search.controller"; +import { SponsorController } from "@controllers/sponsor.controller"; +import { TeamController } from "@controllers/team.controller"; +import { TravelController } from "@controllers/travel.controller"; +import { SettingsController } from "@controllers/settings.controller"; +import { DatabaseService } from "@services/database.service"; +import { EnvService } from "@services/env.service"; +import { LoggerService } from "@services/logger.service"; import cookieParser from "cookie-parser"; import cookieSession from "cookie-session"; import cors from "cors"; diff --git a/src/controllers/account.controller.ts b/src/controllers/account.controller.ts index 27acf531..03a21147 100644 --- a/src/controllers/account.controller.ts +++ b/src/controllers/account.controller.ts @@ -3,9 +3,9 @@ import { Response as ExpressResponse } from "express"; import { autoInjectable } from "tsyringe"; -import { AccountService } from "../services/account.service"; -import * as SuccessConstants from "../constants/success.constant"; -import * as ErrorConstants from "../constants/error.constant"; +import { AccountService } from "@services/account.service"; +import * as SuccessConstants from "@constants/success.constant"; +import * as ErrorConstants from "@constants/error.constant"; import { Body, Controller, @@ -16,13 +16,13 @@ import { Request, Response } from "@decorators/express"; -import Account from "../models/account.model"; -import { EnsureAuthenticated } from "../middlewares/authenticated.middleware"; -import { EnsureAuthorization } from "../middlewares/authorization.middleware"; -import { AuthorizationLevel } from "../constants/authorization-level.constant"; -import { AccountConfirmationService } from "../services/account-confirmation.service"; -import { EmailService } from "../services/email.service"; -import * as GeneralConstants from "../constants/general.constant"; +import Account from "@models/account.model"; +import { EnsureAuthenticated } from "@middlewares/authenticated.middleware"; +import { EnsureAuthorization } from "@middlewares/authorization.middleware"; +import { AuthorizationLevel } from "@constants/authorization-level.constant"; +import { AccountConfirmationService } from "@services/account-confirmation.service"; +import { EmailService } from "@services/email.service"; +import * as GeneralConstants from "@constants/general.constant"; import { join } from "path"; @autoInjectable() diff --git a/src/controllers/authentication.controller.ts b/src/controllers/authentication.controller.ts index 5c3ed5d0..212a0c68 100644 --- a/src/controllers/authentication.controller.ts +++ b/src/controllers/authentication.controller.ts @@ -14,23 +14,23 @@ import { Request as ExpressRequest, Response as ExpressResponse } from "express"; -import { EmailAndPasswordStrategy } from "../strategies/email-and-password.strategy"; +import { EmailAndPasswordStrategy } from "@strategies/email-and-password.strategy"; import passport from "passport"; -import Account from "../models/account.model"; -import * as ErrorConstants from "../constants/error.constant"; -import * as SuccessConstants from "../constants/success.constant"; -import { EnsureAuthenticated } from "../middlewares/authenticated.middleware"; -import { PasswordResetService } from "../services/password-reset.service"; -import { AccountService } from "../services/account.service"; -import PasswordReset from "../models/password-reset-token.model"; -import { EmailService } from "../services/email.service"; +import Account from "@models/account.model"; +import * as ErrorConstants from "@constants/error.constant"; +import * as SuccessConstants from "@constants/success.constant"; +import { EnsureAuthenticated } from "@middlewares/authenticated.middleware"; +import { PasswordResetService } from "@services/password-reset.service"; +import { AccountService } from "@services/account.service"; +import PasswordReset from "@models/password-reset-token.model"; +import { EmailService } from "@services/email.service"; import { join } from "path"; import jwt from "jsonwebtoken"; -import { EnvService } from "../services/env.service"; -import { AccountConfirmationService } from "../services/account-confirmation.service"; -import AccountConfirmation from "../models/account-confirmation-token.model"; -import { EnsureAuthorization } from "../middlewares/authorization.middleware"; -import { AuthorizationLevel } from "../constants/authorization-level.constant"; +import { EnvService } from "@services/env.service"; +import { AccountConfirmationService } from "@services/account-confirmation.service"; +import AccountConfirmation from "@models/account-confirmation-token.model"; +import { EnsureAuthorization } from "@middlewares/authorization.middleware"; +import { AuthorizationLevel } from "@constants/authorization-level.constant"; @autoInjectable() @Controller("/authentication") diff --git a/src/controllers/hacker.controller.ts b/src/controllers/hacker.controller.ts index 7399277f..cadfa527 100644 --- a/src/controllers/hacker.controller.ts +++ b/src/controllers/hacker.controller.ts @@ -9,19 +9,19 @@ import { Response } from "@decorators/express"; import { autoInjectable } from "tsyringe"; -import { AuthorizationLevel } from "../constants/authorization-level.constant"; -import { EnsureAuthenticated } from "../middlewares/authenticated.middleware"; -import { EnsureAuthorization } from "../middlewares/authorization.middleware"; -import Hacker from "../models/hacker.model"; -import { HackerService } from "../services/hacker.service"; -import * as SuccessConstants from "../constants/success.constant"; -import * as ErrorConstants from "../constants/error.constant"; +import { AuthorizationLevel } from "@constants/authorization-level.constant"; +import { EnsureAuthenticated } from "@middlewares/authenticated.middleware"; +import { EnsureAuthorization } from "@middlewares/authorization.middleware"; +import Hacker from "@models/hacker.model"; +import { HackerService } from "@services/hacker.service"; +import * as SuccessConstants from "@constants/success.constant"; +import * as ErrorConstants from "@constants/error.constant"; import { Request as ExpressRequest, Response as ExpressResponse } from "express"; -import { StorageService } from "../services/storage.service"; -import { upload } from "../middlewares/multer.middleware"; +import { StorageService } from "@services/storage.service"; +import { upload } from "@middlewares/multer.middleware"; @autoInjectable() @Controller("/hacker") diff --git a/src/controllers/search.controller.ts b/src/controllers/search.controller.ts index 62aa8de9..e2194980 100644 --- a/src/controllers/search.controller.ts +++ b/src/controllers/search.controller.ts @@ -1,11 +1,11 @@ import { Controller, Get, Query, Response } from "@decorators/express"; import { autoInjectable } from "tsyringe"; -import { AuthorizationLevel } from "../constants/authorization-level.constant"; -import { EnsureAuthenticated } from "../middlewares/authenticated.middleware"; -import { EnsureAuthorization } from "../middlewares/authorization.middleware"; -import { SearchService } from "../services/search.service"; +import { AuthorizationLevel } from "@constants/authorization-level.constant"; +import { EnsureAuthenticated } from "@middlewares/authenticated.middleware"; +import { EnsureAuthorization } from "@middlewares/authorization.middleware"; +import { SearchService } from "@services/search.service"; import { Response as ExpressResponse } from "express"; -import * as SuccessConstants from "../constants/success.constant"; +import * as SuccessConstants from "@constants/success.constant"; @autoInjectable() @Controller("/search") diff --git a/src/controllers/settings.controller.ts b/src/controllers/settings.controller.ts index 02295614..343e0533 100644 --- a/src/controllers/settings.controller.ts +++ b/src/controllers/settings.controller.ts @@ -1,6 +1,6 @@ import { Controller, Get, Response } from "@decorators/express"; import { Response as ExpressResponse } from "express"; -import * as SuccessConstants from "../constants/success.constant"; +import * as SuccessConstants from "@constants/success.constant"; @Controller("/settings") export class SettingsController { diff --git a/src/controllers/sponsor.controller.ts b/src/controllers/sponsor.controller.ts index c9f50879..8e42e530 100644 --- a/src/controllers/sponsor.controller.ts +++ b/src/controllers/sponsor.controller.ts @@ -8,14 +8,14 @@ import { Response } from "@decorators/express"; import { autoInjectable } from "tsyringe"; -import { AuthorizationLevel } from "../constants/authorization-level.constant"; -import { EnsureAuthenticated } from "../middlewares/authenticated.middleware"; -import { EnsureAuthorization } from "../middlewares/authorization.middleware"; -import Sponsor from "../models/sponsor.model"; -import { SponsorService } from "../services/sponsor.service"; +import { AuthorizationLevel } from "@constants/authorization-level.constant"; +import { EnsureAuthenticated } from "@middlewares/authenticated.middleware"; +import { EnsureAuthorization } from "@middlewares/authorization.middleware"; +import Sponsor from "@models/sponsor.model"; +import { SponsorService } from "@services/sponsor.service"; import { Response as ExpressResponse } from "express"; -import * as SuccessConstants from "../constants/success.constant"; -import * as ErrorConstants from "../constants/error.constant"; +import * as SuccessConstants from "@constants/success.constant"; +import * as ErrorConstants from "@constants/error.constant"; @autoInjectable() @Controller("/sponsor") diff --git a/src/controllers/team.controller.ts b/src/controllers/team.controller.ts index b453c480..e2630a38 100644 --- a/src/controllers/team.controller.ts +++ b/src/controllers/team.controller.ts @@ -13,16 +13,15 @@ import { Request as ExpressRequest, Response as ExpressResponse } from "express"; -import { EnsureAuthenticated } from "../middlewares/authenticated.middleware"; -import { EnsureAuthorization } from "../middlewares/authorization.middleware"; -import { AuthorizationLevel } from "../constants/authorization-level.constant"; -import Team from "../models/team.model"; -import { TeamService } from "../services/team.service"; -import * as SuccessConstants from "../constants/success.constant"; -import * as ErrorConstants from "../constants/error.constant"; -import { HackerService } from "../services/hacker.service"; -import Hacker from "../models/hacker.model"; -import { HackerStatus } from "@constants/general.constant"; +import { EnsureAuthenticated } from "@middlewares/authenticated.middleware"; +import { EnsureAuthorization } from "@middlewares/authorization.middleware"; +import { AuthorizationLevel } from "@constants/authorization-level.constant"; +import Team from "@models/team.model"; +import { TeamService } from "@services/team.service"; +import * as SuccessConstants from "@constants/success.constant"; +import * as ErrorConstants from "@constants/error.constant"; +import { HackerService } from "@services/hacker.service"; +import Hacker from "@models/hacker.model"; interface MemberInfo { firstName: string; diff --git a/src/controllers/travel.controller.ts b/src/controllers/travel.controller.ts index ddec79cf..bee311bd 100644 --- a/src/controllers/travel.controller.ts +++ b/src/controllers/travel.controller.ts @@ -8,17 +8,17 @@ import { Response } from "@decorators/express"; import { autoInjectable } from "tsyringe"; -import { AuthorizationLevel } from "../constants/authorization-level.constant"; -import { EnsureAuthenticated } from "../middlewares/authenticated.middleware"; -import { EnsureAuthorization } from "../middlewares/authorization.middleware"; -import Travel from "../models/travel.model"; -import { TravelService } from "../services/travel.service"; +import { AuthorizationLevel } from "@constants/authorization-level.constant"; +import { EnsureAuthenticated } from "@middlewares/authenticated.middleware"; +import { EnsureAuthorization } from "@middlewares/authorization.middleware"; +import Travel from "@models/travel.model"; +import { TravelService } from "@services/travel.service"; import { Request as ExpressRequest, Response as ExpressResponse } from "express"; -import * as SuccessConstants from "../constants/success.constant"; -import * as ErrorConstants from "../constants/error.constant"; +import * as SuccessConstants from "@constants/success.constant"; +import * as ErrorConstants from "@constants/error.constant"; @autoInjectable() @Controller("/travel") diff --git a/src/middlewares/authenticated.middleware.ts b/src/middlewares/authenticated.middleware.ts index eb529cc9..5da74997 100644 --- a/src/middlewares/authenticated.middleware.ts +++ b/src/middlewares/authenticated.middleware.ts @@ -2,7 +2,7 @@ import { Middleware } from "@decorators/express"; import { Request, Response, NextFunction } from "express"; import { ParamsDictionary } from "express-serve-static-core"; import { ParsedQs } from "qs"; -import * as ErrorConstants from "../constants/error.constant"; +import * as ErrorConstants from "@constants/error.constant"; export class EnsureAuthenticated implements Middleware { use( diff --git a/src/middlewares/authorization.middleware.ts b/src/middlewares/authorization.middleware.ts index 8459da38..45441318 100644 --- a/src/middlewares/authorization.middleware.ts +++ b/src/middlewares/authorization.middleware.ts @@ -3,10 +3,10 @@ import { Request, Response, NextFunction } from "express"; import { ParamsDictionary } from "express-serve-static-core"; import { ParsedQs } from "qs"; import { container, delay, inject, injectable } from "tsyringe"; -import * as ErrorConstants from "../constants/error.constant"; -import { AuthorizationLevel } from "../constants/authorization-level.constant"; -import Account from "../models/account.model"; -import { AccountService } from "../services/account.service"; +import * as ErrorConstants from "@constants/error.constant"; +import { AuthorizationLevel } from "@constants/authorization-level.constant"; +import Account from "@models/account.model"; +import { AccountService } from "@services/account.service"; // TODO - Improve the logic of the middleware to reduce duplication of response. // TODO - Provide proper comments / documentation. diff --git a/src/models/account-confirmation-token.model.ts b/src/models/account-confirmation-token.model.ts index d55988fb..d6ca5543 100644 --- a/src/models/account-confirmation-token.model.ts +++ b/src/models/account-confirmation-token.model.ts @@ -6,8 +6,8 @@ import { OneToOne, PrimaryGeneratedColumn } from "typeorm"; -import Account from "./account.model"; -import * as GeneralConstants from "../constants/general.constant"; +import Account from "@models/account.model"; +import * as GeneralConstants from "@constants/general.constant"; @Entity() class AccountConfirmation { diff --git a/src/models/account.model.ts b/src/models/account.model.ts index 2e428d36..8edc3706 100644 --- a/src/models/account.model.ts +++ b/src/models/account.model.ts @@ -9,7 +9,7 @@ import { IsString, Length } from "class-validator"; -import { UserType } from "../constants/general.constant"; +import { UserType } from "@constants/general.constant"; import { classToPlain, Exclude } from "class-transformer"; @Entity() diff --git a/src/models/application.model.ts b/src/models/application.model.ts index cba8c502..2f860147 100644 --- a/src/models/application.model.ts +++ b/src/models/application.model.ts @@ -6,7 +6,7 @@ import { JoinColumn, OneToOne } from "typeorm"; -import Hacker from "./hacker.model"; +import Hacker from "@models/hacker.model"; export interface ApplicationSchema { general: { diff --git a/src/models/bus.model.ts b/src/models/bus.model.ts index d4fc9f30..dbb7311e 100644 --- a/src/models/bus.model.ts +++ b/src/models/bus.model.ts @@ -5,7 +5,7 @@ import { JoinColumn, PrimaryGeneratedColumn } from "typeorm"; -import Hacker from "./hacker.model"; +import Hacker from "@models/hacker.model"; interface OriginSchema { country: string; diff --git a/src/models/hacker.model.ts b/src/models/hacker.model.ts index d4ea0128..0de1df30 100644 --- a/src/models/hacker.model.ts +++ b/src/models/hacker.model.ts @@ -1,8 +1,8 @@ -import { HackerStatus } from "../constants/general.constant"; +import { HackerStatus } from "@constants/general.constant"; import { Column, Entity, JoinColumn, ManyToOne, OneToOne } from "typeorm"; -import Account from "./account.model"; -import { ApplicationSchema } from "./application.model"; -import Team from "./team.model"; +import Account from "@models/account.model"; +import { ApplicationSchema } from "@models/application.model"; +import Team from "@models/team.model"; @Entity() class Hacker { diff --git a/src/models/password-reset-token.model.ts b/src/models/password-reset-token.model.ts index 229ddeeb..23b79562 100644 --- a/src/models/password-reset-token.model.ts +++ b/src/models/password-reset-token.model.ts @@ -6,7 +6,7 @@ import { OneToOne, PrimaryGeneratedColumn } from "typeorm"; -import Account from "./account.model"; +import Account from "@models/account.model"; @Entity() class PasswordReset { diff --git a/src/models/sponsor.model.ts b/src/models/sponsor.model.ts index b8e03f8b..5a958d57 100644 --- a/src/models/sponsor.model.ts +++ b/src/models/sponsor.model.ts @@ -7,8 +7,8 @@ import { OneToOne, JoinColumn } from "typeorm"; -import Account from "./account.model"; -import Hacker from "./hacker.model"; +import Account from "@models/account.model"; +import Hacker from "@models/hacker.model"; @Entity() class Sponsor { diff --git a/src/models/team.model.ts b/src/models/team.model.ts index b46986ff..fa21247d 100644 --- a/src/models/team.model.ts +++ b/src/models/team.model.ts @@ -6,7 +6,7 @@ import { PrimaryGeneratedColumn, JoinColumn } from "typeorm"; -import Hacker from "./hacker.model"; +import Hacker from "@models/hacker.model"; @Entity() class Team { diff --git a/src/models/travel.model.ts b/src/models/travel.model.ts index ab7e52df..1566797c 100644 --- a/src/models/travel.model.ts +++ b/src/models/travel.model.ts @@ -1,6 +1,6 @@ import { Entity, OneToOne, JoinColumn, Column } from "typeorm"; -import Hacker from "./hacker.model"; -import * as GeneralConstants from "../constants/general.constant"; +import Hacker from "@models/hacker.model"; +import * as GeneralConstants from "@constants/general.constant"; import { IsEnum, IsNumber, Max, Min } from "class-validator"; @Entity() diff --git a/src/services/account-confirmation.service.ts b/src/services/account-confirmation.service.ts index e3a3cfe5..754b4118 100644 --- a/src/services/account-confirmation.service.ts +++ b/src/services/account-confirmation.service.ts @@ -1,8 +1,8 @@ import { autoInjectable, singleton } from "tsyringe"; import { getRepository, Repository } from "typeorm"; -import AccountConfirmation from "../models/account-confirmation-token.model"; +import AccountConfirmation from "@models/account-confirmation-token.model"; import jwt from "jsonwebtoken"; -import { EnvService } from "./env.service"; +import { EnvService } from "@services/env.service"; @autoInjectable() @singleton() diff --git a/src/services/account.service.ts b/src/services/account.service.ts index 4142d22c..0e76463c 100644 --- a/src/services/account.service.ts +++ b/src/services/account.service.ts @@ -1,4 +1,4 @@ -import Account from "../models/account.model"; +import Account from "@models/account.model"; import { hashSync } from "bcrypt"; import { getRepository, Repository, UpdateResult } from "typeorm"; import { autoInjectable } from "tsyringe"; diff --git a/src/services/database.service.ts b/src/services/database.service.ts index afac54ad..f71d12b4 100644 --- a/src/services/database.service.ts +++ b/src/services/database.service.ts @@ -1,7 +1,7 @@ import { createConnection } from "typeorm"; import { autoInjectable, singleton } from "tsyringe"; -import { EnvService } from "./env.service"; +import { EnvService } from "@services/env.service"; @autoInjectable() @singleton() diff --git a/src/services/email.service.ts b/src/services/email.service.ts index 351ed9d5..c7091cc0 100644 --- a/src/services/email.service.ts +++ b/src/services/email.service.ts @@ -1,10 +1,10 @@ import { readFileSync } from "fs"; import { autoInjectable } from "tsyringe"; -import { EnvService } from "./env.service"; +import { EnvService } from "@services/env.service"; import { createTransport } from "nodemailer"; import { compile } from "handlebars"; import mjml2html from "mjml"; -import { LoggerService } from "./logger.service"; +import { LoggerService } from "@services/logger.service"; @autoInjectable() export class EmailService { diff --git a/src/services/hacker.service.ts b/src/services/hacker.service.ts index c30c9ee2..8e9808de 100644 --- a/src/services/hacker.service.ts +++ b/src/services/hacker.service.ts @@ -1,8 +1,8 @@ import { autoInjectable, singleton } from "tsyringe"; import { getRepository, Repository, UpdateResult } from "typeorm"; -import Hacker from "../models/hacker.model"; +import Hacker from "@models/hacker.model"; import { toDataURL } from "qrcode"; -import { EnvService } from "./env.service"; +import { EnvService } from "@services/env.service"; const cache = require("memory-cache"); diff --git a/src/services/logger.service.ts b/src/services/logger.service.ts index 63e7e736..24660060 100755 --- a/src/services/logger.service.ts +++ b/src/services/logger.service.ts @@ -10,8 +10,8 @@ import winston, { } from "winston"; import expressWinston from "express-winston"; import { inject, injectable, singleton } from "tsyringe"; -import { ErrorRequestHandler, Handler, Response } from "express"; -import { EnvService } from "./env.service"; +import { ErrorRequestHandler, Handler } from "express"; +import { EnvService } from "@services/env.service"; import { Format } from "logform"; @injectable() diff --git a/src/services/password-reset.service.ts b/src/services/password-reset.service.ts index 60551915..288a80a0 100644 --- a/src/services/password-reset.service.ts +++ b/src/services/password-reset.service.ts @@ -1,9 +1,9 @@ import { autoInjectable } from "tsyringe"; import { DeleteResult, getRepository, Repository } from "typeorm"; -import Account from "../models/account.model"; -import PasswordReset from "../models/password-reset-token.model"; +import Account from "@models/account.model"; +import PasswordReset from "@models/password-reset-token.model"; import jwt from "jsonwebtoken"; -import { EnvService } from "./env.service"; +import { EnvService } from "@services/env.service"; @autoInjectable() export class PasswordResetService { diff --git a/src/services/sponsor.service.ts b/src/services/sponsor.service.ts index ee9c3f90..c80d194e 100644 --- a/src/services/sponsor.service.ts +++ b/src/services/sponsor.service.ts @@ -1,9 +1,8 @@ import { UpdateResult } from "typeorm"; -import * as logger from "./logger.service"; import { autoInjectable, singleton } from "tsyringe"; import { getRepository, Repository } from "typeorm"; -import Sponsor from "../models/sponsor.model"; +import Sponsor from "@models/sponsor.model"; @autoInjectable() @singleton() diff --git a/src/services/storage.service.ts b/src/services/storage.service.ts index 7950655c..0366ce31 100644 --- a/src/services/storage.service.ts +++ b/src/services/storage.service.ts @@ -1,8 +1,8 @@ // Imports the Google Cloud client library import * as GStorage from "@google-cloud/storage"; import { autoInjectable } from "tsyringe"; -import { EnvService } from "./env.service"; -import { LoggerService } from "./logger.service"; +import { EnvService } from "@services/env.service"; +import { LoggerService } from "@services/logger.service"; @autoInjectable() export class StorageService { diff --git a/src/services/team.service.ts b/src/services/team.service.ts index 0084d8f9..ed261074 100644 --- a/src/services/team.service.ts +++ b/src/services/team.service.ts @@ -1,7 +1,7 @@ -import Team from "../models/team.model"; +import Team from "@models/team.model"; import { getRepository, Repository, UpdateResult } from "typeorm"; import { autoInjectable, singleton } from "tsyringe"; -import Hacker from "../models/hacker.model"; +import Hacker from "@models/hacker.model"; @autoInjectable() @singleton() diff --git a/src/services/travel.service.ts b/src/services/travel.service.ts index 13dfa5aa..4358f349 100644 --- a/src/services/travel.service.ts +++ b/src/services/travel.service.ts @@ -1,7 +1,7 @@ -import Travel from "../models/travel.model"; +import Travel from "@models/travel.model"; import { getRepository, Repository, UpdateResult } from "typeorm"; import { autoInjectable } from "tsyringe"; -import Hacker from "../models/hacker.model"; +import Hacker from "@models/hacker.model"; @autoInjectable() export class TravelService { diff --git a/src/strategies/email-and-password.strategy.ts b/src/strategies/email-and-password.strategy.ts index 5c93c41d..61879bc5 100644 --- a/src/strategies/email-and-password.strategy.ts +++ b/src/strategies/email-and-password.strategy.ts @@ -1,8 +1,8 @@ import passport from "passport"; import { Strategy } from "passport-local"; import { autoInjectable, singleton } from "tsyringe"; -import Account from "../models/account.model"; -import { AccountService } from "../services/account.service"; +import Account from "@models/account.model"; +import { AccountService } from "@services/account.service"; @autoInjectable() @singleton() From ddb940483e11fc670b657542614ec8708249c07c Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Thu, 20 Jan 2022 20:49:39 -0500 Subject: [PATCH 44/72] refactor: remove old unit tests. --- src/tests/account.test.js | 871 -------- src/tests/auth.service.spec.js | 4 - src/tests/auth.test.js | 75 - src/tests/email.service.spec.js | 71 - src/tests/hacker.test.js | 1938 ----------------- src/tests/role.test.js | 144 -- src/tests/search.service.spec.js | 334 --- src/tests/settings.test.js | 159 -- src/tests/setup.spec.js | 73 - src/tests/sponsor.test.js | 533 ----- src/tests/storage.spec.js | 51 - src/tests/team.test.js | 667 ------ src/tests/testResume.pdf | Bin 98553 -> 0 bytes src/tests/util/account.test.util.js | 520 ----- .../util/accountConfirmation.test.util.js | 107 - src/tests/util/auth.test.util.js | 26 - src/tests/util/bus.test.util.js | 54 - src/tests/util/hacker.test.util.js | 675 ------ src/tests/util/resetPassword.test.util.js | 61 - src/tests/util/role.test.util.js | 53 - src/tests/util/roleBinding.test.util.js | 167 -- src/tests/util/settings.test.util.js | 40 - src/tests/util/sponsor.test.util.js | 75 - src/tests/util/staff.test.util.js | 47 - src/tests/util/team.test.util.js | 95 - src/tests/util/volunteer.test.util.js | 65 - src/tests/volunteer.test.js | 309 --- 27 files changed, 7214 deletions(-) delete mode 100644 src/tests/account.test.js delete mode 100644 src/tests/auth.service.spec.js delete mode 100644 src/tests/auth.test.js delete mode 100644 src/tests/email.service.spec.js delete mode 100644 src/tests/hacker.test.js delete mode 100644 src/tests/role.test.js delete mode 100644 src/tests/search.service.spec.js delete mode 100644 src/tests/settings.test.js delete mode 100644 src/tests/setup.spec.js delete mode 100644 src/tests/sponsor.test.js delete mode 100644 src/tests/storage.spec.js delete mode 100644 src/tests/team.test.js delete mode 100644 src/tests/testResume.pdf delete mode 100644 src/tests/util/account.test.util.js delete mode 100644 src/tests/util/accountConfirmation.test.util.js delete mode 100644 src/tests/util/auth.test.util.js delete mode 100644 src/tests/util/bus.test.util.js delete mode 100644 src/tests/util/hacker.test.util.js delete mode 100644 src/tests/util/resetPassword.test.util.js delete mode 100644 src/tests/util/role.test.util.js delete mode 100644 src/tests/util/roleBinding.test.util.js delete mode 100644 src/tests/util/settings.test.util.js delete mode 100644 src/tests/util/sponsor.test.util.js delete mode 100644 src/tests/util/staff.test.util.js delete mode 100644 src/tests/util/team.test.util.js delete mode 100644 src/tests/util/volunteer.test.util.js delete mode 100644 src/tests/volunteer.test.js diff --git a/src/tests/account.test.js b/src/tests/account.test.js deleted file mode 100644 index 14d525ec..00000000 --- a/src/tests/account.test.js +++ /dev/null @@ -1,871 +0,0 @@ -"use strict"; -const chai = require("chai"); -const chaiHttp = require("chai-http"); -chai.use(chaiHttp); -const server = require("../app"); -const Account = require("../models/account.model"); -chai.should(); -const Constants = { - Error: require("../constants/error.constant"), - General: require("../constants/general.constant"), - Success: require("../constants/success.constant") -}; - -const util = { - account: require("./util/account.test.util"), - auth: require("./util/auth.test.util"), - accountConfirmation: require("./util/accountConfirmation.test.util"), - reset: require("./util/resetPassword.test.util"), - role: require("./util/role.test.util"), - roleBinding: require("./util/roleBinding.test.util"), - accountConfirmation: require("./util/accountConfirmation.test.util"), - resetPassword: require("./util/resetPassword.test.util.js") -}; -const agent = chai.request.agent(server.app); -// tokens -const confirmationToken = util.accountConfirmation.ConfirmationToken; -const fakeToken = util.accountConfirmation.FakeToken; -const resetToken = util.reset.ResetToken; -// accounts -const Admin0 = util.account.staffAccounts.stored[0]; -const teamHackerAccount0 = util.account.hackerAccounts.stored.team[0]; - -//This account has a confirmation token in the db -const storedAccount1 = util.account.NonConfirmedAccount1; -const storedAccount2 = util.account.NonConfirmedAccount2; - -//This account does not have a confirmation token in the DB -const storedAccount3 = util.account.NonConfirmedAccount3; - -// admin role binding - -const newAccount0 = util.account.unlinkedAccounts.new[0]; - -//This account should NOT have a phone number -const noPhoneAccount = util.account.NoPhoneHackerAccount0; - -describe("GET user account", function() { - async function storeAll() { - await util.account.storeHackerStaffAccounts(); - await util.role.storeAll(); - await util.roleBinding.storeAll(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("should FAIL to list the user's account on /api/account/self GET due to authentication", function(done) { - chai.request(server.app) - .get("/api/account/self") - .end(function(err, res) { - res.should.have.status(401); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - done(); - }); - }); - - // fail due to invalid login - it("should FAIL due to invalid password", function(done) { - agent - .post("/api/auth/login") - .type("application/json") - .send({ - email: Admin0.email, - password: "FakePassword" - }) - .end((err, res) => { - res.should.have.status(401); - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - done(); - }); - }); - - // success case - it("should list the user's account on /api/account/self GET", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return ( - agent - .get("/api/account/self") - // does not have password because of to stripped json - .end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.ACCOUNT_READ - ); - res.body.should.have.property("data"); - res.body.data.should.be.a("object"); - res.body.data.should.have.property("firstName"); - res.body.data.should.have.property("lastName"); - res.body.data.should.have.property("email"); - res.body.data.should.have.property( - "dietaryRestrictions" - ); - res.body.data.should.have.property("gender"); - done(); - }) - ); - }); - }); - - // success case - admin case - it("should list another account specified by id using admin priviledge on /api/account/:id/ GET", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return ( - agent - .get(`/api/account/${teamHackerAccount0._id}`) - // does not have password because of to stripped json - .end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.ACCOUNT_READ - ); - res.body.should.have.property("data"); - - // use acc.toStrippedJSON to deal with hidden passwords and convert _id to id - const acc = new Account(teamHackerAccount0); - chai.assert.equal( - JSON.stringify(res.body.data), - JSON.stringify(acc.toStrippedJSON()) - ); - done(); - }) - ); - }); - }); - // success case - user case - it("should list an account specified by id on /api/account/:id/ GET", function(done) { - util.auth.login(agent, teamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return ( - agent - .get(`/api/account/${teamHackerAccount0._id}`) - // does not have password because of to stripped json - .end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.ACCOUNT_READ - ); - res.body.should.have.property("data"); - - // use acc.toStrippedJSON to deal with hidden passwords and convert _id to id - const acc = new Account(teamHackerAccount0); - chai.assert.equal( - JSON.stringify(res.body.data), - JSON.stringify(acc.toStrippedJSON()) - ); - done(); - }) - ); - }); - }); - - // // fail case on authorization - it("should FAIL to list an account specified by id on /api/account/:id/ GET due to lack of authorization", function(done) { - util.auth.login(agent, teamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return ( - agent - .get(`/api/account/${Admin0._id}`) - // does not have password because of to stripped json - .end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.AUTH_403_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }) - ); - }); - }); -}); - -describe("POST create account", function() { - async function storeAll() { - await util.account.storeHackerStaffAccounts(); - await util.role.storeAll(); - await util.roleBinding.storeAll(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("should SUCCEED and create a new account", function(done) { - chai.request(server.app) - .post(`/api/account/`) - .type("application/json") - .send(newAccount0) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Success.ACCOUNT_CREATE); - - // use acc.toStrippedJSON to deal with hidden passwords and convert _id to id - const acc = new Account(newAccount0).toStrippedJSON(); - // delete id as those are generated - delete acc.id; - delete res.body.data.id; - chai.assert.equal( - JSON.stringify(res.body.data), - JSON.stringify(acc) - ); - done(); - }); - }); - it("should FAIL to create an account because the email is already in use", function(done) { - chai.request(server.app) - .post(`/api/account/`) - .type("application/json") - .send(teamHackerAccount0) - .end(function(err, res) { - res.should.have.status(422); - done(); - }); - }); - it("should SUCCEED and create a new account without a phone number", function(done) { - chai.request(server.app) - .post("/api/account") - .type("application/json") - .send(noPhoneAccount) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Success.ACCOUNT_CREATE); - - // use acc.toStrippedJSON to deal with hidden passwords and convert _id to id - const acc = new Account(noPhoneAccount).toStrippedJSON(); - // delete id as those are generated - delete acc.id; - delete res.body.data.id; - - chai.assert.equal( - JSON.stringify(res.body.data), - JSON.stringify(acc) - ); - done(); - }); - }); -}); - -describe("POST confirm account", function() { - async function storeAll() { - await util.account.storeExtraAccounts(); - await util.accountConfirmation.storeAll(); - await util.role.storeAll(); - await util.roleBinding.storeAll(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("should SUCCEED and confirm the account", function(done) { - chai.request(server.app) - .post(`/api/auth/confirm/${confirmationToken}`) - .type("application/json") - .end(function(err, res) { - res.should.have.status(200); - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.AUTH_CONFIRM_ACCOUNT - ); - done(); - }); - }); - - it("should FAIL confirming the account", function(done) { - chai.request(server.app) - .post(`/api/auth/confirm/${fakeToken}`) - .type("application/json") - .end(function(err, res) { - res.should.have.status(401); - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.ACCOUNT_TOKEN_401_MESSAGE - ); - done(); - }); - }); - - it("should FAIL to confirm account that has token with email but no account", function(done) { - chai.request(server.app) - .post(`/api/auth/confirm/${fakeToken}`) - .type("application/json") - .end(function(err, res) { - res.should.have.status(401); - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.ACCOUNT_TOKEN_401_MESSAGE - ); - done(); - }); - }); -}); - -describe("PATCH update account", function() { - const updatedInfo = { - _id: teamHackerAccount0._id, - firstName: "new", - lastName: "name", - email: "newUpdatedEmail@mail.com" - }; - - const failUpdatedInfo = { - _id: Admin0._id, - firstName: "fail", - lastName: "fail", - email: storedAccount1.email - }; - async function storeAll() { - await util.account.storeHackerStaffExtraAccount(); - await util.accountConfirmation.storeAll(); - await util.role.storeAll(); - await util.roleBinding.storeAll(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - // fail on authentication - it("should FAIL to update an account due to authentication", function(done) { - chai.request(server.app) - .patch(`/api/account/${updatedInfo._id}`) - .end(function(err, res) { - res.should.have.status(401); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - done(); - }); - }); - - // succeed on :all case - it("should SUCCEED and use admin to update another account", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - agent - .patch(`/api/account/${updatedInfo._id}`) - .type("application/json") - .send(updatedInfo) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.ACCOUNT_UPDATE - ); - res.body.should.have.property("data"); - // Is this correct matching of data? - res.body.data.firstName.should.equal(updatedInfo.firstName); - res.body.data.lastName.should.equal(updatedInfo.lastName); - done(); - }); - }); - }); - - // succeed on :self case - it("should SUCCEED and update the user's own account", function(done) { - util.auth.login(agent, teamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - agent - .patch(`/api/account/${updatedInfo._id}`) - .type("application/json") - .send(updatedInfo) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.ACCOUNT_UPDATE - ); - res.body.should.have.property("data"); - // Is this correct matching of data? - res.body.data.firstName.should.equal(updatedInfo.firstName); - res.body.data.lastName.should.equal(updatedInfo.lastName); - res.body.data.email.should.equal(updatedInfo.email); - done(); - }); - }); - }); - - // fail due to lack of authorization - it("should FAIL to update an account due to lack of authorization", function(done) { - util.auth.login(agent, teamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - agent - .patch(`/api/account/${failUpdatedInfo._id}`) - .type("application/json") - .send(updatedInfo) - .end(function(err, res) { - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.AUTH_403_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - }); - }); - - // fail due to attempt to update account email to one that already exists in DB - it("should FAIL to update email to one that already exists", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - agent - .patch(`/api/account/${failUpdatedInfo._id}`) - .type("application/json") - .send(failUpdatedInfo) - .end(function(err, res) { - res.should.have.status(409); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.ACCOUNT_EMAIL_409_MESSAGE - ); - done(); - }); - }); - }); -}); - -describe("POST reset password", function() { - const password = { - password: "NewPassword" - }; - async function storeAll() { - await util.account.storeStoredTeamAccounts(); - await util.resetPassword.storeAll(); - await util.role.storeAll(); - await util.roleBinding.storeAll(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("should SUCCEED and change the password", function(done) { - chai.request(server.app) - .post("/api/auth/password/reset") - .type("application/json") - .set("X-Reset-Token", resetToken) - .send(password) - .end(function(err, res) { - res.should.have.status(200); - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.AUTH_RESET_PASSWORD - ); - done(); - }); - }); -}); - -describe("PATCH change password for logged in user", function() { - const successChangePassword = { - oldPassword: Admin0.password, - newPassword: "password12345" - }; - const failChangePassword = { - oldPassword: "WrongPassword", - newPassword: "password12345" - }; - async function storeAll() { - await util.account.storeGetInviteAccounts(); - await util.resetPassword.storeAll(); - await util.role.storeAll(); - await util.roleBinding.storeAll(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - // fail on authentication - it("should FAIL to change the user's password because they are not logged in", function(done) { - chai.request(server.app) - .patch("/api/auth/password/change") - .type("application/json") - .send(failChangePassword) - .end(function(err, res) { - res.should.have.status(401); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - done(); - }); - }); - // success case - it("should change the logged in user's password to a new password", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - agent - .patch("/api/auth/password/change") - .type("application/json") - .send(successChangePassword) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.AUTH_RESET_PASSWORD - ); - done(); - }); - }); - }); - // fail case because old password in incorrect - it("should FAIL to change the logged in user's password to a new password because old password is incorrect", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - agent - .patch("/api/auth/password/change") - .type("application/json") - .send(failChangePassword) - .end(function(err, res) { - res.should.have.status(401); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.AUTH_401_MESSAGE - ); - done(); - }); - }); - }); -}); - -describe("GET retrieve permissions", function() { - async function storeAll() { - await util.account.storeHackerStaffAccounts(); - await util.role.storeAll(); - await util.roleBinding.storeAll(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("should SUCCEED and retrieve the rolebindings for the user", function(done) { - util.auth.login(agent, teamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - agent - .get("/api/auth/rolebindings/" + teamHackerAccount0._id) - .type("application/json") - .end(function(err, res) { - res.should.have.status(200); - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.AUTH_GET_ROLE_BINDINGS - ); - res.body.should.have.property("data"); - res.body.data.should.be.a("object"); - res.body.data.should.have.property("roles"); - res.body.data.should.have.property("accountId"); - res.body.data.accountId.should.equal( - teamHackerAccount0._id.toHexString() - ); - done(); - }); - }); - }); - it("should FAIL to retrieve the rolebindings as the account is not authenticated", function(done) { - chai.request(server.app) - .get("/api/auth/rolebindings/" + teamHackerAccount0._id) - .type("application/json") - .end(function(err, res) { - res.should.have.status(401); - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - done(); - }); - }); -}); - -describe("GET resend confirmation email", function() { - async function storeAll() { - await util.account.storeVerifyConfirmationAccounts(); - await util.accountConfirmation.storeAll(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("should SUCCEED and resend the confirmation email", function(done) { - util.auth.login(agent, storedAccount1, (error) => { - if (error) { - agent.close(); - return done(error); - } - agent - .get("/api/auth/confirm/resend") - .type("application/json") - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.AUTH_SEND_CONFIRMATION_EMAIL - ); - done(); - }); - }); - }); - it("should FAIL as the account is already confirmed", function(done) { - util.auth.login(agent, teamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - agent - .get("/api/auth/confirm/resend") - .type("application/json") - .end(function(err, res) { - res.should.have.status(422); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal("Account already confirmed"); - done(); - }); - }); - }); - it("should FAIL as account confirmation token does not exist", function(done) { - util.auth.login(agent, storedAccount3, (error) => { - if (error) { - agent.close(); - return done(error); - } - agent - .get("/api/auth/confirm/resend") - .type("application/json") - .end(function(err, res) { - res.should.have.status(428); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - "Account confirmation token does not exist" - ); - done(); - }); - }); - }); -}); - -describe("POST invite account", function() { - async function storeAll() { - await util.account.storeStaffUnlinkedAccount(); - await util.role.storeAll(); - await util.roleBinding.storeAll(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("Should succeed to invite a user to create an account", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return ( - agent - .post("/api/account/invite") - .type("application/json") - .send({ - email: newAccount0.email, - accountType: Constants.General.VOLUNTEER - }) - // does not have password because of to stripped json - .end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(200); - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.ACCOUNT_INVITE - ); - done(); - }) - ); - }); - }); -}); - -describe("GET invites", function() { - async function storeAll() { - await util.account.storeGetInviteAccounts(); - await util.accountConfirmation.storeAll(); - await util.role.storeAll(); - await util.roleBinding.storeAll(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("Should FAIL to get all invites due to Authentication", function(done) { - chai.request(server.app) - .get("/api/account/invite") - .end(function(err, res) { - res.should.have.status(401); - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - done(); - }); - }); - it("Should FAIL to get all invites due to Authorization", function(done) { - util.auth.login(agent, teamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent.get("/api/account/invite").end(function(err, res) { - res.should.have.status(403); - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_403_MESSAGE); - done(); - }); - }); - }); - it("Should SUCCEED to get all invites", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent.get("/api/account/invite").end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(200); - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.ACCOUNT_GET_INVITES - ); - res.body.should.have.property("data"); - res.body.data.should.have.property("invites"); - res.body.data.invites.length.should.equal(1); - done(); - }); - }); - }); -}); diff --git a/src/tests/auth.service.spec.js b/src/tests/auth.service.spec.js deleted file mode 100644 index 3fa68279..00000000 --- a/src/tests/auth.service.spec.js +++ /dev/null @@ -1,4 +0,0 @@ -"use strict"; -const dotenv = require("dotenv"); -const AuthService = require("../services/auth.service"); -const assert = require("chai").assert; diff --git a/src/tests/auth.test.js b/src/tests/auth.test.js deleted file mode 100644 index e833cf53..00000000 --- a/src/tests/auth.test.js +++ /dev/null @@ -1,75 +0,0 @@ -"use strict"; -const chai = require("chai"); -const chaiHttp = require("chai-http"); -chai.use(chaiHttp); -const server = require("../app"); -const logger = require("../services/logger.service"); -const Account = require("../models/account.model"); -const should = chai.should(); - -const agent = chai.request.agent(server.app); - -const util = { - account: require("./util/account.test.util"), - auth: require("./util/auth.test.util"), - accountConfirmation: require("./util/accountConfirmation.test.util"), - reset: require("./util/resetPassword.test.util"), - role: require("./util/role.test.util") -}; - -const constants = { - success: require("../constants/success.constant") -}; - -const roles = require("../constants/role.constant"); - -// hacker role binding -const teamHackerAccount0 = util.account.hackerAccounts.stored.team[0]; - -describe("GET roles", function() { - async function storeAll() { - await util.role.storeAll(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("should list all roles GET", function(done) { - util.auth.login(agent, teamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent.get("/api/auth/roles").end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(constants.success.AUTH_GET_ROLES); - res.body.should.have.property("data"); - res.body.data.should.be.a("Array"); - - let rolenames = []; - roles.allRolesArray.forEach((element) => { - rolenames.push(element.name); - }); - - let retrievedRoleNames = []; - res.body.data.forEach((element) => { - retrievedRoleNames.push(element.name); - }); - - rolenames.should.have.members(retrievedRoleNames); - done(); - }); - }); - }); -}); diff --git a/src/tests/email.service.spec.js b/src/tests/email.service.spec.js deleted file mode 100644 index bd6e9745..00000000 --- a/src/tests/email.service.spec.js +++ /dev/null @@ -1,71 +0,0 @@ -"use strict"; -const dotenv = require("dotenv"); -const path = require("path"); -dotenv.config({ - path: path.join(__dirname, "../.env") -}); -const EmailService = require("../services/email.service"); -const assert = require("chai").assert; - -describe("Email Service", function() { - it("It should send an email", (done) => { - EmailService.send({ - to: process.env.NO_REPLY_EMAIL, - from: process.env.NO_REPLY_EMAIL, - subject: "Hey man", - text: "Hi!", - mailSettings: { - sandboxMode: { - enable: true - } - } - }) - .then((response) => { - assert.equal( - response[0].statusCode, - 200, - "response should be accepted" - ); - done(); - }) - .catch(done); - }); - it("It should send multiple emails", (done) => { - EmailService.sendMultiple({ - to: [process.env.NO_REPLY_EMAIL, process.env.NO_REPLY_EMAIL], - from: process.env.NO_REPLY_EMAIL, - subject: "Hey man", - text: "Hi!", - mailSettings: { - sandboxMode: { - enable: true - } - } - }) - .then((responses) => { - responses.forEach((resp) => { - if (resp) { - assert.equal( - resp.statusCode, - 200, - "response should be accepted" - ); - } - }); - done(); - }) - .catch(done); - }); - it("It should compile a handlebars email", (done) => { - const handlebarPath = path.join(__dirname, `../assets/email/test.hbs`); - const rendered = EmailService.renderEmail(handlebarPath, { - TEST: "TESTTEST", - NOT_ESCAPED: "localhost:1337/reset?token=lala" - }); - assert.equal( - '
This is used for testing email service. DO NOT REMOVE.TESTTEST. link
', - rendered - ); - done(); - }); -}); diff --git a/src/tests/hacker.test.js b/src/tests/hacker.test.js deleted file mode 100644 index b6435750..00000000 --- a/src/tests/hacker.test.js +++ /dev/null @@ -1,1938 +0,0 @@ -"use strict"; -const chai = require("chai"); -const chaiHttp = require("chai-http"); -chai.use(chaiHttp); -const server = require("../app"); -const agent = chai.request.agent(server.app); -chai.should(); -const Hacker = require("../models/hacker.model"); -const fs = require("fs"); -const path = require("path"); -const Constants = { - Success: require("../constants/success.constant"), - General: require("../constants/general.constant"), - Error: require("../constants/error.constant") -}; - -const util = { - auth: require("./util/auth.test.util"), - hacker: require("./util/hacker.test.util"), - account: require("./util/account.test.util"), - settings: require("./util/settings.test.util"), - accountConfirmation: require("./util/accountConfirmation.test.util"), - role: require("./util/role.test.util"), - roleBinding: require("./util/roleBinding.test.util") -}; -const StorageService = require("../services/storage.service"); - -const Admin0 = util.account.staffAccounts.stored[0]; - -const volunteerAccount0 = util.account.volunteerAccounts.stored[0]; - -const newHackerAccount0 = util.account.hackerAccounts.new[0]; -const newHacker0 = util.hacker.newHacker0; -const invalidHackerAccount0 = util.account.hackerAccounts.invalid; -const invalidHacker0 = util.hacker.invalidHacker0; -const invalidHacker2 = util.hacker.invalidHacker2; -const newHacker1 = util.hacker.newHacker1; - -const noTeamHackerAccount0 = util.account.hackerAccounts.stored.noTeam[0]; -const noTeamHacker0 = util.hacker.NoTeamHacker0; - -const teamHackerAccount0 = util.account.hackerAccounts.stored.team[0]; -const teamHackerAccount1 = util.account.hackerAccounts.stored.team[1]; -const TeamHacker0 = util.hacker.TeamHacker0; -const TeamHacker1 = util.hacker.TeamHacker1; -const duplicateAccountLinkHacker0 = util.hacker.duplicateAccountLinkHacker0; - -const unconfirmedHackerAccount1 = - util.account.hackerAccounts.stored.unconfirmed[0]; -const unconfirmedHackerAccount0 = util.hacker.unconfirmedAccountHacker0; - -const unconfirmedHacker1 = util.hacker.unconfirmedAccountHacker1; - -const invalidHacker1 = util.hacker.invalidHacker1; - -const BatchAcceptHackerArrayValid = [ - util.hacker.TeamHacker0._id, - util.hacker.TeamHacker1._id, - util.hacker.NoTeamHacker0._id -]; - -const BatchAcceptHackerArrayInvalid = [ - invalidHacker1._id, - unconfirmedHacker1._id -]; - -describe("GET hacker", function() { - async function storeAll() { - await util.hacker.storeAll(); - await util.account.storeStaffNoTeamTeamUnconfirmedInvalid(); - await util.role.storeAll(); - await util.roleBinding.storeAll(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - // fail on authentication - it("should FAIL to list a hacker's information on /api/hacker/:id GET due to authentication", function(done) { - chai.request(server.app) - .get(`/api/hacker/` + TeamHacker0._id) - .end(function(err, res) { - res.should.have.status(401); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - done(); - }); - }); - - // success case - it("should list the user's hacker info on /api/hacker/self GET", function(done) { - util.auth.login(agent, teamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent.get("/api/hacker/self").end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Success.HACKER_READ); - res.body.should.have.property("data"); - - let hacker = new Hacker(TeamHacker0); - chai.assert.equal( - JSON.stringify(res.body.data), - JSON.stringify(hacker.toJSON()) - ); - done(); - }); - }); - }); - - // fail case due to wrong account type - it("should FAIL to list the hacker info of an admin due to wrong account type /api/account/self GET", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent.get("/api/hacker/self").end(function(err, res) { - res.should.have.status(409); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.ACCOUNT_TYPE_409_MESSAGE - ); - done(); - }); - }); - }); - - // fail case due to unconfirmed email address of already defined hacker - it("should FAIL to list the user's hacker info due to unconfirmed email on /api/hacker/self GET", function(done) { - util.auth.login(agent, unconfirmedHackerAccount1, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent.get("/api/hacker/self").end(function(err, res) { - res.should.have.status(409); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.ACCOUNT_TYPE_409_MESSAGE - ); - done(); - }); - }); - }); - - // succeed on admin case - it("should list a hacker's information using admin power on /api/hacker/:id GET", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return ( - agent - .get(`/api/hacker/${TeamHacker0._id}`) - // does not have password because of to stripped json - .end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.HACKER_READ - ); - res.body.should.have.property("data"); - - let hacker = new Hacker(TeamHacker0); - chai.assert.equal( - JSON.stringify(res.body.data), - JSON.stringify(hacker.toJSON()) - ); - - done(); - }) - ); - }); - }); - - // succeed on :self case - it("should list the user's hacker information on /api/hacker/:id GET", function(done) { - util.auth.login(agent, teamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return ( - agent - .get(`/api/hacker/${TeamHacker0._id}`) - // does not have password because of to stripped json - .end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.HACKER_READ - ); - res.body.should.have.property("data"); - - let hacker = new Hacker(TeamHacker0); - - chai.assert.equal( - JSON.stringify(res.body.data), - JSON.stringify(hacker.toJSON()) - ); - - done(); - }) - ); - }); - }); - - // fail due to lack of authorization - it("should FAIL to list a hacker information due to lack of authorization on /api/hacker/:id GET", function(done) { - util.auth.login(agent, noTeamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return ( - agent - .get(`/api/hacker/${TeamHacker0._id}`) - // does not have password because of to stripped json - .end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.AUTH_403_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }) - ); - }); - }); - - // fail due to lack of hacker - it("should FAIL to list an invalid hacker /api/hacker/:id GET", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .get(`/api/hacker/${invalidHacker1._id}`) - .end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(404); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.HACKER_404_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - }); - }); - - // succeed on admin case - it("should list a hacker's information using admin power on /api/hacker/email/:email GET", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return ( - agent - .get(`/api/hacker/email/${teamHackerAccount0.email}`) - // does not have password because of to stripped json - .end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.HACKER_READ - ); - res.body.should.have.property("data"); - - let hacker = new Hacker(TeamHacker0); - chai.assert.equal( - JSON.stringify(res.body.data), - JSON.stringify(hacker.toJSON()) - ); - - done(); - }) - ); - }); - }); - - // succeed on :self case - it("should list the user's hacker information on /api/hacker/email/:email GET", function(done) { - util.auth.login(agent, teamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return ( - agent - .get(`/api/hacker/email/${teamHackerAccount0.email}`) - // does not have password because of to stripped json - .end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.HACKER_READ - ); - res.body.should.have.property("data"); - - let hacker = new Hacker(TeamHacker0); - - chai.assert.equal( - JSON.stringify(res.body.data), - JSON.stringify(hacker.toJSON()) - ); - - done(); - }) - ); - }); - }); - - // fail due to lack of authorization - it("should FAIL to list a hacker information due to lack of authorization on /api/hacker/email/:id GET", function(done) { - util.auth.login(agent, noTeamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return ( - agent - .get(`/api/hacker/email/${teamHackerAccount0.email}`) - // does not have password because of to stripped json - .end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.AUTH_403_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }) - ); - }); - }); -}); - -describe("POST create hacker", function() { - async function storeAll() { - await util.roleBinding.storeAll(); - await util.role.storeAll(); - await util.settings.storeAll(); - await util.hacker.storeAll(); - await util.account.storeOneOfEach(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - // fail on authentication - it("should FAIL to create a new hacker due to lack of authentication", function(done) { - chai.request(server.app) - .post(`/api/hacker/`) - .type("application/json") - .send(newHacker1) - .end(function(err, res) { - res.should.have.status(401); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - - done(); - }); - }); - - // succeed on admin case - it("should SUCCEED and create a new hacker (with an account that has been confirmed) using admin credentials", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - - return done(error); - } - return agent - .post(`/api/hacker/`) - .type("application/json") - .send(newHacker0) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.HACKER_CREATE - ); - res.body.should.have.property("data"); - - // create JSON version of model - // delete id as they will be different between model objects - // update status to be applied on the comparator hacker object - const hacker = new Hacker(newHacker0).toJSON(); - hacker.status = Constants.General.HACKER_STATUS_APPLIED; - delete res.body.data.id; - delete hacker.id; - chai.assert.equal( - JSON.stringify(res.body.data), - JSON.stringify(hacker), - "objects do not match" - ); - - done(); - }); - }); - }); - - // succeed on user case - it("should SUCCEED and create a new hacker for user (with an account that has been confirmed)", function(done) { - util.auth.login(agent, newHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .post(`/api/hacker/`) - .type("application/json") - .send(newHacker0) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.HACKER_CREATE - ); - res.body.should.have.property("data"); - - // create JSON version of model - // delete id as they will be different between model objects - // update status to be applied on the comparator hacker object - const hacker = new Hacker(newHacker0).toJSON(); - hacker.status = Constants.General.HACKER_STATUS_APPLIED; - delete res.body.data.id; - delete hacker.id; - chai.assert.equal( - JSON.stringify(res.body.data), - JSON.stringify(hacker) - ); - done(); - }); - }); - }); - - it("should FAIL to create a new hacker when applications have not yet opened.", function(done) { - // Upload application not yet open. - util.settings.setApplicationNotYetOpen().then( - util.auth.login(agent, newHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .post(`/api/hacker/`) - .type("application/json") - .send(newHacker0) - .end(function(err, res) { - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.SETTINGS_403_MESSAGE - ); - done(); - }); - }) - ); - }); - - it("should FAIL to create a new hacker when applications have closed.", function(done) { - // Upload application closed. - util.settings.setApplicationClosed().then( - util.auth.login(agent, newHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .post(`/api/hacker/`) - .type("application/json") - .send(newHacker0) - .end(function(err, res) { - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.SETTINGS_403_MESSAGE - ); - done(); - }); - }) - ); - }); - - // should fail due to travel request larger than 100 - it("should FAIL if the new hacker inputs a value larger than 100 for travel reimbursement", function(done) { - util.auth.login(agent, newHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .post(`/api/hacker/`) - .type("application/json") - .send(invalidHacker2) - .end(function(err, res) { - res.should.have.status(422); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal("Validation failed"); - res.body.should.have.property("data"); - res.body.data.should.have.property( - "application.accommodation.travel" - ); - res.body.data[ - "application.accommodation.travel" - ].should.have.property("msg"); - res.body.data[ - "application.accommodation.travel" - ].msg.should.equal( - "application.accommodation.travel must be between 0 and 100" - ); - done(); - }); - }); - }); - - // should fail due to 'false' on code of conduct - it("should FAIL if the new hacker does not accept code of conduct", function(done) { - util.auth.login(agent, newHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .post(`/api/hacker/`) - .type("application/json") - .send(invalidHacker0) - .end(function(err, res) { - res.should.have.status(422); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal("Validation failed"); - res.body.should.have.property("data"); - res.body.data.should.have.property( - "application.other.privacyPolicy" - ); - res.body.data[ - "application.other.privacyPolicy" - ].msg.should.equal("Must be equal to true"); - res.body.data.should.have.property( - "application.other.codeOfConduct" - ); - res.body.data[ - "application.other.codeOfConduct" - ].msg.should.equal("Must be equal to true"); - done(); - }); - }); - }); - - // fail on unconfirmed account, using admin - it("should FAIL to create a new hacker if the account hasn't been confirmed", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .post(`/api/hacker/`) - .type("application/json") - .send(unconfirmedHackerAccount0) - .end(function(err, res) { - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.ACCOUNT_403_MESSAGE - ); - res.should.have.status(403); - done(); - }); - }); - }); - - // fail due to duplicate accountId - it("should FAIL to create new hacker due to duplicate account link", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .post(`/api/hacker/`) - .type("application/json") - .send(duplicateAccountLinkHacker0) - .end(function(err, res) { - res.should.have.status(409); - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.HACKER_ID_409_MESSAGE - ); - res.body.should.have.property("data"); - done(); - }); - }); - }); - - // fail on invalid input - it("should FAIL to create new hacker due to invalid input", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .post(`/api/hacker/`) - .type("application/json") - .send(invalidHacker1) - .end(function(err, res) { - res.should.have.status(422); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal("Validation failed"); - res.body.should.have.property("data"); - res.body.data.should.have.property("accountId"); - res.body.data.accountId.should.have.property("msg"); - res.body.data.accountId.msg.should.equal("Invalid mongoID"); - res.body.data.should.have.property( - "application.general.school" - ); - res.body.data[ - "application.general.school" - ].should.have.property("msg"); - res.body.data[ - "application.general.school" - ].msg.should.equal("name must exist"); - res.body.data.should.have.property( - "application.general.jobInterest" - ); - res.body.data[ - "application.general.jobInterest" - ].should.have.property("msg"); - - res.body.data[ - "application.general.jobInterest" - ].should.have.property("msg"); - res.body.data[ - "application.general.jobInterest" - ].msg.should.equal("The value must be part of the enum"); - res.body.data.should.have.property( - "application.accommodation.travel" - ); - res.body.data[ - "application.accommodation.travel" - ].should.have.property("msg"); - res.body.data[ - "application.accommodation.travel" - ].msg.should.equal( - "application.accommodation.travel must be an integer." - ); - - done(); - }); - }); - }); -}); - -describe("PATCH update multiple hackers", function() { - async function storeAll() { - await util.roleBinding.storeAll(); - await util.role.storeAll(); - await util.settings.storeAll(); - await util.hacker.storeAll(); - await util.account.storeOneOfEach(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("should FAIL input validation on /api/hacker/batchAccept as an Admin", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/hacker/batchAccept/`) - .type("application/json") - .send() - .end(function(err, res) { - res.should.have.status(422); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.VALIDATION_422_MESSAGE - ); - done(); - }); - }); - }); - it("should FAIL authorization on /api/hacker/batchAccept as a non-Admin", function(done) { - util.auth.login(agent, noTeamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/hacker/batchAccept/`) - .type("application/json") - .send() - .end(function(err, res) { - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.AUTH_403_MESSAGE - ); - done(); - }); - }); - }); - it("should SUCCEED and accept 2 hackers on /api/hacker/batchAccept as an Admin", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/hacker/batchAccept/`) - .type("application/json") - .send({ ids: BatchAcceptHackerArrayValid }) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.HACKER_UPDATE_BATCH - ); - res.body.should.have.property("data"); - chai.assert.equal( - JSON.stringify(res.body.data), - JSON.stringify({ - success_ids: BatchAcceptHackerArrayValid, - errors: [] - }) - ); - done(); - }); - }); - }); - it("should SUCCEED and accept 0 out of 2 hackers on /api/hacker/batchAccept as an Admin", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/hacker/batchAccept/`) - .type("application/json") - .send({ ids: BatchAcceptHackerArrayInvalid }) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.HACKER_UPDATE_BATCH - ); - res.body.should.have.property("data"); - res.body.data.should.have.property("success_ids"); - chai.assert.equal(res.body.data.success_ids.length, 0); - res.body.data.should.have.property("errors"); - chai.assert.equal(res.body.data.errors.length, 2); - done(); - }); - }); - }); -}); - -describe("PATCH update one hacker", function() { - async function storeAll() { - await util.roleBinding.storeAll(); - await util.role.storeAll(); - await util.settings.storeAll(); - await util.hacker.storeAll(); - await util.account.storeOneOfEach(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - // fail on authentication - it("should FAIL to update a hacker on /api/hacker/:id GET due to authentication", function(done) { - chai.request(server.app) - .patch(`/api/hacker/${TeamHacker0._id}`) - .type("application/json") - .send({ - application: TeamHacker0.application - }) - .end(function(err, res) { - res.should.have.status(401); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - done(); - }); - }); - - //should FAIL on authentication - it("should FAIL to accept a hacker on /api/hacker/accept/:id due to authentication", function(done) { - chai.request(server.app) - .patch(`/api/hacker/accept/${TeamHacker0._id}`) - .type("application/json") - .send() - .end(function(err, res) { - res.should.have.status(401); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - done(); - }); - }); - - // should FAIL due to authorization - it("should FAIL to accept hacker info due to lack of authorization on /api/hacker/accept/:id", function(done) { - util.auth.login(agent, noTeamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/hacker/accept/${TeamHacker0._id}`) - .type("application/json") - .send() - .end(function(err, res) { - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.AUTH_403_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - }); - }); - - it("should FAIL to accept an invalid hacker's info on /api/hacker/accept/:id", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/hacker/accept/${invalidHacker1._id}`) - .type("application/json") - .send() - .end(function(err, res) { - res.should.have.status(404); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.ACCOUNT_404_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - }); - }); - - it("should SUCCEED and accept a hacker on /api/hacker/accept/:id as an Admin", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/hacker/accept/${TeamHacker0._id}`) - .type("application/json") - .send() - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.HACKER_UPDATE - ); - res.body.should.have.property("data"); - chai.assert.equal( - JSON.stringify(res.body.data), - JSON.stringify({ - status: "Accepted" - }) - ); - done(); - }); - }); - }); - - it("should FAIL to accept a hacker on /api/hacker/acceptEmail/:email due to authentication", function(done) { - chai.request(server.app) - .patch(`/api/hacker/acceptEmail/${teamHackerAccount0.email}`) - .type("application/json") - .send() - .end(function(err, res) { - res.should.have.status(401); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - done(); - }); - }); - - // should FAIL due to authorization - it("should FAIL to accept hacker info due to lack of authorization on /api/hacker/acceptEmail/:email", function(done) { - util.auth.login(agent, noTeamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/hacker/acceptEmail/${teamHackerAccount0.email}`) - .type("application/json") - .send() - .end(function(err, res) { - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.AUTH_403_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - }); - }); - - it("should FAIL to accept an invalid hacker's info on /api/hacker/acceptEmail/:email", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch( - `/api/hacker/acceptEmail/${invalidHackerAccount0[0].email}` - ) - .type("application/json") - .send() - .end(function(err, res) { - res.should.have.status(404); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.ACCOUNT_404_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - }); - }); - - it("should SUCCEED and accept a hacker on /api/hacker/acceptEmail/:email as an Admin", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/hacker/acceptEmail/${teamHackerAccount0.email}`) - .type("application/json") - .send() - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.HACKER_UPDATE - ); - res.body.should.have.property("data"); - chai.assert.equal(res.body.data.hacker.status, "Accepted"); - done(); - }); - }); - }); - - // should succeed on admin case - it("should SUCCEED and update a hacker using admin power", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - let app = TeamHacker0.application; - app.accommodation.shirtSize = "M"; - return agent - .patch(`/api/hacker/${TeamHacker0._id}`) - .type("application/json") - .send({ - application: { - general: app.general, - shortAnswer: app.shortAnswer, - other: app.other, - accommodation: { - barriers: app.accommodation.barriers, - impairments: app.accommodation.impairments, - travel: app.accommodation.travel, - shirtSize: "M" - } - } - }) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.HACKER_UPDATE - ); - res.body.should.have.property("data"); - res.body.data.should.have.property("application"); - res.body.data.application.should.have.property( - "accommodation" - ); - res.body.data.application.accommodation.should.have.property( - "shirtSize" - ); - chai.assert.equal( - JSON.stringify( - res.body.data.application.accommodation.shirtSize - ), - '"M"' - ); - done(); - }); - }); - }); - - it("should SUCCEED and update a hacker STATUS as an Admin", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/hacker/status/${TeamHacker0._id}`) - .type("application/json") - .send({ - status: "Accepted" - }) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.HACKER_UPDATE - ); - res.body.should.have.property("data"); - chai.assert.equal( - JSON.stringify(res.body.data), - JSON.stringify({ - status: "Accepted" - }) - ); - done(); - }); - }); - }); - - it("should FAIL and NOT update a hacker STATUS as a Hacker", function(done) { - util.auth.login(agent, teamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/hacker/status/${TeamHacker0._id}`) - .type("application/json") - .send({ - status: "Accepted" - }) - .end(function(err, res) { - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.AUTH_403_MESSAGE - ); - res.body.should.have.property("data"); - done(); - }); - }); - }); - - // hacker changed email, thus cannot change their status until they confirm email - it("should FAIL and NOT update a hacker STATUS as a Hacker due to unconfirmed email", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/hacker/status/${unconfirmedHacker1._id}`) - .type("application/json") - .send({ - status: "Waitlisted" - }) - .end(function(err, res) { - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.ACCOUNT_403_MESSAGE - ); - res.body.should.have.property("data"); - done(); - }); - }); - }); - - // volunteer should successfully checkin hacker - it("should SUCCEED and check in hacker as a volunteer", function(done) { - util.auth.login(agent, volunteerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/hacker/checkin/${TeamHacker0._id}`) - .type("application/json") - .send({ - status: "Checked-in" - }) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.HACKER_UPDATE - ); - res.body.should.have.property("data"); - chai.assert.equal( - JSON.stringify(res.body.data), - JSON.stringify({ - status: "Checked-in" - }) - ); - done(); - }); - }); - }); - - // hacker should fail to checkin hacker - it("should FAIL to check in hacker as a hacker", function(done) { - util.auth.login(agent, teamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/hacker/checkin/${TeamHacker0._id}`) - .type("application/json") - .send({ - status: "Checked-in" - }) - .end(function(err, res) { - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.AUTH_403_MESSAGE - ); - res.body.should.have.property("data"); - done(); - }); - }); - }); - - // hacker should FAIL to checkin hacker due to unconfirmed email - it("should FAIL to check in hacker as a volunteer due to unconfirmed email", function(done) { - util.auth.login(agent, volunteerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/hacker/checkin/${unconfirmedHacker1._id}`) - .type("application/json") - .send({ - status: "Checked-in" - }) - .end(function(err, res) { - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.ACCOUNT_403_MESSAGE - ); - res.body.should.have.property("data"); - done(); - }); - }); - }); - - // should succeed on hacker case - it("should SUCCEED and update the user's hacker info", function(done) { - util.auth.login(agent, noTeamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - let app = noTeamHacker0.application; - return agent - .patch(`/api/hacker/${noTeamHacker0._id}`) - .type("application/json") - .send({ - application: { - general: app.general, - shortAnswer: app.shortAnswer, - other: app.other, - accommodation: { - barriers: app.accommodation.barriers, - impairments: app.accommodation.impairments, - travel: app.accommodation.travel, - shirtSize: "M" - } - } - }) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.HACKER_UPDATE - ); - res.body.should.have.property("data"); - res.body.data.should.have.property("application"); - res.body.data.application.should.have.property( - "accommodation" - ); - res.body.data.application.accommodation.should.have.property( - "shirtSize" - ); - chai.assert.equal( - JSON.stringify( - res.body.data.application.accommodation.shirtSize - ), - '"M"' - ); - done(); - }); - }); - }); - - // should FAIL to change hacker data with an unconfirmed email - it("should FAIL and not update the user's hacker info due to unconfirmed email", function(done) { - util.auth.login(agent, unconfirmedHackerAccount1, (error) => { - if (error) { - agent.close(); - return done(error); - } - let app = unconfirmedHacker1.application; - return agent - .patch(`/api/hacker/${unconfirmedHacker1._id}`) - .type("application/json") - .send({ - application: { - general: app.general, - shortAnswer: app.shortAnswer, - other: app.other, - accommodation: { - barriers: app.accommodation.barriers, - impairments: app.accommodation.impairments, - travel: app.accommodation.travel, - shirtSize: "M" - } - } - }) - .end(function(err, res) { - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.ACCOUNT_403_MESSAGE - ); - res.body.should.have.property("data"); - done(); - }); - }); - }); - - // should fail due to authorization - it("should Fail to update hacker info due to lack of authorization", function(done) { - util.auth.login(agent, noTeamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - let app = TeamHacker0.application; - return agent - .patch(`/api/hacker/${TeamHacker0._id}`) - .type("application/json") - .send({ - application: { - general: app.general, - shortAnswer: app.shortAnswer, - other: app.other, - accommodation: { - barriers: app.accommodation.barriers, - impairments: app.accommodation.impairments, - travel: app.accommodation.travel, - shirtSize: "M" - } - } - }) - .end(function(err, res) { - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.AUTH_403_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - }); - }); - - // fail due to lack of hacker - it("should fail to change an invalid hacker's info", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .get(`/api/hacker/${invalidHacker1._id}`) - .end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(404); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.HACKER_404_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - }); - }); - - // Succeed and change accepted to confirm - it("should succeed for hacker to update their own status from accepted to confirmed", function(done) { - util.auth.login(agent, noTeamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/hacker/confirmation/${noTeamHacker0._id}`) - .type("application/json") - .send({ - confirm: true - }) - .end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.HACKER_UPDATE - ); - res.body.should.have.property("data"); - chai.assert.equal( - JSON.stringify(res.body.data), - JSON.stringify({ - status: Constants.General.HACKER_STATUS_CONFIRMED - }) - ); - - done(); - }); - }); - }); - - // Fail and don't change to accepted - it("should FAIL for hacker to update their own status from accepted to confirmed due to unconfirmed email", function(done) { - util.auth.login(agent, unconfirmedHackerAccount1, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/hacker/confirmation/${unconfirmedHacker1._id}`) - .type("application/json") - .send({ - confirm: true - }) - .end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.ACCOUNT_403_MESSAGE - ); - res.body.should.have.property("data"); - done(); - }); - }); - }); - - // Succeed and change confirmed to accepted - it("should succeed for hacker to update their own status from confirmed to accepted", function(done) { - util.auth.login(agent, teamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/hacker/confirmation/${TeamHacker0._id}`) - .type("application/json") - .send({ - confirm: false - }) - .end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.HACKER_UPDATE - ); - res.body.should.have.property("data"); - chai.assert.equal( - JSON.stringify(res.body.data), - JSON.stringify({ - status: Constants.General.HACKER_STATUS_WITHDRAWN - }) - ); - - done(); - }); - }); - }); - - // fail for a hacker that's not accepted - it("should FAIL to update hacker status when hacker status is not accepted or confirmed", function(done) { - util.auth.login(agent, util.account.waitlistedHacker0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch( - `/api/hacker/confirmation/${util.hacker.waitlistedHacker0._id}` - ) - .type("application/json") - .send({ - confirm: true - }) - .end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(409); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.HACKER_STATUS_409_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - }); - }); - - // fail for a hacker that's not accepted - it("should fail for hacker trying to confirm someone else", function(done) { - util.auth.login(agent, util.account.waitlistedHacker0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/hacker/confirmation/${noTeamHacker0._id}`) - .type("application/json") - .send({ - confirm: true - }) - .end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.AUTH_403_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - }); - }); -}); - -describe("POST add a hacker resume", function() { - async function storeAll() { - await util.roleBinding.storeAll(); - await util.role.storeAll(); - await util.settings.storeAll(); - await util.hacker.storeAll(); - await util.account.storeOneOfEach(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("It should SUCCEED and upload a resume for a hacker", function(done) { - //this takes a lot of time for some reason - util.auth.login(agent, noTeamHacker0, (error) => { - if (error) { - return done(error); - } - return agent - .post(`/api/hacker/resume/${noTeamHacker0._id}`) - .type("multipart/form-data") - .attach( - "resume", - fs.createReadStream(path.join(__dirname, "testResume.pdf")), - { - contentType: "application/pdf" - } - ) - .end(function(err, res) { - res.should.have.status(200); - res.should.have.property("body"); - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.RESUME_UPLOAD - ); - res.body.should.have.property("data"); - res.body.data.should.have.property("filename"); - StorageService.download(res.body.data.filename).then( - (value) => { - const actualFile = fs.readFileSync( - path.join(__dirname, "testResume.pdf") - ); - chai.assert.equal( - value[0].length, - actualFile.length - ); - StorageService.delete(res.body.data.filename) - .then(() => { - done(); - }) - .catch(done); - } - ); - }); - }); - }); -}); - -describe("GET Hacker stats", function() { - async function storeAll() { - await util.roleBinding.storeAll(); - await util.role.storeAll(); - await util.settings.storeAll(); - await util.hacker.storeAll(); - await util.account.storeHackerStaffAccounts(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("It should FAIL and get hacker stats (invalid validation)", function(done) { - //this takes a lot of time for some reason - util.auth.login(agent, Admin0, (error) => { - if (error) { - return done(error); - } - return agent.get(`/api/hacker/stats`).end(function(err, res) { - res.should.have.status(422); - res.should.have.property("body"); - res.body.should.have.property("message"); - done(); - }); - }); - }); - it("It should SUCCEED and get hacker stats", function(done) { - //this takes a lot of time for some reason - util.auth.login(agent, Admin0, (error) => { - if (error) { - return done(error); - } - return agent - .get(`/api/hacker/stats`) - .query({ - model: "hacker", - q: JSON.stringify([]) - }) - .end(function(err, res) { - res.should.have.status(200); - res.should.have.property("body"); - res.body.should.have.property("message"); - res.body.message.should.equal("Retrieved stats"); - res.body.should.have.property("data"); - res.body.data.should.have.property("stats"); - res.body.data.stats.should.have.property("total"); - res.body.data.stats.should.have.property("status"); - res.body.data.stats.should.have.property("school"); - res.body.data.stats.should.have.property("degree"); - res.body.data.stats.should.have.property("gender"); - res.body.data.stats.should.have.property("travel"); - res.body.data.stats.should.have.property("ethnicity"); - res.body.data.stats.should.have.property("jobInterest"); - res.body.data.stats.should.have.property("fieldOfStudy"); - res.body.data.stats.should.have.property("graduationYear"); - res.body.data.stats.should.have.property( - "dietaryRestrictions" - ); - res.body.data.stats.should.have.property("shirtSize"); - res.body.data.stats.should.have.property("age"); - res.body.data.stats.should.have.property("applicationDate"); - done(); - }); - }); - }); - it("It should FAIL and get hacker stats due to invalid Authorization", function(done) { - //this takes a lot of time for some reason - util.auth.login(agent, teamHackerAccount0, (error) => { - if (error) { - return done(error); - } - return agent.get(`/api/hacker/stats`).end(function(err, res) { - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_403_MESSAGE); - res.body.should.have.property("data"); - done(); - }); - }); - }); - it("It should FAIL and get hacker stats due to invalid Authentication", function(done) { - //this takes a lot of time for some reason - chai.request(server.app) - .get(`/api/hacker/stats`) - .end(function(err, res) { - res.should.have.status(401); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - done(); - }); - }); -}); - -describe("POST send week-of email", function() { - async function storeAll() { - await util.roleBinding.storeAll(); - await util.role.storeAll(); - await util.settings.storeAll(); - await util.hacker.storeAll(); - await util.account.storeStaffNoTeamTeamUnconfirmedInvalid(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("It should FAIL to send the week-of email due to invalid Authentication", function(done) { - //this takes a lot of time for some reason - chai.request(server.app) - .post(`/api/hacker/email/weekOf/${noTeamHacker0._id}`) - .end(function(err, res) { - res.should.have.status(401); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - res.body.should.have.property("data"); - done(); - }); - }); - it("It should FAIL to send the week-of email due to invalid Authorization", function(done) { - //this takes a lot of time for some reason - util.auth.login(agent, noTeamHacker0, (error) => { - if (error) { - return done(error); - } - return agent - .post(`/api/hacker/email/weekOf/${noTeamHacker0._id}`) - .end(function(err, res) { - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.AUTH_403_MESSAGE - ); - res.body.should.have.property("data"); - done(); - }); - }); - }); - it("It should SUCCEED to send the week-of email", function(done) { - //this takes a lot of time for some reason - util.auth.login(agent, Admin0, (error) => { - if (error) { - return done(error); - } - return agent - .post(`/api/hacker/email/weekOf/${TeamHacker0._id}`) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.HACKER_SENT_WEEK_OF - ); - res.body.should.have.property("data"); - done(); - }); - }); - }); - - it("It should FAIL to send the week-of email due to unconfirmed email of hacker", function(done) { - //this takes a lot of time for some reason - util.auth.login(agent, Admin0, (error) => { - if (error) { - return done(error); - } - return agent - .post(`/api/hacker/email/weekOf/${unconfirmedHacker1._id}`) - .end(function(err, res) { - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.ACCOUNT_403_MESSAGE - ); - res.body.should.have.property("data"); - done(); - }); - }); - }); -}); - -describe("POST send day-of email", function() { - async function storeAll() { - await util.roleBinding.storeAll(); - await util.role.storeAll(); - await util.settings.storeAll(); - await util.hacker.storeAll(); - await util.account.storeOneOfEach(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("It should FAIL to send the day-of email due to invalid Authentication", function(done) { - //this takes a lot of time for some reason - chai.request(server.app) - .post(`/api/hacker/email/dayOf/${TeamHacker1._id}`) - .end(function(err, res) { - res.should.have.status(401); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - res.body.should.have.property("data"); - done(); - }); - }); - it("It should FAIL to send the day-of email due to invalid Authorization", function(done) { - //this takes a lot of time for some reason - util.auth.login(agent, teamHackerAccount1, (error) => { - if (error) { - return done(error); - } - return agent - .post(`/api/hacker/email/dayOf/${TeamHacker1._id}`) - .end(function(err, res) { - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.AUTH_403_MESSAGE - ); - res.body.should.have.property("data"); - done(); - }); - }); - }); - it("It should SUCCEED to send the day-of email", function(done) { - //this takes a lot of time for some reason - util.auth.login(agent, Admin0, (error) => { - if (error) { - return done(error); - } - return agent - .post(`/api/hacker/email/dayOf/${TeamHacker1._id}`) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.HACKER_SENT_DAY_OF - ); - res.body.should.have.property("data"); - done(); - }); - }); - }); - - it("It should FAIL to send the day-of email due to unconfirmed email of hacker", function(done) { - //this takes a lot of time for some reason - util.auth.login(agent, Admin0, (error) => { - if (error) { - return done(error); - } - return agent - .post(`/api/hacker/email/dayOf/${unconfirmedHacker1._id}`) - .end(function(err, res) { - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.ACCOUNT_403_MESSAGE - ); - res.body.should.have.property("data"); - done(); - }); - }); - }); -}); diff --git a/src/tests/role.test.js b/src/tests/role.test.js deleted file mode 100644 index bcbf217a..00000000 --- a/src/tests/role.test.js +++ /dev/null @@ -1,144 +0,0 @@ -"use strict"; -const chai = require("chai"); -const chaiHttp = require("chai-http"); -chai.use(chaiHttp); -const server = require("../app"); -const Role = require("../models/role.model"); -const agent = chai.request.agent(server.app); -const should = chai.should(); - -const util = { - role: require("./util/role.test.util"), - account: require("./util/account.test.util"), - auth: require("./util/auth.test.util"), - roleBinding: require("./util/roleBinding.test.util") -}; - -const Constants = { - Error: require("../constants/error.constant"), - Success: require("../constants/success.constant") -}; - -const Admin0 = util.account.staffAccounts.stored[0]; -const Hacker0 = util.account.hackerAccounts.stored.team[0]; - -describe("POST create role", function() { - async function storeAll() { - await util.account.storeHackerStaffAccounts(); - await util.roleBinding.storeAll(); - await util.role.storeAll(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("should Fail to create a role because staff is not logged in", function(done) { - chai.request(server.app) - .post(`/api/role/`) - .type("application/json") - .send(util.role.newRole1) - .end(function(err, res) { - res.should.have.status(401); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - - done(); - }); - }); - - // should succeed on logged in admin - it("should SUCCEED and add new role", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .post(`/api/role/`) - .type("application/json") - .send(util.role.newRole1) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.ROLE_CREATE - ); - - res.body.should.have.property("data"); - - // create JSON version of model - // delete id as they will be different between model objects - // delete ids of route objects in 'routes' - const role = new Role(util.role.newRole1).toJSON(); - delete res.body.data.id; - for (var route of res.body.data.routes) { - delete route._id; - } - delete role.id; - for (route of role.routes) { - delete route._id; - } - - chai.assert.equal( - JSON.stringify(res.body.data), - JSON.stringify(role) - ); - done(); - }); - }); - }); - - // should FAIL due to lack of authorization - it("should Fail to add new role due to lack of authorization", function(done) { - util.auth.login(agent, Hacker0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .post(`/api/role/`) - .type("application/json") - .send(util.role.newRole1) - .end(function(err, res) { - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.AUTH_403_MESSAGE - ); - done(); - }); - }); - }); - - // should succeed despite duplicate routes - it("should Suceed to add new role despite to duplicate routes", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .post(`/api/role/`) - .type("application/json") - .send(util.role.duplicateRole1) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.ROLE_CREATE - ); - done(); - }); - }); - }); -}); diff --git a/src/tests/search.service.spec.js b/src/tests/search.service.spec.js deleted file mode 100644 index 4b681eea..00000000 --- a/src/tests/search.service.spec.js +++ /dev/null @@ -1,334 +0,0 @@ -"use strict"; - -const chai = require("chai"); -const chaiHttp = require("chai-http"); -chai.use(chaiHttp); -const server = require("../app"); - -const agent = chai.request.agent(server.app); -const assert = require("chai").assert; -const should = chai.should(); -const logger = require("../services/logger.service"); - -const Constants = { - Error: require("../constants/error.constant") -}; - -const util = { - hacker: require("./util/hacker.test.util"), - account: require("./util/account.test.util"), - auth: require("./util/auth.test.util"), - role: require("./util/role.test.util"), - roleBinding: require("./util/roleBinding.test.util"), - settings: require("./util/settings.test.util") -}; - -const queryToExecute = [ - { - param: "application.general.degree", - operation: "equals", - value: "Undergraduate" - } -]; - -const query2 = [ - { - param: "application.general.school", - operation: "ne", - value: "McGill" - } -]; - -const badQuery = [ - { - param: "password", - operation: "equals", - value: "passowrd" - } -]; - -const Admin0 = util.account.staffAccounts.stored[0]; - -const noTeamHackerAccount0 = util.account.hackerAccounts.stored.noTeam[0]; - -describe("Searching for hackers", function() { - async function storeAll() { - await util.roleBinding.storeAll(); - await util.role.storeAll(); - await util.settings.storeAll(); - await util.hacker.storeAll(); - await util.account.storeOneOfEach(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("Should FAIL to search due to invalid authentication", function(done) { - util.auth.login( - agent, - { - email: "abc", - password: "def" - }, - (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .get("/api/search") - .query({ - model: "account", - q: JSON.stringify(queryToExecute) - }) - .end(function(err, res) { - res.should.have.status(401); - res.body.message.should.equal( - Constants.Error.AUTH_401_MESSAGE - ); - res.body.should.have.property("data"); - done(); - }); - } - ); - }); - - it("Should FAIL to search due to invalid authorization", function(done) { - util.auth.login(agent, noTeamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .get("/api/search") - .query({ - model: "account", - q: JSON.stringify(queryToExecute) - }) - .end(function(err, res) { - res.should.have.status(403); - res.body.message.should.equal( - Constants.Error.AUTH_403_MESSAGE - ); - res.body.should.have.property("data"); - done(); - }); - }); - }); - it("Should return all undergraduate hackers", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .get("/api/search") - .query({ - model: "hacker", - q: JSON.stringify(queryToExecute) - }) - .end(function(err, res) { - res.should.have.status(200); - res.body.should.have.property("data"); - res.body.data.should.have.length(2); - done(); - }); - }); - }); - - it("Should return an error as hackers don't have password stored", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .get("/api/search") - .query({ - model: "hacker", - q: JSON.stringify(badQuery) - }) - .end(function(err, res) { - res.should.have.status(422); - done(); - }); - }); - }); - - it("Should return an error as staff aren't searchable", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .get("/api/search") - .query({ - model: "staff", - q: JSON.stringify(badQuery) - }) - .end(function(err, res) { - res.should.have.status(422); - res.body.data.model.msg.should.equal( - "Must be a valid searchable model" - ); - done(); - }); - }); - }); - it("Should throw an error because model is not lowercase", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .get("/api/search") - .query({ - model: "Hacker", - q: JSON.stringify(query2) - }) - .end(function(err, res) { - res.should.have.status(422); - res.body.data.model.msg.should.equal( - "Model must be lower case" - ); - done(); - }); - }); - }); - it("Should throw an error because of a fake model", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .get("/api/search") - .query({ - model: "hackerz", - q: JSON.stringify(query2) - }) - .end(function(err, res) { - res.should.have.status(422); - res.body.data.model.msg.should.equal( - "Must be a valid searchable model" - ); - done(); - }); - }); - }); - it("Should only return 1 hacker (page size)", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .get("/api/search") - .query({ - model: "hacker", - q: JSON.stringify(query2), - limit: 1 - }) - .end(function(err, res) { - res.should.have.status(200); - res.body.data.should.have.length(1); - done(); - }); - }); - }); - it("Should only return 1 hacker (pagination)", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return ( - agent - .get("/api/search") - //There are two test samples so by making limit 1, there will be something on the second page - .query({ - model: "hacker", - q: JSON.stringify(query2), - limit: 1, - page: 1 - }) - .end(function(err, res) { - res.should.have.status(200); - res.body.data.should.have.length(1); - done(); - }) - ); - }); - }); - it("Should throw an error because out of bounds (page size)", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .get("/api/search") - .query({ - model: "hacker", - q: JSON.stringify(query2), - limit: 5000 - }) - .end(function(err, res) { - res.should.have.status(422); - done(); - }); - }); - }); - it("Should throw an error because out of bounds (pagination)", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .get("/api/search") - .query({ - model: "hacker", - q: JSON.stringify(query2), - limit: 1, - page: -1 - }) - .end(function(err, res) { - res.should.have.status(422); - done(); - }); - }); - }); - - it("Should expand the accountId when expand is set to true", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .get("/api/search") - .query({ - model: "hacker", - q: JSON.stringify(queryToExecute), - expand: true - }) - .end(function(err, res) { - res.should.have.status(200); - res.body.should.have.property("data"); - res.body.data.should.have.length(2); - res.body.data[0].should.have.property("accountId"); - res.body.data[0].accountId.should.have.property("email"); - done(); - }); - }); - }); -}); diff --git a/src/tests/settings.test.js b/src/tests/settings.test.js deleted file mode 100644 index 13bce7df..00000000 --- a/src/tests/settings.test.js +++ /dev/null @@ -1,159 +0,0 @@ -"use strict"; -const chai = require("chai"); -const chaiHttp = require("chai-http"); -chai.use(chaiHttp); -const server = require("../app"); -const agent = chai.request.agent(server.app); -chai.should(); -const util = { - account: require("./util/account.test.util"), - auth: require("./util/auth.test.util"), - settings: require("./util/settings.test.util"), - role: require("./util/role.test.util"), - roleBinding: require("./util/roleBinding.test.util") -}; - -const Constants = { - Success: require("../constants/success.constant"), - Error: require("../constants/error.constant"), - Settings: require("../constants/settings.constant") -}; - -const invalidAccount = util.account.hackerAccounts.stored.noTeam[0]; -const Admin = util.account.staffAccounts.stored[0]; - -describe("GET settings", function() { - async function storeAll() { - await util.account.storeHackerStaffExtraAccount(); - await util.settings.storeAll(); - await util.role.storeAll(); - await util.roleBinding.storeAll(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("should get the current settings", function(done) { - chai.request(server.app) - .get(`/api/settings/`) - // does not have password because of to stripped json - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Success.SETTINGS_GET); - done(); - }); - }); -}); - -describe("PATCH settings", function() { - async function storeAll() { - await util.account.storeHackerStaffExtraAccount(); - await util.settings.storeAll(); - await util.role.storeAll(); - await util.roleBinding.storeAll(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("should FAIL to update the settings due to lack of authentication", function(done) { - chai.request(server.app) - .patch(`/api/settings/`) - // does not have password because of to stripped json - .end(function(err, res) { - res.should.have.status(401); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - done(); - }); - }); - it("should FAIL to update the settings due to lack of authorization", function(done) { - util.auth.login(agent, invalidAccount, (error) => { - if (error) { - agent.close(); - return done(error); - } - return ( - agent - .patch(`/api/settings/`) - .type("application/json") - .send({ - openTime: new Date().toString(), - closeTime: new Date().toString(), - confirmTime: new Date().toString() - }) - // does not have password because of to stripped json - .end(function(err, res) { - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.AUTH_403_MESSAGE - ); - done(); - }) - ); - }); - }); - it("should succeed to update the settings", function(done) { - util.auth.login(agent, Admin, (error) => { - if (error) { - agent.close(); - return done(error); - } - return ( - agent - .patch(`/api/settings/`) - .type("application/json") - .send(Constants.Settings.CONFIRM_CLOSED) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.SETTINGS_PATCH - ); - done(); - }) - ); - }); - }); - it("should succeed to make the hackathon remote", function(done) { - util.auth.login(agent, Admin, (error) => { - if (error) { - agent.close(); - return done(error); - } - return ( - agent - .patch(`/api/settings/`) - .type("application/json") - .send(Constants.Settings.REMOTE_HACKATHON) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.SETTINGS_PATCH - ); - done(); - }) - ); - }); - }); -}); diff --git a/src/tests/setup.spec.js b/src/tests/setup.spec.js deleted file mode 100644 index ea387b65..00000000 --- a/src/tests/setup.spec.js +++ /dev/null @@ -1,73 +0,0 @@ -"use strict"; -const winston = require("winston"); -winston.remove(winston.transports.Console); -const server = require("../app.js"); -const Util = { - Account: require("./util/account.test.util"), - Bus: require("./util/bus.test.util"), - Hacker: require("./util/hacker.test.util"), - Role: require("./util/role.test.util"), - RoleBinding: require("./util/roleBinding.test.util"), - Settings: require("./util/settings.test.util"), - Sponsor: require("./util/sponsor.test.util"), - Staff: require("./util/staff.test.util"), - Team: require("./util/team.test.util"), - Volunteer: require("./util/volunteer.test.util"), - AccountConfirmation: require("./util/accountConfirmation.test.util"), - ResetPassword: require("./util/resetPassword.test.util.js") -}; -const logger = require("../services/logger.service"); - -//make sure that we are connected to the database -before(function(done) { - this.timeout(60000); - - server.app.on("event:connected to db", () => { - /** - * Give the database time to create an index on existing schemas before we delete them. - * Hacky way to get around a new error. - */ - setTimeout(() => { - dropAll() - .then(done) - .catch(done); - }, 1000); - }); -}); - -after(function(done) { - this.timeout(60000); - dropAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); -}); - -afterEach(function(done) { - this.timeout(60000); - dropAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); -}); - -async function dropAll() { - await Util.RoleBinding.dropAll(); - await Util.Role.dropAll(); - await Util.ResetPassword.dropAll(); - await Util.AccountConfirmation.dropAll(); - await Util.Volunteer.dropAll(); - await Util.Settings.dropAll(); - await Util.Staff.dropAll(); - await Util.Team.dropAll(); - await Util.Sponsor.dropAll(); - await Util.Bus.dropAll(); - await Util.Hacker.dropAll(); - await Util.Account.dropAll(); -} diff --git a/src/tests/sponsor.test.js b/src/tests/sponsor.test.js deleted file mode 100644 index bf27c9f0..00000000 --- a/src/tests/sponsor.test.js +++ /dev/null @@ -1,533 +0,0 @@ -"use strict"; -const chai = require("chai"); -const chaiHttp = require("chai-http"); -chai.use(chaiHttp); -const server = require("../app"); -const agent = chai.request.agent(server.app); -const Sponsor = require("../models/sponsor.model"); -const should = chai.should(); -const mongoose = require("mongoose"); -const Constants = { - Success: require("../constants/success.constant"), - Error: require("../constants/error.constant") -}; - -const util = { - sponsor: require("./util/sponsor.test.util"), - auth: require("./util/auth.test.util"), - account: require("./util/account.test.util"), - role: require("./util/role.test.util"), - roleBinding: require("./util/roleBinding.test.util") -}; - -const Admin0 = util.account.staffAccounts.stored[0]; -const HackerAccount0 = util.account.hackerAccounts.stored.team[0]; -const T1SponsorAccount0 = util.account.sponsorT1Accounts.stored[0]; -const newT2SponsorAccount0 = util.account.sponsorT2Accounts.new[0]; -const T1Sponsor0 = util.sponsor.T1Sponsor0; -const newT2Sponsor0 = util.sponsor.newT2Sponsor0; - -let duplicateSponsor = util.sponsor.duplicateAccountLinkSponsor1; - -describe("GET user's sponsor info", function() { - async function storeAll() { - await util.roleBinding.storeAll(); - await util.role.storeAll(); - await util.sponsor.storeAll(); - await util.account.storeSponsorAccount(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("should FAIL list a sponsor's information due to authentication from /api/sponsor/self GET", function(done) { - chai.request(server.app) - .get(`/api/sponsor/self`) - // does not have password because of to stripped json - .end(function(err, res) { - res.should.have.status(401); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - - done(); - }); - }); - - it("should FAIL to list a sponsor's info due to authorization /api/sponsor/self GET", function(done) { - util.auth.login(agent, HackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent.get(`/api/sponsor/self`).end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_403_MESSAGE); - res.body.should.have.property("data"); - - done(); - }); - }); - }); - - it("should FAIL to list a sponsor's info due to wrong account type on /api/sponsor/self GET", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent.get(`/api/sponsor/self`).end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(409); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.ACCOUNT_TYPE_409_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - }); - }); - - it("should FAIL to list a sponsor's info due to lack of sponsor on /api/sponsor/self GET", function(done) { - util.auth.login(agent, newT2SponsorAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent.get(`/api/sponsor/self`).end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(404); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.SPONSOR_404_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - }); - }); - - it("should SUCCEED to list user's sponsor info /api/sponsor/self GET", function(done) { - util.auth.login(agent, T1SponsorAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent.get(`/api/sponsor/self`).end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Success.SPONSOR_READ); - res.body.should.have.property("data"); - res.body.data.should.be.a("object"); - - let sponsor = new Sponsor(T1Sponsor0); - chai.assert.equal( - JSON.stringify(res.body.data), - JSON.stringify(sponsor.toJSON()) - ); - done(); - }); - }); - }); -}); - -describe("GET sponsor by id", function() { - async function storeAll() { - await util.roleBinding.storeAll(); - await util.role.storeAll(); - await util.sponsor.storeAll(); - await util.account.storeSponsorAccount(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("should FAIL list a sponsor's information due to authentication from /api/sponsor/:id GET", function(done) { - chai.request(server.app) - .get(`/api/sponsor/` + T1Sponsor0._id) - // does not have password because of to stripped json - .end(function(err, res) { - res.should.have.status(401); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - - done(); - }); - }); - - // admin success - it("should succeed to list a sponsor's info using admin power on /api/sponsor/:id GET", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .get(`/api/sponsor/${T1Sponsor0._id}`) - .end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.SPONSOR_READ - ); - res.body.should.have.property("data"); - res.body.data.should.be.a("object"); - - let sponsor = new Sponsor(T1Sponsor0); - chai.assert.equal( - JSON.stringify(res.body.data), - JSON.stringify(sponsor.toJSON()) - ); - done(); - }); - }); - }); - - // regular user access success - it("should succeed to list a user's sponsor info on /api/sponsor/:id GET", function(done) { - util.auth.login(agent, T1SponsorAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .get(`/api/sponsor/${util.sponsor.T1Sponsor0._id}`) - .end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.SPONSOR_READ - ); - res.body.should.have.property("data"); - res.body.data.should.be.a("object"); - - let sponsor = new Sponsor(T1Sponsor0); - chai.assert.equal( - JSON.stringify(res.body.data), - JSON.stringify(sponsor.toJSON()) - ); - done(); - }); - }); - }); - - // failure due to lack of auth - it("should FAIL to list a user's sponsor info due to lack of authorization /api/sponsor/:id GET", function(done) { - util.auth.login(agent, HackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .get(`/api/sponsor/${util.sponsor.T1Sponsor0._id}`) - .end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.AUTH_403_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - }); - }); - - // failure due to lack of this sponsor - it("should FAIL to list non existant info on /api/sponsor/:id GET", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .get(`/api/sponsor/${mongoose.Types.ObjectId()}`) - .end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(404); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.SPONSOR_404_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - }); - }); -}); - -describe("POST create sponsor", function() { - async function storeAll() { - await util.roleBinding.storeAll(); - await util.role.storeAll(); - await util.sponsor.storeAll(); - await util.account.storeSponsorAccount(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("should FAIL to create a new sponsor due to lack of authentication", function(done) { - chai.request(server.app) - .post(`/api/sponsor`) - .type("application/json") - .send(util.sponsor.newSponsor) - .end(function(err, res) { - res.should.have.status(401); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - - done(); - }); - }); - - // success case with self caes - there is no admin case - it("should SUCCEED and create a new sponsor", function(done) { - util.auth.login(agent, newT2SponsorAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .post(`/api/sponsor/`) - .type("application/json") - .send(newT2Sponsor0) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.SPONSOR_CREATE - ); - res.body.should.have.property("data"); - - // deleting id because that was generated, and not part of original data - const sponsor = new Sponsor(newT2Sponsor0).toJSON(); - delete res.body.data.id; - delete sponsor.id; - chai.assert.equal( - JSON.stringify(res.body.data), - JSON.stringify(sponsor) - ); - done(); - }); - }); - }); - - // fail case - duplicate accountId - it("should FAIL to create a sponsor due to duplicate accountId", function(done) { - util.auth.login(agent, T1SponsorAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .post(`/api/sponsor/`) - .type("application/json") - .send(duplicateSponsor) - .end(function(err, res) { - res.should.have.status(409); - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.SPONSOR_ID_409_MESSAGE - ); - res.body.should.have.property("data"); - done(); - }); - }); - }); - - // unauthorized case - it("should FAIL to create a new sponsor", function(done) { - util.auth.login(agent, HackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .post(`/api/sponsor/`) - .type("application/json") - .send(newT2Sponsor0) - .end(function(err, res) { - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.AUTH_403_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - }); - }); -}); - -describe("PATCH update sponsor", function() { - async function storeAll() { - await util.roleBinding.storeAll(); - await util.role.storeAll(); - await util.sponsor.storeAll(); - await util.account.storeSponsorAccount(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("should FAIL to update a sponsor due to lack of authentication", function(done) { - chai.request(server.app) - .patch(`/api/sponsor/${T1Sponsor0._id}/`) - .type("application/json") - .send({ - company: "NewCompanyName" - }) - .end(function(err, res) { - res.should.have.status(401); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - - done(); - }); - }); - - it("should FAIL to update a sponsor due to authorization", function(done) { - util.auth.login(agent, newT2SponsorAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/sponsor/${T1Sponsor0._id}/`) - .type("application/json") - .send({ - company: "NewCompanyName" - }) - .end(function(err, res) { - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.AUTH_403_MESSAGE - ); - - done(); - }); - }); - }); - - it("should FAIL to update a sponsor due wrong id", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/sponsor/${Admin0._id}/`) - .type("application/json") - .send({ - company: "NewCompanyName" - }) - .end(function(err, res) { - res.should.have.status(500); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.SPONSOR_UPDATE_500_MESSAGE - ); - - done(); - }); - }); - }); - - // success case with self caes - there is no admin case - it("should SUCCEED and update a sponsor", function(done) { - util.auth.login(agent, T1SponsorAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/sponsor/${T1Sponsor0._id}/`) - .type("application/json") - .send({ - company: "NewCompanyName" - }) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.SPONSOR_UPDATE - ); - res.body.should.have.property("data"); - - res.body.data.should.have.property("company"); - res.body.data.company.should.equal("NewCompanyName"); - - done(); - }); - }); - }); -}); diff --git a/src/tests/storage.spec.js b/src/tests/storage.spec.js deleted file mode 100644 index 8f6713c4..00000000 --- a/src/tests/storage.spec.js +++ /dev/null @@ -1,51 +0,0 @@ -"use strict"; -const path = require("path"); -//load up env variables -require("../services/env.service").load(path.join(__dirname, "../.env")); - -const StorageService = require("../services/storage.service"); - -const assert = require("chai").assert; - -var fs = require("fs"); - -describe("Storage service", function() { - this.timeout(0); - const file = { - mimetype: "application/pdf", - buffer: fs.readFileSync(__dirname + "/testResume.pdf") - }; - it("Should upload new file", (done) => { - const gcfilename = "resumes/testResume.pdf"; - StorageService.upload(file, gcfilename) - .then((addr) => { - assert.equal(addr, StorageService.getPublicUrl(gcfilename)); - done(); - }) - .catch(done); - }); - it("should get test file", (done) => { - StorageService.download("resumes/testResume.pdf") - .then((buffer) => { - assert.deepEqual( - buffer[0], - file.buffer, - "Two buffers are not equal" - ); - done(); - }) - .catch(done); - }); - it("should delete test file", (done) => { - StorageService.delete("resumes/testResume.pdf") - .then(() => { - StorageService.exists("resumes/testResume.pdf") - .then((exists) => { - assert.isFalse(exists[0]); - done(); - }) - .catch(done); - }) - .catch(done); - }); -}); diff --git a/src/tests/team.test.js b/src/tests/team.test.js deleted file mode 100644 index 5223ae26..00000000 --- a/src/tests/team.test.js +++ /dev/null @@ -1,667 +0,0 @@ -"use strict"; -const chai = require("chai"); -const chaiHttp = require("chai-http"); -const should = chai.should(); -chai.use(chaiHttp); -const server = require("../app"); -const Team = require("../models/team.model"); - -const util = { - team: require("./util/team.test.util"), - hacker: require("./util/hacker.test.util"), - account: require("./util/account.test.util"), - auth: require("./util/auth.test.util"), - role: require("./util/role.test.util"), - roleBinding: require("./util/roleBinding.test.util") -}; - -const Constants = { - Success: require("../constants/success.constant"), - Error: require("../constants/error.constant") -}; - -const agent = chai.request.agent(server.app); - -const Admin0 = util.account.staffAccounts.stored[0]; -const teamHackerAccount0 = util.account.hackerAccounts.stored.team[0]; -const noTeamHackerAccount0 = util.account.hackerAccounts.stored.noTeam[0]; -const sponsorT1Account0 = util.account.sponsorT1Accounts.stored[0]; - -describe("GET team", function() { - async function storeAll() { - await util.roleBinding.storeAll(); - await util.role.storeAll(); - await util.team.storeAll(); - await util.account.storeTeamAccount(); - await util.hacker.storeAll(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("should FAIL to list a team's information due to lack of authentication", function(done) { - chai.request(server.app) - .get(`/api/team/${util.team.Team3._id}`) - .end(function(err, res) { - res.should.have.status(401); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - res.body.should.have.property("data"); - - done(); - }); - }); - - it("should Fail and list a team's information from /api/team/ GET due to non existant team id", function(done) { - util.auth.login( - agent, - util.account.hackerAccounts.stored.team[0], - (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .get(`/api/team/${util.team.newTeam1._id}`) - .end(function(err, res) { - res.should.have.status(404); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.TEAM_404_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - } - ); - }); - - it("should SUCCEED and list a team's information from /api/team/ GET", function(done) { - util.auth.login(agent, util.account.waitlistedHacker0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .get(`/api/team/${util.team.Team3._id}`) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Success.TEAM_READ); - res.body.should.have.property("data"); - res.body.data.should.have.property("team"); - res.body.data.team.name.should.equal("FullTeam"); - res.body.data.team.should.have.property("members"); - res.body.data.team.members[0].should.equal( - util.hacker.TeamHacker1._id.toString() - ); - res.body.data.team.members[1].should.equal( - util.hacker.TeamHacker2._id.toString() - ); - res.body.data.team.members[2].should.equal( - util.hacker.TeamHacker3._id.toString() - ); - res.body.data.team.members[3].should.equal( - util.hacker.TeamHacker4._id.toString() - ); - - res.body.data.should.have.property("members"); - res.body.data.members[0].firstName.should.equal( - util.account.hackerAccounts.stored.team[1].firstName - ); - res.body.data.members[0].lastName.should.equal( - util.account.hackerAccounts.stored.team[1].lastName - ); - res.body.data.members[0].status.should.equal( - util.hacker.TeamHacker1.status - ); - res.body.data.members[0].school.should.equal( - util.hacker.TeamHacker1.application.general.school - ); - res.body.data.members[1].firstName.should.equal( - util.account.hackerAccounts.stored.team[2].firstName - ); - res.body.data.members[1].lastName.should.equal( - util.account.hackerAccounts.stored.team[2].lastName - ); - res.body.data.members[1].status.should.equal( - util.hacker.TeamHacker2.status - ); - res.body.data.members[1].school.should.equal( - util.hacker.TeamHacker2.application.general.school - ); - res.body.data.members[2].firstName.should.equal( - util.account.hackerAccounts.stored.team[3].firstName - ); - res.body.data.members[2].lastName.should.equal( - util.account.hackerAccounts.stored.team[3].lastName - ); - res.body.data.members[2].status.should.equal( - util.hacker.TeamHacker3.status - ); - res.body.data.members[2].school.should.equal( - util.hacker.TeamHacker3.application.general.school - ); - res.body.data.members[3].firstName.should.equal( - util.account.hackerAccounts.stored.team[4].firstName - ); - res.body.data.members[3].lastName.should.equal( - util.account.hackerAccounts.stored.team[4].lastName - ); - res.body.data.members[3].status.should.equal( - util.hacker.TeamHacker4.status - ); - res.body.data.members[3].school.should.equal( - util.hacker.TeamHacker4.application.general.school - ); - - done(); - }); - }); - }); -}); - -describe("POST create team", function() { - async function storeAll() { - await util.roleBinding.storeAll(); - await util.role.storeAll(); - await util.team.storeAll(); - await util.account.storeTeamAccount(); - await util.hacker.storeAll(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("should FAIL to create a new team due to lack of authentication", function(done) { - chai.request(server.app) - .post(`/api/team/`) - .type("application/json") - .send(util.team.newTeam1) - .end(function(err, res) { - res.should.have.status(401); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - res.body.should.have.property("data"); - - done(); - }); - }); - - it("should FAIL to create a new team due to lack of authorization", function(done) { - util.auth.login(agent, sponsorT1Account0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .post(`/api/team/`) - .type("application/json") - .send(util.team.newTeam1) - .end(function(err, res) { - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.AUTH_403_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - }); - }); - - it("should FAIL to create a new team due to logged in user not being a hacker", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .post(`/api/team/`) - .type("application/json") - .send(util.team.newTeam1) - .end(function(err, res) { - res.should.have.status(404); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.HACKER_404_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - }); - }); - - it("should FAIL to create a new team due to duplicate team name", function(done) { - util.auth.login(agent, noTeamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .post(`/api/team/`) - .type("application/json") - .send(util.team.duplicateTeamName1) - .end(function(err, res) { - res.should.have.status(409); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.TEAM_NAME_409_MESSAGE - ); - res.body.should.have.property("data"); - res.body.data.should.equal( - util.team.duplicateTeamName1.name - ); - - done(); - }); - }); - }); - - it("should Fail to create a new team due to hacker already being in a team", function(done) { - util.auth.login(agent, teamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .post(`/api/team/`) - .type("application/json") - .send(util.team.newTeam1) - .end(function(err, res) { - res.should.have.status(409); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.TEAM_MEMBER_409_MESSAGE - ); - res.body.should.have.property("data"); - done(); - }); - }); - }); - - it("should SUCCEED and create a new team", function(done) { - util.auth.login(agent, noTeamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .post(`/api/team/`) - .type("application/json") - .send(util.team.newTeam1) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.TEAM_CREATE - ); - res.body.should.have.property("data"); - - // deleting _id because that was generated, and not part of original data - const team = new Team(util.team.createdNewTeam1).toJSON(); - delete res.body.data.id; - delete team.id; - chai.assert.equal( - JSON.stringify(res.body.data), - JSON.stringify(team) - ); - done(); - }); - }); - }); -}); - -describe("PATCH join team", function() { - async function storeAll() { - await util.roleBinding.storeAll(); - await util.role.storeAll(); - await util.team.storeAll(); - await util.hacker.storeAll(); - await util.account.storeOneOfEach(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("should FAIL to join a hacker to a team due to lack of authentication", function(done) { - chai.request(server.app) - .patch(`/api/team/join/`) - .type("application/json") - .send({ - name: "BronzeTeam" - }) - .end(function(err, res) { - res.should.have.status(401); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - res.body.should.have.property("data"); - - done(); - }); - }); - - it("should FAIL to join a volunteer to a team.", function(done) { - util.auth.login( - agent, - util.account.volunteerAccounts.stored[0], - (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/team/join/`) - .type("application/json") - .send({ - name: "BronzeTeam" - }) - .end(function(err, res) { - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.AUTH_403_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - } - ); - }); - - it("should FAIL to join a hacker to a team that doesn't exist.", function(done) { - util.auth.login(agent, teamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/team/join/`) - .type("application/json") - .send({ - name: "NonExistTeam" - }) - .end(function(err, res) { - res.should.have.status(404); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.TEAM_404_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - }); - }); - - it("should FAIL to join a hacker to a team that is full.", function(done) { - util.auth.login(agent, teamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/team/join/`) - .type("application/json") - .send({ - name: "FullTeam" - }) - .end(function(err, res) { - res.should.have.status(409); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.TEAM_SIZE_409_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - }); - }); - - it("should SUCCEED and join a hacker without a team to a team.", function(done) { - util.auth.login(agent, noTeamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/team/join/`) - .type("application/json") - .send({ - name: "BronzeTeam" - }) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Success.TEAM_JOIN); - res.body.should.have.property("data"); - - done(); - }); - }); - }); - - it("should SUCCEED and join a hacker on a team to aother team.", function(done) { - util.auth.login(agent, teamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/team/join/`) - .type("application/json") - .send({ - name: "SilverTeam" - }) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Success.TEAM_JOIN); - res.body.should.have.property("data"); - - done(); - }); - }); - }); -}); - -describe("PATCH change team info", function() { - async function storeAll() { - await util.roleBinding.storeAll(); - await util.role.storeAll(); - await util.team.storeAll(); - await util.account.storeTeamAccount(); - await util.hacker.storeAll(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("should FAIL to change a hacker's team information due to invalid authentication", function(done) { - chai.request(server.app) - .patch(`/api/team/${util.hacker.TeamHacker4._id}`) - .type("application/json") - .send({ - name: "BronzeTeamASDF" - }) - .end(function(err, res) { - res.should.have.status(401); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - res.body.should.have.property("data"); - - done(); - }); - }); - - it("should FAIL for a hacker to change another team's information due to invalid authorization", function(done) { - util.auth.login( - agent, - util.account.hackerAccounts.stored.team[1], - (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/team/${util.hacker.TeamHacker0._id}`) - .type("application/json") - .send({ - name: "SuccessTeamASDF" - }) - .end(function(err, res) { - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.AUTH_403_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - } - ); - }); - - it("should SUCCEED to change the hacker's team information", function(done) { - util.auth.login( - agent, - util.account.hackerAccounts.stored.team[1], - (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/team/${util.hacker.TeamHacker1._id}`) - .type("application/json") - .send({ - name: "SuccessTeamASDF" - }) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.TEAM_UPDATE - ); - res.body.should.have.property("data"); - res.body.data.should.have.property("name"); - res.body.data.name.should.equal("SuccessTeamASDF"); - done(); - }); - } - ); - }); - - it("should SUCCEED and leave a team.", function(done) { - util.auth.login(agent, teamHackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/team/leave/`) - .type("application/json") - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.TEAM_HACKER_LEAVE - ); - res.body.should.have.property("data"); - done(); - }); - }); - }); - - it("should SUCCEED for an admin to change a team information", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .patch(`/api/team/${util.hacker.TeamHacker3._id}`) - .type("application/json") - .send({ - name: "SuccessTeamASDF" - }) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.TEAM_UPDATE - ); - res.body.should.have.property("data"); - res.body.data.should.have.property("name"); - res.body.data.name.should.equal("SuccessTeamASDF"); - - done(); - }); - }); - }); - - it("should FAIL to leave a team due to invalid authentication.", function(done) { - chai.request(server.app) - .patch(`/api/team/leave/`) - .type("application/json") - .end(function(err, res) { - res.should.have.status(401); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - res.body.should.have.property("data"); - - done(); - }); - }); -}); diff --git a/src/tests/testResume.pdf b/src/tests/testResume.pdf deleted file mode 100644 index 90bdb4d6f45ae113815f5d0ec984309de5ef6231..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 98553 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
$B%17cB?_gT!+)?ItD!c|w&9l31?>zeRp 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 diff --git a/src/tests/util/account.test.util.js b/src/tests/util/account.test.util.js deleted file mode 100644 index cc0140fb..00000000 --- a/src/tests/util/account.test.util.js +++ /dev/null @@ -1,520 +0,0 @@ -"use strict"; -const Constants = require("../../constants/general.constant"); -const Account = require("../../models/account.model"); -const mongoose = require("mongoose"); -const bcrypt = require("bcrypt"); -const logger = require("../../services/logger.service"); - -let counters = { - emailCounter: 0 -}; - -function incrementCounters() { - for (const key in counters) { - if (counters.hasOwnProperty(key)) { - counters[key] = counters[key] + 1; - } - } -} - -function extractAccountInfo(acc) { - let accDetails = {}; - - for (const val in acc) { - // use .hasOwnProperty instead of 'in' to get rid of inherited properties such as 'should' - if (Account.schema.paths.hasOwnProperty(val)) { - accDetails[val] = acc[val]; - } - } - - return accDetails; -} - -function generateRandomValue(atr) { - switch (atr) { - case "_id": - return mongoose.Types.ObjectId(); - case "firstName": - // generates a random string between length 5 and 10 of random characters from a-z - return Math.random() - .toString(36) - .replace(/[^a-z]+/g, "") - .substr(0, Math.floor(Math.random() * 6 + 5)); - case "lastName": - return Math.random() - .toString(36) - .replace(/[^a-z]+/g, "") - .substr(0, Math.floor(Math.random() * 6 + 5)); - case "pronoun": - // generate random string between length 2 and 4 - return Math.random() - .toString(36) - .replace(/[^a-z]+/g, "") - .substr(0, Math.floor(Math.random() * 3 + 2)); - case "gender": - return "Female"; - case "email": - const email = `abc.def${counters.emailCounter}@blahblah.com`; - return email; - case "password": - return Math.random() - .toString(36) - .substr(0, 10); - case "dietaryRestrictions": - return [ - Constants.SAMPLE_DIET_RESTRICTIONS[ - Math.floor( - Math.random() * - Constants.SAMPLE_DIET_RESTRICTIONS.length - ) - ] - ]; - case "gender": - // generate random string between length 2 and 10 - return Math.random() - .toString(36) - .replace(/[^a-z]+/g, "") - .substr(0, Math.floor(Math.random() * 9 + 2)); - case "confirmed": - // return false, because if an account is confirmed there should be a document of that account type, - // which this does not create - return Math.random() < 0.5; - case "accountType": - return Constants.EXTENDED_USER_TYPES[ - Math.floor(Math.random() * Constants.EXTENDED_USER_TYPES.length) - ]; - case "birthDate": - return new Date(); - case "phoneNumber": - return Math.floor(Math.random() * 10000000000); - } -} - -function createAccount(acc = {}) { - incrementCounters(); - const extractedAcc = extractAccountInfo(acc); - - for (const atr in Account.schema.paths) { - if (!Account.schema.paths.hasOwnProperty(atr)) { - continue; - } - - // if this value has been passed in, continue - if (extractedAcc[atr] !== undefined) { - continue; - } - - extractedAcc[atr] = generateRandomValue(atr); - } - - return extractedAcc; -} - -function createNAccounts(n, acc = {}) { - let accounts = []; - for (let i = 0; i < n; i++) { - accounts.push(createAccount(acc)); - } - - return accounts; -} - -let hackerAccounts = { - new: createNAccounts(10, { - accountType: Constants.HACKER, - confirmed: true - }), - stored: { - team: createNAccounts(10, { - accountType: Constants.HACKER, - confirmed: true - }), - noTeam: createNAccounts(10, { - accountType: Constants.HACKER, - confirmed: true - }), - unconfirmed: createNAccounts(5, { - accountType: Constants.HACKER, - confirmed: false - }) - }, - invalid: createNAccounts(10, { - accountType: Constants.HACKER - }) -}; - -let volunteerAccounts = { - new: createNAccounts(5, { - accountType: Constants.VOLUNTEER, - confirmed: true - }), - stored: createNAccounts(5, { - accountType: Constants.VOLUNTEER, - confirmed: true - }), - invalid: createNAccounts(5, { - accountType: Constants.VOLUNTEER - }) -}; - -let staffAccounts = { - stored: createNAccounts(5, { - accountType: Constants.STAFF, - confirmed: true - }) -}; - -let sponsorT1Accounts = { - new: createNAccounts(5, { - accountType: Constants.SPONSOR_T1, - confirmed: false - }), - stored: createNAccounts(5, { - accountType: Constants.SPONSOR_T1, - confirmed: true - }), - invalid: createNAccounts(5, { - accountType: Constants.SPONSOR_T1 - }) -}; - -let sponsorT2Accounts = { - new: createNAccounts(5, { - accountType: Constants.SPONSOR_T2, - confirmed: true - }), - stored: createNAccounts(5, { - accountType: Constants.SPONSOR_T2, - confirmed: true - }), - invalid: createNAccounts(5, { - accountType: Constants.SPONSOR_T2 - }) -}; - -let sponsorT3Accounts = { - new: createNAccounts(5, { - accountType: Constants.SPONSOR_T3, - confirmed: true - }), - stored: createNAccounts(5, { - accountType: Constants.SPONSOR_T3, - confirmed: true - }), - invalid: createNAccounts(5, { - accountType: Constants.SPONSOR_T3 - }) -}; - -let sponsorT4Accounts = { - new: createNAccounts(5, { - accountType: Constants.SPONSOR_T4, - confirmed: true - }), - stored: createNAccounts(5, { - accountType: Constants.SPONSOR_T4, - confirmed: true - }), - invalid: createNAccounts(5, { - accountType: Constants.SPONSOR_T4 - }) -}; - -let sponsorT5Accounts = { - new: createNAccounts(5, { - accountType: Constants.SPONSOR_T5, - confirmed: true - }), - stored: createNAccounts(5, { - accountType: Constants.SPONSOR_T5, - confirmed: true - }), - invalid: createNAccounts(5, { - accountType: Constants.SPONSOR_T5 - }) -}; - -let unlinkedAccounts = { - new: [ - createAccount({ - accountType: Constants.HACKER, - confirmed: false - }) - ], - invalid: [createAccount()], - stored: [ - createAccount({ - accountType: Constants.HACKER - }), - createAccount({ - accountType: Constants.HACKER - }) - ] -}; - -const waitlistedHacker0 = { - _id: mongoose.Types.ObjectId(), - firstName: "abcd", - lastName: "defg3", - pronoun: "They/Them", - gender: "Female", - email: "waitlisted1@blahblah.com", - password: "probsShouldBeHashed2", - dietaryRestrictions: ["vegetarian"], - gender: "Male", - confirmed: true, - accountType: Constants.HACKER, - birthDate: "1990-01-04", - phoneNumber: 1000000004 -}; - -// non confirmed account for hacker -const NonConfirmedAccount1 = { - _id: mongoose.Types.ObjectId(), - firstName: "LMAO", - lastName: "ROFL", - pronoun: "Ey/Em", - gender: "Female", - email: "notconfirmed1@blahblah.com", - password: "probsShouldBeHashed5", - dietaryRestrictions: ["something1", "something2"], - gender: "Male", - confirmed: false, - birthDate: "1980-07-30", - phoneNumber: 1001230236, - accountType: Constants.HACKER -}; - -const NonConfirmedAccount2 = { - _id: mongoose.Types.ObjectId(), - firstName: "LMAO", - lastName: "ROFL", - gender: "Female", - email: "notconfirmed2@blahblah.com", - password: "probsShouldBeHashed5", - dietaryRestrictions: ["something1", "something2"], - gender: "Male", - confirmed: false, - accountType: Constants.HACKER -}; - -const NonConfirmedAccount3 = createAccount({ - confirmed: false, - accountType: Constants.HACKER, - email: "notconfirmed3@blahblah.com" -}); - -const NoPhoneHackerAccount0 = { - _id: mongoose.Types.ObjectId(), - firstName: "LMAO", - lastName: "ROFL", - pronoun: "Ey/Em", - gender: "Female", - email: "noPhone0@blahblah.com", - password: "probsShouldBeHashed5", - dietaryRestrictions: ["something1", "something2"], - gender: "Male", - confirmed: false, - birthDate: "1980-07-30", - accountType: Constants.HACKER -}; - -const extraAccounts = [ - waitlistedHacker0, - NonConfirmedAccount1, - NonConfirmedAccount2, - NonConfirmedAccount3 -]; - -module.exports = { - hackerAccounts: hackerAccounts, - volunteerAccounts: volunteerAccounts, - staffAccounts: staffAccounts, - sponsorT1Accounts: sponsorT1Accounts, - sponsorT2Accounts: sponsorT2Accounts, - sponsorT3Accounts: sponsorT3Accounts, - sponsorT4Accounts: sponsorT4Accounts, - sponsorT5Accounts: sponsorT5Accounts, - unlinkedAccounts: unlinkedAccounts, - - waitlistedHacker0: waitlistedHacker0, - NonConfirmedAccount1: NonConfirmedAccount1, - NonConfirmedAccount2: NonConfirmedAccount2, - NonConfirmedAccount3: NonConfirmedAccount3, - NoPhoneHackerAccount0: NoPhoneHackerAccount0, - - extraAccounts: extraAccounts, - - storeAll: storeAll, - storeHackerStaffAccounts: storeHackerStaffAccounts, - storeVerifyConfirmationAccounts: storeVerifyConfirmationAccounts, - storeStaffUnlinkedAccount: storeStaffUnlinkedAccount, - storeGetInviteAccounts: storeGetInviteAccounts, - storeExtraAccounts: storeExtraAccounts, - storeHackerStaffExtraAccount: storeHackerStaffExtraAccount, - storeStoredTeamAccounts: storeStoredTeamAccounts, - storeSponsorAccount: storeSponsorAccount, - storeTeamAccount: storeTeamAccount, - storeStaffNoTeamTeamUnconfirmedInvalid: storeStaffNoTeamTeamUnconfirmedInvalid, - storeOneOfEach: storeOneOfEach, - dropAll: dropAll, - equals: equals -}; - -function encryptPassword(user) { - let encryptedUser = JSON.parse(JSON.stringify(user)); - encryptedUser.password = bcrypt.hashSync(user.password, 10); - return encryptedUser; -} - -function store(attributes) { - const acctDocs = []; - const acctNames = []; - for (var i = 0; i < attributes.length; i++) { - const encryptedUser = encryptPassword(attributes[i]); - acctDocs.push(new Account(encryptedUser)); - acctNames.push(attributes[i].firstName + "," + attributes[i].lastName); - } - - return Account.collection.insertMany(acctDocs); -} - -async function storeStoredTeamAccounts() { - await store(hackerAccounts.stored.team); -} - -async function storeStaffNoTeamTeamUnconfirmedInvalid() { - await store(hackerAccounts.stored.team); - await store(hackerAccounts.stored.noTeam); - await store(hackerAccounts.stored.unconfirmed); - await store(staffAccounts.stored); - await store(unlinkedAccounts.stored); - await store(hackerAccounts.new); - await store(extraAccounts); -} - -async function storeGetInviteAccounts() { - await store(hackerAccounts.stored.team); - await store(staffAccounts.stored); -} - -async function storeTeamAccount() { - await store(hackerAccounts.stored.noTeam); - await store(hackerAccounts.stored.team); - await store(staffAccounts.stored); - await store(sponsorT1Accounts.stored); -} - -async function storeSponsorAccount() { - await store(hackerAccounts.stored.team); - await store(staffAccounts.stored); - await store(sponsorT1Accounts.stored); - await store(sponsorT2Accounts.stored); - await store(sponsorT1Accounts.new); - await store(sponsorT2Accounts.new); -} - -async function storeHackerStaffExtraAccount() { - await store(hackerAccounts.stored.noTeam); - await store(hackerAccounts.stored.team); - await store(staffAccounts.stored); - await store(extraAccounts); -} - -async function storeHackerStaffAccounts() { - await store(hackerAccounts.stored.team); - await store(hackerAccounts.stored.noTeam); - await store(staffAccounts.stored); -} - -async function storeExtraAccounts() { - await store(extraAccounts); -} - -async function storeVerifyConfirmationAccounts() { - await store(hackerAccounts.stored.team); - await store(extraAccounts); -} - -async function storeStaffUnlinkedAccount() { - await store(staffAccounts.stored); - await store(unlinkedAccounts.stored); -} - -async function storeOneOfEach() { - await store(hackerAccounts.stored.team); - await store(hackerAccounts.stored.noTeam); - await store(hackerAccounts.stored.unconfirmed); - await store(volunteerAccounts.stored); - await store(staffAccounts.stored); - await store(unlinkedAccounts.stored); - await store(hackerAccounts.new); - await store(volunteerAccounts.new); - await store(extraAccounts); -} - -async function storeAll() { - await store(hackerAccounts.stored.team); - await store(hackerAccounts.stored.noTeam); - await store(hackerAccounts.stored.unconfirmed); - await store(volunteerAccounts.stored); - await store(staffAccounts.stored); - await store(sponsorT1Accounts.stored); - await store(sponsorT2Accounts.stored); - await store(sponsorT3Accounts.stored); - await store(sponsorT4Accounts.stored); - await store(sponsorT5Accounts.stored); - await store(unlinkedAccounts.stored); - - await store(hackerAccounts.new); - await store(volunteerAccounts.new); - await store(sponsorT1Accounts.new); - await store(sponsorT2Accounts.new); - await store(sponsorT3Accounts.new); - await store(sponsorT4Accounts.new); - await store(sponsorT5Accounts.new); - - await store(extraAccounts); -} - -async function dropAll() { - try { - await Account.collection.drop(); - } catch (e) { - if (e.code === 26) { - logger.info("namespace %s not found", Account.collection.name); - } else { - throw e; - } - } -} - -// Try deleting this and see if anything fucks up - -/** - * Compare two accounts - * @param {Account} acc1 - * @param {Account} acc2 - */ -function equals(acc1, acc2) { - const id1 = typeof acc1._id === "string" ? acc1._id : acc1._id.valueOf(); - const id2 = typeof acc2._id === "string" ? acc1._id : acc1._id.valueOf(); - const id = id1 === id2; - const firstName = acc1.firstName === acc2.firstName; - const lastName = acc1.lastName === acc2.lastName; - const pronoun = acc1.pronoun === acc2.pronoun; - const email = acc1.email === acc2.email; - const dietaryRestrictions = - acc1.dietaryRestrictions.join(",") === - acc2.dietaryRestrictions.join(","); - const gender = acc1.gender === acc2.gender; - return [ - id, - firstName, - lastName, - email, - dietaryRestrictions, - gender, - pronoun - ]; -} diff --git a/src/tests/util/accountConfirmation.test.util.js b/src/tests/util/accountConfirmation.test.util.js deleted file mode 100644 index eec693c1..00000000 --- a/src/tests/util/accountConfirmation.test.util.js +++ /dev/null @@ -1,107 +0,0 @@ -"use strict"; -const Util = { - Account: require("./account.test.util") -}; - -const Services = { - AccountConfirmation: require("../../services/accountConfirmation.service") -}; - -const mongoose = require("mongoose"); - -const AccountConfirmationToken = mongoose.model("AccountConfirmationToken"); - -const Constants = require("../../constants/general.constant"); -const logger = require("../../services/logger.service"); - -const HackerConfirmation = { - _id: mongoose.Types.ObjectId(), - accountId: Util.Account.NonConfirmedAccount1._id, - accountType: Constants.HACKER, - email: Util.Account.NonConfirmedAccount1.email -}; - -const HackerConfirmation2 = { - _id: mongoose.Types.ObjectId(), - accountId: Util.Account.NonConfirmedAccount2._id, - accountType: Constants.HACKER, - email: Util.Account.NonConfirmedAccount2.email -}; - -const HackerConfirmation3 = { - _id: mongoose.Types.ObjectId(), - email: Util.Account.unlinkedAccounts.new[0].email -}; - -const InvitedConfirmation1 = { - _id: mongoose.Types.ObjectId(), - accountType: Constants.HACKER, - email: "abcd@efgh.com", - confirmationType: Constants.CONFIRMATION_TYPE_INVITE -}; - -// Using a real ID which is stored but corresponds to another account -const FakeHackerToken = { - _id: HackerConfirmation._id, - accountId: Util.Account.sponsorT1Accounts.stored[0]._id, - accountType: Constants.HACKER -}; - -const ConfirmationToken = Services.AccountConfirmation.generateToken( - HackerConfirmation._id, - HackerConfirmation.accountId -); -const FakeToken = Services.AccountConfirmation.generateToken( - FakeHackerToken._id, - FakeHackerToken.accountId -); - -const AccountConfirmationTokens = [ - HackerConfirmation, - HackerConfirmation2, - HackerConfirmation3, - InvitedConfirmation1 -]; - -function store(attributes) { - const accountConfirmationDocs = []; - const accountConfirmationIds = []; - for (var i = 0; i < attributes.length; i++) { - accountConfirmationDocs.push( - new AccountConfirmationToken(attributes[i]) - ); - accountConfirmationIds.push(attributes[i]._id); - } - return AccountConfirmationToken.collection.insertMany( - accountConfirmationDocs - ); -} - -async function storeAll() { - await store(AccountConfirmationTokens); -} - -async function dropAll() { - try { - await AccountConfirmationToken.collection.drop(); - } catch (e) { - if (e.code === 26) { - logger.info( - "namespace %s not found", - AccountConfirmationToken.collection.name - ); - } else { - throw e; - } - } -} - -module.exports = { - HackerConfirmation: HackerConfirmation, - ConfirmationToken: ConfirmationToken, - FakeToken: FakeToken, - AccountConfirmationTokens: AccountConfirmationTokens, - InvitedConfirmation1: InvitedConfirmation1, - storeAll: storeAll, - dropAll: dropAll -}; diff --git a/src/tests/util/auth.test.util.js b/src/tests/util/auth.test.util.js deleted file mode 100644 index b326113c..00000000 --- a/src/tests/util/auth.test.util.js +++ /dev/null @@ -1,26 +0,0 @@ -"use strict"; -module.exports = { - login: login -}; -/** - * Use this function to log in a user before executing a test that requires certain permissions. - * @param {ChaiHttp.Agent} agent - * @param {{email:string,password:string}} credentials - * @param {(err?:any)=>void} callback - */ -function login(agent, credentials, callback) { - agent - .post("/api/auth/login") - .type("application/json") - .send({ - email: credentials.email, - password: credentials.password - }) - .end((err, res) => { - if (err) { - callback(err); - } else { - callback(); - } - }); -} diff --git a/src/tests/util/bus.test.util.js b/src/tests/util/bus.test.util.js deleted file mode 100644 index d84d668c..00000000 --- a/src/tests/util/bus.test.util.js +++ /dev/null @@ -1,54 +0,0 @@ -"use strict"; -const Util = { - Hacker: require("./hacker.test.util") -}; -const Bus = require("../../models/bus.model"); -const logger = require("../../services/logger.service"); - -const Bus1 = { - origin: { - country: "Country1", - provinceOrState: "Province2", - zip: "123456", - city: "City1", - addr1: "addr1-1", - addr2: "addr2-1" - }, - capacity: 10, - hackers: [Util.Hacker.TeamHacker0._id] -}; -const Busses = [Bus1]; - -module.exports = { - Bus1: Bus1, - Busses: Busses, - storeAll: storeAll, - dropAll: dropAll -}; - -function store(attributes) { - const busDocs = []; - const busZips = []; - for (var i = 0; i < attributes.length; i++) { - busDocs.push(new Bus(attributes[i])); - busZips.push(attributes[i].zip); - } - - return Bus.collection.insertMany(busDocs); -} - -async function storeAll() { - await store(Busses); -} - -async function dropAll() { - try { - await Bus.collection.drop(); - } catch (e) { - if (e.code === 26) { - logger.info("namespace %s not found", Bus.collection.name); - } else { - throw e; - } - } -} diff --git a/src/tests/util/hacker.test.util.js b/src/tests/util/hacker.test.util.js deleted file mode 100644 index 25287159..00000000 --- a/src/tests/util/hacker.test.util.js +++ /dev/null @@ -1,675 +0,0 @@ -"use strict"; -const Util = { - Account: require("./account.test.util") -}; -const Constants = { - MongoId: require("../../constants/testMongoId.constant") -}; - -const mongoose = require("mongoose"); -const Hacker = require("../../models/hacker.model"); -const logger = require("../../services/logger.service"); - -const TeamHacker0 = { - _id: Constants.MongoId.hackerAId, - accountId: Util.Account.hackerAccounts.stored.team[0]._id, - status: "Confirmed", - application: { - general: { - school: "University of Blah", - degree: "Masters", - fieldOfStudy: ["EE"], - graduationYear: 2019, - jobInterest: "Full Time", - URL: { - //gcloud bucket link - resume: "www.gcloud.com/myResume100", - github: "www.github.com/Person1", - dribbble: null, - personal: "www.person1.com", - linkedIn: "www.linkedin.com/in/Person1", - other: null - } - }, - shortAnswer: { - skills: ["CSS", "HTML", "JS"], - question1: "a", - question2: "a", - previousHackathons: 1 - }, - other: { - ethnicity: ["Native American"], - codeOfConduct: true, - privacyPolicy: true - }, - accommodation: { - dietaryRestrictions: ["Gluten-Free"], - shirtSize: "L", - travel: 0 - } - }, - teamId: Constants.MongoId.team1Id -}; - -const TeamHacker1 = { - _id: Constants.MongoId.hackerDId, - accountId: Util.Account.hackerAccounts.stored.team[1]._id, - status: "Checked-in", - application: { - general: { - school: "University of Blah", - degree: "Masters", - fieldOfStudy: ["EE"], - graduationYear: 2019, - jobInterest: "Internship", - URL: { - //gcloud bucket link - resume: "www.gcloud.com/myResume2", - github: "www.github.com/Personasdf", - dribbble: null, - personal: null, - linkedIn: null, - other: null - } - }, - shortAnswer: { - skills: ["CSS", "HTML", "JS"], - question1: "a", - question2: "a", - previousHackathons: 2 - }, - other: { - ethnicity: ["European"], - codeOfConduct: true, - privacyPolicy: true - }, - accommodation: { - dietaryRestrictions: ["Gluten-Free"], - shirtSize: "L", - travel: 0 - } - }, - teamId: Constants.MongoId.team3Id -}; - -const TeamHacker2 = { - _id: Constants.MongoId.hackerEId, - accountId: Util.Account.hackerAccounts.stored.team[2]._id, - status: "Waitlisted", - application: { - general: { - school: "University of Blah", - degree: "Masters", - fieldOfStudy: ["EE"], - graduationYear: 2019, - jobInterest: "Internship", - URL: { - //gcloud bucket link - resume: "www.gcloud.com/myResume2", - github: "www.github.com/Personasdf", - dribbble: null, - personal: null, - linkedIn: null, - other: null - } - }, - shortAnswer: { - skills: ["CSS", "HTML", "JS"], - question1: "a", - question2: "a", - previousHackathons: 3 - }, - other: { - ethnicity: ["European"], - codeOfConduct: true, - privacyPolicy: true - }, - accommodation: { - dietaryRestrictions: ["Gluten-Free"], - shirtSize: "L", - travel: 0 - } - }, - teamId: Constants.MongoId.team3Id -}; - -const TeamHacker3 = { - _id: Constants.MongoId.hackerFId, - accountId: Util.Account.hackerAccounts.stored.team[3]._id, - status: "Waitlisted", - application: { - general: { - school: "University of Blah", - degree: "Masters", - fieldOfStudy: ["EE"], - graduationYear: 2019, - jobInterest: "Internship", - URL: { - //gcloud bucket link - resume: "www.gcloud.com/myResume2", - github: "www.github.com/Personasdf", - dribbble: null, - personal: null, - linkedIn: null, - other: null - } - }, - shortAnswer: { - skills: ["CSS", "HTML", "JS"], - question1: "a", - question2: "a", - previousHackathons: 4 - }, - other: { - ethnicity: ["European"], - codeOfConduct: true, - privacyPolicy: true - }, - accommodation: { - dietaryRestrictions: ["Gluten-Free"], - shirtSize: "L", - travel: 0 - } - }, - teamId: Constants.MongoId.team3Id -}; - -const TeamHacker4 = { - _id: Constants.MongoId.hackerGId, - accountId: Util.Account.hackerAccounts.stored.team[4]._id, - status: "Waitlisted", - application: { - general: { - school: "University of Blah", - degree: "Masters", - fieldOfStudy: ["EE"], - graduationYear: 2019, - jobInterest: "Internship", - URL: { - //gcloud bucket link - resume: "www.gcloud.com/myResume2", - github: "www.github.com/Personasdf", - dribbble: null, - personal: null, - linkedIn: null, - other: null - } - }, - shortAnswer: { - skills: ["CSS", "HTML", "JS"], - question1: "a", - question2: "a", - previousHackathons: 5 - }, - other: { - ethnicity: ["European"], - codeOfConduct: true, - privacyPolicy: true - }, - accommodation: { - dietaryRestrictions: ["Gluten-Free"], - shirtSize: "L", - travel: 0 - } - }, - teamId: Constants.MongoId.team3Id -}; - -const NoTeamHacker0 = { - _id: Constants.MongoId.hackerBId, - accountId: Util.Account.hackerAccounts.stored.noTeam[0]._id, - status: "Accepted", - application: { - general: { - school: "University of Blah", - degree: "Masters", - fieldOfStudy: ["EE"], - graduationYear: 2019, - jobInterest: "Internship", - URL: { - //gcloud bucket link - resume: "www.gcloud.com/myResume1", - github: "www.github.com/Person4", - dribbble: null, - personal: null, - linkedIn: null, - other: null - } - }, - shortAnswer: { - skills: ["CSS", "HTML", "JS"], - question1: "a", - question2: "a", - previousHackathons: 1 - }, - other: { - ethnicity: ["European"], - codeOfConduct: true, - privacyPolicy: true - }, - accommodation: { - dietaryRestrictions: ["Gluten-Free"], - shirtSize: "L", - travel: 0 - } - } -}; - -const newHacker0 = { - accountId: Util.Account.hackerAccounts.new[0]._id, - application: { - general: { - school: "University of ASDF", - degree: "Masters", - fieldOfStudy: ["EE"], - graduationYear: 2019, - jobInterest: "Full Time", - URL: { - //gcloud bucket link - resume: "www.gcloud.com/myResume100", - github: "www.github.com/Person1", - dribbble: null, - personal: "www.person1.com", - linkedIn: "www.linkedin.com/in/Person1", - other: null - } - }, - shortAnswer: { - skills: ["CSS", "HTML", "JS"], - question1: "a", - question2: "a", - previousHackathons: 2 - }, - other: { - ethnicity: ["Caucasian"], - codeOfConduct: true, - privacyPolicy: true - }, - accommodation: { - dietaryRestrictions: ["Gluten-Free"], - shirtSize: "L", - travel: 0 - } - } -}; - -const newHacker1 = { - accountId: Util.Account.hackerAccounts.new[1]._id, - application: { - general: { - school: "University of YIKES", - degree: "PhD", - fieldOfStudy: ["EE"], - graduationYear: 2019, - jobInterest: "Full Time", - URL: { - //gcloud bucket link - resume: "www.gcloud.com/myResume100", - github: "www.github.com/Person1", - dribbble: null, - personal: "www.person1.com", - linkedIn: "www.linkedin.com/in/Person1", - other: null - } - }, - shortAnswer: { - skills: ["CSS", "HTML", "JS"], - question1: "a", - question2: "a", - previousHackathons: 3 - }, - other: { - ethnicity: ["African American"], - codeOfConduct: true, - privacyPolicy: true - }, - accommodation: { - dietaryRestrictions: ["Gluten-Free"], - shirtSize: "L", - travel: 0 - } - } -}; - -// duplicate of newHack0, but with false for code of conduct -const invalidHacker0 = { - accountId: Util.Account.hackerAccounts.new[0]._id, - application: { - general: { - school: "University of ASDF", - degree: "Masters", - fieldOfStudy: ["EE"], - graduationYear: 2019, - jobInterest: "Full Time", - URL: { - //gcloud bucket link - resume: "www.gcloud.com/myResume100", - github: "www.github.com/Person1", - dribbble: null, - personal: "www.person1.com", - linkedIn: "www.linkedin.com/in/Person1", - other: null - } - }, - shortAnswer: { - skills: ["CSS", "HTML", "JS"], - question1: "a", - question2: "a", - previousHackathons: 4 - }, - other: { - ethnicity: ["Caucasian"], - // must accept code of conduct to be valid - codeOfConduct: false, - privacyPolicy: false - }, - accommodation: { - dietaryRestrictions: ["Gluten-Free"], - shirtSize: "L", - travel: 0 - } - } -}; - -const invalidHacker1 = { - _id: mongoose.Types.ObjectId(), - // invalid mongoID - accountId: Util.Account.hackerAccounts.invalid[1]._invalidId, - application: { - general: { - // invalid missing school attribute - degree: "Undergraduate", - fieldOfStudy: ["EE"], - graduationYear: 2020, - // invalid job interest - jobInterest: "ASDF", - URL: { - // invalid URL links with no resume - } - }, - shortAnswer: { - skills: ["CSS", "HTML", "JS"], - question1: "a", - question2: "a", - previousHackathons: 5 - }, - other: { - ethnicity: ["Caucasian"], - codeOfConduct: true, - privacyPolicy: true - }, - accommodation: { - dietaryRestrictions: ["Gluten-Free"], - shirtSize: "L", - travel: "sfg" - } - } -}; - -// duplicate of newHack0, but with 101 for travel -const invalidHacker2 = { - accountId: Util.Account.hackerAccounts.new[0]._id, - application: { - general: { - school: "University of ASDF", - degree: "Masters", - fieldOfStudy: ["EE"], - graduationYear: 2019, - jobInterest: "Full Time", - URL: { - //gcloud bucket link - resume: "www.gcloud.com/myResume100", - github: "www.github.com/Person1", - dribbble: null, - personal: "www.person1.com", - linkedIn: "www.linkedin.com/in/Person1", - other: null - } - }, - shortAnswer: { - skills: ["CSS", "HTML", "JS"], - question1: "a", - question2: "a", - previousHackathons: 1 - }, - other: { - ethnicity: ["Caucasian"], - codeOfConduct: true, - privacyPolicy: true - }, - accommodation: { - dietaryRestrictions: ["Gluten-Free"], - shirtSize: "L", - // must be between [0,100] to be valid - travel: 101 - } - } -}; - -const duplicateAccountLinkHacker0 = { - _id: mongoose.Types.ObjectId(), - accountId: Util.Account.hackerAccounts.stored.team[0]._id, - status: "Applied", - application: { - general: { - school: "University of Blah", - degree: "Undergraduate", - fieldOfStudy: ["CS"], - graduationYear: 2019, - jobInterest: "Full Time", - URL: { - //gcloud bucket link - resume: "www.gcloud.com/myResume100", - github: "www.github.com/Person1", - dribbble: null, - personal: "www.person1.com", - linkedIn: "www.linkedin.com/in/Person1", - other: null - } - }, - shortAnswer: { - skills: ["CSS", "HTML", "JS"], - question1: "a", - question2: "a", - previousHackathons: 2 - }, - other: { - ethnicity: ["Caucasian"], - codeOfConduct: true, - privacyPolicy: true - }, - accommodation: { - dietaryRestrictions: ["Gluten-Free"], - shirtSize: "L", - travel: 0 - } - } -}; - -const waitlistedHacker0 = { - _id: Constants.MongoId.hackerCId, - accountId: Util.Account.waitlistedHacker0._id, - status: "Waitlisted", - application: { - general: { - school: "University of Blah", - degree: "Masters", - fieldOfStudy: ["EE"], - graduationYear: 2019, - jobInterest: "Intership", - URL: { - //gcloud bucket link - resume: "www.gcloud.com/myResume2", - github: "www.github.com/Personasdf", - dribbble: null, - personal: null, - linkedIn: null, - other: null - } - }, - shortAnswer: { - skills: ["CSS", "HTML", "JS"], - question1: "a", - question2: "a", - previousHackathons: 3 - }, - other: { - ethnicity: ["European"], - codeOfConduct: true, - privacyPolicy: true - }, - accommodation: { - dietaryRestrictions: ["Gluten-Free"], - shirtSize: "L", - travel: 0 - } - }, - teamId: Constants.MongoId.team2Id -}; - -const unconfirmedAccountHacker0 = { - _id: Constants.MongoId.hackerCId, - accountId: Util.Account.NonConfirmedAccount3._id, - status: "Waitlisted", - application: { - general: { - school: "University of Blah1", - degree: "Masters", - fieldOfStudy: ["EE"], - graduationYear: 2019, - jobInterest: "Internship", - URL: { - //gcloud bucket link - resume: "www.gcloud.com/myResume123", - github: "www.github.com/Personasdf", - dribbble: null, - personal: null, - linkedIn: null, - other: null - } - }, - shortAnswer: { - skills: ["CSS", "HTML", "JS"], - question1: "a", - question2: "a", - previousHackathons: 4 - }, - other: { - ethnicity: ["European"], - codeOfConduct: true, - privacyPolicy: true - }, - accommodation: { - dietaryRestrictions: ["Gluten-Free"], - shirtSize: "L", - travel: 0 - } - } -}; - -const unconfirmedAccountHacker1 = { - _id: Constants.MongoId.hackerHId, - accountId: Util.Account.hackerAccounts.stored.unconfirmed[0]._id, - status: "Accepted", - application: { - general: { - school: "University of Blah2", - degree: "Undergraduate", - fieldOfStudy: ["EE"], - graduationYear: 2019, - jobInterest: "Internship", - URL: { - //gcloud bucket link - resume: "www.gcloud.com/myResume123", - github: "www.github.com/Personasdf", - dropler: null, - personal: null, - linkedIn: null, - other: null - } - }, - shortAnswer: { - skills: ["CSS", "HTML", "JS"], - question1: "a", - question2: "a", - previousHackathons: 5 - }, - other: { - ethnicity: ["European"], - codeOfConduct: true, - privacyPolicy: true - }, - accommodation: { - dietaryRestrictions: ["Gluten-Free"], - shirtSize: "L", - travel: 0 - } - } -}; - -const Hackers = [ - TeamHacker0, - TeamHacker1, - TeamHacker2, - TeamHacker3, - TeamHacker4, - - NoTeamHacker0, - unconfirmedAccountHacker1, - - duplicateAccountLinkHacker0, - waitlistedHacker0 -]; - -module.exports = { - TeamHacker0: TeamHacker0, - TeamHacker1: TeamHacker1, - TeamHacker2: TeamHacker2, - TeamHacker3: TeamHacker3, - TeamHacker4: TeamHacker4, - - NoTeamHacker0: NoTeamHacker0, - - newHacker0: newHacker0, - newHacker1: newHacker1, - - invalidHacker0: invalidHacker0, - invalidHacker1: invalidHacker1, - invalidHacker2: invalidHacker2, - - duplicateAccountLinkHacker0: duplicateAccountLinkHacker0, - waitlistedHacker0: waitlistedHacker0, - unconfirmedAccountHacker0: unconfirmedAccountHacker0, - unconfirmedAccountHacker1: unconfirmedAccountHacker1, - - Hackers: Hackers, - storeAll: storeAll, - dropAll: dropAll -}; - -function store(attributes) { - const hackerDocs = []; - const hackerIds = []; - for (var i = 0; i < attributes.length; i++) { - hackerDocs.push(new Hacker(attributes[i])); - hackerIds.push(attributes[i]._id); - } - - return Hacker.collection.insertMany(hackerDocs); -} - -async function storeAll() { - await store(Hackers); -} - -async function dropAll() { - try { - await Hacker.collection.drop(); - } catch (e) { - if (e.code === 26) { - logger.info("namespace %s not found", Hacker.collection.name); - } else { - throw e; - } - } -} diff --git a/src/tests/util/resetPassword.test.util.js b/src/tests/util/resetPassword.test.util.js deleted file mode 100644 index 53b3d6e0..00000000 --- a/src/tests/util/resetPassword.test.util.js +++ /dev/null @@ -1,61 +0,0 @@ -"use strict"; -const Util = { - Account: require("./account.test.util") -}; - -const Services = { - resetPassword: require("../../services/resetPassword.service") -}; - -const mongoose = require("mongoose"); -const ResetPassword = require("../../models/passwordResetToken.model"); - -const logger = require("../../services/logger.service"); - -const ResetPasswordToken1 = { - _id: mongoose.Types.ObjectId(), - accountId: Util.Account.hackerAccounts.stored.team[0]._id -}; - -const ResetToken = Services.resetPassword.generateToken( - ResetPasswordToken1._id, - ResetPasswordToken1.accountId -); - -const ResetPasswords = [ResetPasswordToken1]; - -function store(attributes) { - const resetPasswordDocs = []; - const resetPasswordIds = []; - for (var i = 0; i < attributes.length; i++) { - resetPasswordDocs.push(new ResetPassword(attributes[i])); - resetPasswordIds.push(attributes[i]._id); - } - return ResetPassword.collection.insertMany(resetPasswordDocs); -} - -async function storeAll() { - await store(ResetPasswords); -} - -async function dropAll() { - try { - await ResetPassword.collection.drop(); - } catch (e) { - if (e.code === 26) { - logger.info( - "namespace %s not found", - ResetPassword.collection.name - ); - } else { - throw e; - } - } -} - -module.exports = { - ResetToken: ResetToken, - ResetPasswords: ResetPasswords, - storeAll: storeAll, - dropAll: dropAll -}; diff --git a/src/tests/util/role.test.util.js b/src/tests/util/role.test.util.js deleted file mode 100644 index 4c9912ef..00000000 --- a/src/tests/util/role.test.util.js +++ /dev/null @@ -1,53 +0,0 @@ -"use strict"; -const Role = require("../../models/role.model"); -const Constants = { - General: require("../../constants/general.constant"), - Role: require("../../constants/role.constant") -}; -const Routes = require("../../constants/routes.constant"); -const mongoose = require("mongoose"); -const logger = require("../../services/logger.service"); - -const newRole1 = { - name: "newRole", - routes: [Routes.hackerRoutes.getSelf, Routes.hackerRoutes.getSelfById] -}; - -const duplicateRole1 = { - name: "duplicateRole", - routes: [Routes.hackerRoutes.getAnyById] -}; - -function store(attributes) { - const roleDocs = []; - const roleNames = []; - attributes.forEach((attribute) => { - roleDocs.push(new Role(attribute)); - roleNames.push(attribute.name); - }); - - return Role.collection.insertMany(roleDocs); -} - -async function storeAll() { - await store(Constants.Role.allRolesArray); -} - -async function dropAll() { - try { - await Role.collection.drop(); - } catch (e) { - if (e.code === 26) { - logger.info("namespace %s not found", Role.collection.name); - } else { - throw e; - } - } -} - -module.exports = { - newRole1: newRole1, - duplicateRole1: duplicateRole1, - storeAll: storeAll, - dropAll: dropAll -}; diff --git a/src/tests/util/roleBinding.test.util.js b/src/tests/util/roleBinding.test.util.js deleted file mode 100644 index 56c566d6..00000000 --- a/src/tests/util/roleBinding.test.util.js +++ /dev/null @@ -1,167 +0,0 @@ -"use strict"; -const RoleBinding = require("../../models/roleBinding.model"); -const Util = { - Account: require("./account.test.util") -}; -const Constants = { - Role: require("../../constants/role.constant"), - General: require("../../constants/general.constant") -}; -const logger = require("../../services/logger.service"); - -function createRoleBinding(accountId, accountType = null, specificRoles = []) { - let roleBinding = { - accountId: accountId, - roles: [Constants.Role.accountRole] - }; - - switch (accountType) { - case Constants.General.HACKER: - roleBinding.roles.push(Constants.Role.hackerRole); - break; - case Constants.General.VOLUNTEER: - roleBinding.roles.push(Constants.Role.volunteerRole); - break; - case Constants.General.STAFF: - roleBinding.roles.push(Constants.Role.adminRole); - break; - case Constants.General.SPONSOR_T1: - roleBinding.roles.push(Constants.Role.sponsorT1Role); - break; - case Constants.General.SPONSOR_T2: - roleBinding.roles.push(Constants.Role.sponsorT2Role); - break; - case Constants.General.SPONSOR_T3: - roleBinding.roles.push(Constants.Role.sponsorT3Role); - break; - case Constants.General.SPONSOR_T4: - roleBinding.roles.push(Constants.Role.sponsorT4Role); - break; - case Constants.General.SPONSOR_T5: - roleBinding.roles.push(Constants.Role.sponsorT5Role); - break; - } - - for (const role of specificRoles) { - roleBinding.roles.push(role); - } - - return roleBinding; -} - -function createRoleBindings(accounts) { - let roleBindings = []; - - for (const account of accounts) { - roleBindings.push(createRoleBinding(account._id, account.accountType)); - } - - return roleBindings; -} - -const TeamHackerRB = createRoleBindings( - Util.Account.hackerAccounts.stored.team -); -const NoTeamHackerRB = createRoleBindings( - Util.Account.hackerAccounts.stored.noTeam -); -const UnconfirmedHackerRB = createRoleBindings( - Util.Account.hackerAccounts.stored.unconfirmed -); -const VolunteerRB = createRoleBindings(Util.Account.volunteerAccounts.stored); -const StaffRB = createRoleBindings(Util.Account.staffAccounts.stored); -const SponsorT1RB = createRoleBindings(Util.Account.sponsorT1Accounts.stored); -const SponsorT2RB = createRoleBindings(Util.Account.sponsorT2Accounts.stored); -const SponsorT3RB = createRoleBindings(Util.Account.sponsorT3Accounts.stored); -const SponsorT4RB = createRoleBindings(Util.Account.sponsorT4Accounts.stored); -const SponsorT5RB = createRoleBindings(Util.Account.sponsorT5Accounts.stored); - -const newHackerRB = createRoleBindings(Util.Account.hackerAccounts.new); -const newVolunteerRB = createRoleBindings(Util.Account.volunteerAccounts.new); -const newSponsorT1RB = createRoleBindings(Util.Account.sponsorT1Accounts.new); -const newSponsorT2RB = createRoleBindings(Util.Account.sponsorT2Accounts.new); -const newSponsorT3RB = createRoleBindings(Util.Account.sponsorT3Accounts.new); -const newSponsorT4RB = createRoleBindings(Util.Account.sponsorT4Accounts.new); -const newSponsorT5RB = createRoleBindings(Util.Account.sponsorT5Accounts.new); - -const extraAccounts = [ - createRoleBinding(Util.Account.NonConfirmedAccount1._id), - createRoleBinding(Util.Account.NonConfirmedAccount2._id), - createRoleBinding(Util.Account.NonConfirmedAccount3._id), - createRoleBinding( - Util.Account.waitlistedHacker0._id, - Constants.General.HACKER - ) -]; - -function store(attributes) { - const roleBindingDocs = []; - const roleBindingNames = []; - attributes.forEach((attribute) => { - roleBindingDocs.push(new RoleBinding(attribute)); - roleBindingNames.push(attribute.name); - }); - - return RoleBinding.collection.insertMany(roleBindingDocs); -} - -async function storeAll() { - await store(TeamHackerRB); - await store(NoTeamHackerRB); - await store(UnconfirmedHackerRB); - await store(VolunteerRB); - await store(StaffRB); - await store(SponsorT1RB); - await store(SponsorT2RB); - await store(SponsorT3RB); - await store(SponsorT4RB); - await store(SponsorT5RB); - - await store(newHackerRB); - await store(newVolunteerRB); - await store(newSponsorT1RB); - await store(newSponsorT2RB); - await store(newSponsorT3RB); - await store(newSponsorT4RB); - await store(newSponsorT5RB); - - await store(extraAccounts); -} - -async function dropAll() { - try { - await RoleBinding.collection.drop(); - } catch (e) { - if (e.code === 26) { - logger.info("namespace %s not found", RoleBinding.collection.name); - } else { - throw e; - } - } -} - -module.exports = { - TeamHackerRB: TeamHackerRB, - NoTeamHackerRB: NoTeamHackerRB, - UnconfirmedHackerRB: UnconfirmedHackerRB, - VolunteerRB: VolunteerRB, - StaffRB: StaffRB, - SponsorT1RB: SponsorT1RB, - SponsorT2RB: SponsorT2RB, - SponsorT3RB: SponsorT3RB, - SponsorT4RB: SponsorT4RB, - SponsorT5RB: SponsorT5RB, - - newHackerRB: newHackerRB, - newVolunteerRB: newVolunteerRB, - newSponsorT1RB: newSponsorT1RB, - newSponsorT2RB: newSponsorT2RB, - newSponsorT3RB: newSponsorT3RB, - newSponsorT4RB: newSponsorT4RB, - newSponsorT5RB: newSponsorT5RB, - - extraAccounts: extraAccounts, - - storeAll: storeAll, - dropAll: dropAll -}; diff --git a/src/tests/util/settings.test.util.js b/src/tests/util/settings.test.util.js deleted file mode 100644 index bb6961e2..00000000 --- a/src/tests/util/settings.test.util.js +++ /dev/null @@ -1,40 +0,0 @@ -const Settings = require("../../models/settings.model"); -const logger = require("../../services/logger.service"); -const Constants = { - Settings: require("../../constants/settings.constant") -}; - -async function storeAll() { - const toStore = new Settings(Constants.Settings.APP_OPEN); - Settings.collection.insertOne(toStore); -} - -async function setApplicationClosed() { - await dropAll(); - const toStore = new Settings(Constants.Settings.APP_CLOSED); - Settings.collection.insertOne(toStore); -} - -async function setApplicationNotYetOpen() { - await dropAll(); - const toStore = new Settings(Constants.Settings.APP_NOT_YET_OPEN); - Settings.collection.insertOne(toStore); -} - -async function dropAll() { - try { - await Settings.collection.drop(); - } catch (e) { - if (e.code === 26) { - logger.info("namespace %s not found", Settings.collection.name); - } else { - throw e; - } - } -} -module.exports = { - storeAll: storeAll, - dropAll: dropAll, - setApplicationClosed: setApplicationClosed, - setApplicationNotYetOpen: setApplicationNotYetOpen -}; diff --git a/src/tests/util/sponsor.test.util.js b/src/tests/util/sponsor.test.util.js deleted file mode 100644 index 091dac9d..00000000 --- a/src/tests/util/sponsor.test.util.js +++ /dev/null @@ -1,75 +0,0 @@ -"use strict"; -const Util = { - Account: require("./account.test.util"), - Hacker: require("./hacker.test.util") -}; -const Sponsor = require("../../models/sponsor.model"); -const mongoose = require("mongoose"); -const logger = require("../../services/logger.service"); - -const T1Sponsor0 = { - _id: mongoose.Types.ObjectId(), - accountId: Util.Account.sponsorT1Accounts.stored[0]._id, - tier: 1, - company: "Best company NA", - contractURL: "https://linkto.con", - nominees: [Util.Hacker.TeamHacker0._id] -}; - -const newT2Sponsor0 = { - // no _id as that will be generated - accountId: Util.Account.sponsorT2Accounts.new[0]._id, - tier: 2, - company: "Best company EU", - contractURL: "https://linktocontract2.con", - nominees: [Util.Hacker.NoTeamHacker0._id] -}; - -const duplicateAccountLinkSponsor1 = { - _id: mongoose.Types.ObjectId(), - accountId: Util.Account.sponsorT1Accounts.stored[0]._id, - tier: 3, - company: "Best company NA1", - contractURL: "https://linkto1.con", - nominees: [Util.Hacker.TeamHacker0._id] -}; - -const Sponsors = [T1Sponsor0]; - -function store(attributes) { - const sponsorDocs = []; - const sponsorComps = []; - attributes.forEach((attribute) => { - sponsorDocs.push(new Sponsor(attribute)); - sponsorComps.push(attribute.company); - }); - - return Sponsor.collection.insertMany(sponsorDocs); -} - -async function storeAll() { - await store(Sponsors); -} - -async function dropAll() { - try { - await Sponsor.collection.drop(); - } catch (e) { - if (e.code === 26) { - logger.info("namespace %s not found", Sponsor.collection.name); - } else { - throw e; - } - } -} - -module.exports = { - T1Sponsor0: T1Sponsor0, - newT2Sponsor0: newT2Sponsor0, - - duplicateAccountLinkSponsor1: duplicateAccountLinkSponsor1, - - Sponsors: Sponsors, - storeAll: storeAll, - dropAll: dropAll -}; diff --git a/src/tests/util/staff.test.util.js b/src/tests/util/staff.test.util.js deleted file mode 100644 index 45867221..00000000 --- a/src/tests/util/staff.test.util.js +++ /dev/null @@ -1,47 +0,0 @@ -"use strict"; -const Util = { - Account: require("./account.test.util") -}; -const Staff = require("../../models/staff.model"); -const mongoose = require("mongoose"); -const logger = require("../../services/logger.service"); - -const Staff0 = { - _id: mongoose.Types.ObjectId(), - accountId: Util.Account.staffAccounts.stored[0] -}; -const Staffs = [Staff0]; - -function store(attributes) { - const staffDocs = []; - const staffIds = []; - attributes.forEach((attribute) => { - staffDocs.push(new Staff(attribute)); - staffIds.push(attribute._id); - }); - - return Staff.collection.insertMany(staffDocs); -} - -async function storeAll() { - await store(Staffs); -} - -async function dropAll() { - try { - await Staff.collection.drop(); - } catch (e) { - if (e.code === 26) { - logger.info("namespace %s not found", Staff.collection.name); - } else { - throw e; - } - } -} - -module.exports = { - Staff0: Staff0, - Staffs: Staffs, - storeAll: storeAll, - dropAll: dropAll -}; diff --git a/src/tests/util/team.test.util.js b/src/tests/util/team.test.util.js deleted file mode 100644 index 1927e472..00000000 --- a/src/tests/util/team.test.util.js +++ /dev/null @@ -1,95 +0,0 @@ -"use strict"; -const Util = { - Hacker: require("./hacker.test.util") -}; -const Constants = { - MongoId: require("../../constants/testMongoId.constant") -}; -const Team = require("../../models/team.model"); -const mongoose = require("mongoose"); -const logger = require("../../services/logger.service"); - -const duplicateTeamName1 = { - name: "SilverTeam", - projectName: "AProject" -}; - -const newTeam1 = { - _id: mongoose.Types.ObjectId(), - name: "BronzeTeam1", - projectName: "YetAnotherProject" -}; - -const createdNewTeam1 = { - name: "BronzeTeam1", - members: [Util.Hacker.NoTeamHacker0._id], - projectName: "YetAnotherProject" -}; - -const Team1 = { - _id: Constants.MongoId.team1Id, - name: "BronzeTeam", - members: [Util.Hacker.TeamHacker0._id], - devpostURL: "justanother.devpost.com", - projectName: "YetAnotherProject" -}; - -const Team2 = { - _id: Constants.MongoId.team2Id, - name: "SilverTeam", - members: [Util.Hacker.waitlistedHacker0._id], - devpostURL: "watwatwat.devpost.com", - projectName: "WatWatWat" -}; - -const Team3 = { - _id: Constants.MongoId.team3Id, - name: "FullTeam", - members: [ - Util.Hacker.TeamHacker1._id, - Util.Hacker.TeamHacker2._id, - Util.Hacker.TeamHacker3._id, - Util.Hacker.TeamHacker4._id - ] -}; - -const Teams = [Team1, Team2, Team3]; - -function store(attributes) { - const teamDocs = []; - const names = []; - attributes.forEach((attribute) => { - teamDocs.push(new Team(attribute)); - names.push(attribute.name); - }); - - return Team.collection.insertMany(teamDocs); -} - -async function storeAll() { - await store(Teams); -} - -async function dropAll() { - try { - await Team.collection.drop(); - } catch (e) { - if (e.code === 26) { - logger.info("namespace %s not found", Team.collection.name); - } else { - throw e; - } - } -} - -module.exports = { - newTeam1: newTeam1, - createdNewTeam1: createdNewTeam1, - duplicateTeamName1: duplicateTeamName1, - Team1: Team1, - Team2: Team2, - Team3: Team3, - Teams: Teams, - storeAll: storeAll, - dropAll: dropAll -}; diff --git a/src/tests/util/volunteer.test.util.js b/src/tests/util/volunteer.test.util.js deleted file mode 100644 index a8ef4903..00000000 --- a/src/tests/util/volunteer.test.util.js +++ /dev/null @@ -1,65 +0,0 @@ -"use strict"; -const Util = { - Account: require("./account.test.util") -}; -const mongoose = require("mongoose"); -const Volunteer = require("../../models/volunteer.model"); -const logger = require("../../services/logger.service"); - -const newVolunteer0 = { - accountId: Util.Account.volunteerAccounts.new[0]._id -}; - -const duplicateVolunteer1 = { - accountId: Util.Account.volunteerAccounts.stored[0]._id -}; - -const Volunteer0 = { - _id: mongoose.Types.ObjectId(), - accountId: Util.Account.volunteerAccounts.stored[0]._id -}; - -const invalidVolunteer0 = { - _id: mongoose.Types.ObjectId(), - accountId: Util.Account.staffAccounts.stored[0]._id -}; - -const Volunteers = [Volunteer0]; - -function store(attributes) { - const volunteerDocs = []; - const volunteerIds = []; - attributes.forEach((attribute) => { - volunteerDocs.push(new Volunteer(attribute)); - volunteerIds.push(attribute._id); - }); - - return Volunteer.collection.insertMany(volunteerDocs); -} - -async function storeAll() { - await store(Volunteers); -} - -async function dropAll() { - try { - await Volunteer.collection.drop(); - } catch (e) { - if (e.code === 26) { - logger.info("namespace %s not found", Volunteer.collection.name); - } else { - throw e; - } - } -} - -module.exports = { - duplicateVolunteer1: duplicateVolunteer1, - newVolunteer0: newVolunteer0, - Volunteer0: Volunteer0, - invalidVolunteer0: invalidVolunteer0, - - Volunteers: Volunteers, - storeAll: storeAll, - dropAll: dropAll -}; diff --git a/src/tests/volunteer.test.js b/src/tests/volunteer.test.js deleted file mode 100644 index 7a700417..00000000 --- a/src/tests/volunteer.test.js +++ /dev/null @@ -1,309 +0,0 @@ -"use strict"; -const chai = require("chai"); -const chaiHttp = require("chai-http"); -chai.use(chaiHttp); -const server = require("../app"); -const agent = chai.request.agent(server.app); -const should = chai.should(); -const Volunteer = require("../models/volunteer.model"); -const Constants = { - Success: require("../constants/success.constant"), - Error: require("../constants/error.constant") -}; - -const util = { - volunteer: require("./util/volunteer.test.util"), - account: require("./util/account.test.util"), - auth: require("./util/auth.test.util"), - role: require("./util/role.test.util"), - roleBinding: require("./util/roleBinding.test.util") -}; - -const Admin0 = util.account.staffAccounts.stored[0]; -const HackerAccount0 = util.account.hackerAccounts.stored.team[0]; - -const VolunteerAccount0 = util.account.volunteerAccounts.stored[0]; -const Volunteer0 = util.volunteer.Volunteer0; - -const newVolunteerAccount0 = util.account.volunteerAccounts.new[0]; -const newVolunteer0 = util.volunteer.newVolunteer0; -const duplicateVolunteer = util.volunteer.duplicateVolunteer1; - -const invalidVolunteer0 = util.volunteer.invalidVolunteer0; - -describe("GET volunteer", function() { - async function storeAll() { - await util.roleBinding.storeAll(); - await util.role.storeAll(); - await util.volunteer.storeAll(); - await util.account.storeOneOfEach(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("should FAIL to get volunteer due to lack of authentication", function(done) { - chai.request(server.app) - .get(`/api/volunteer/${Volunteer0._id}`) - .end(function(err, res) { - res.should.have.status(401); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - res.body.should.have.property("data"); - - done(); - }); - }); - - it("should Fail to GET volunteer due inappropriate authorization", function(done) { - util.auth.login(agent, HackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .get(`/api/volunteer/${util.volunteer.Volunteer0._id}`) - .end(function(err, res) { - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.AUTH_403_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - }); - }); - - it("should Fail to GET volunteer due to non existant volunteer id", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .get(`/api/volunteer/${Admin0._id}`) - .end(function(err, res) { - res.should.have.status(404); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.VOLUNTEER_404_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - }); - }); - - // success case - it("should GET volunteer info by id with admin credentials", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .get(`/api/volunteer/${Volunteer0._id}`) - .end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.VOLUNTEER_GET_BY_ID - ); - res.body.should.have.property("data"); - - let volunteer = new Volunteer(util.volunteer.Volunteer0); - chai.assert.equal( - JSON.stringify(res.body.data), - JSON.stringify(volunteer.toJSON()) - ); - done(); - }); - }); - }); - - // success case - it("should GET the user's volunteer info by id", function(done) { - util.auth.login(agent, VolunteerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .get(`/api/volunteer/${util.volunteer.Volunteer0._id}`) - .end(function(err, res) { - if (err) { - return done(err); - } - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.VOLUNTEER_GET_BY_ID - ); - res.body.should.have.property("data"); - - let volunteer = new Volunteer(util.volunteer.Volunteer0); - chai.assert.equal( - JSON.stringify(res.body.data), - JSON.stringify(volunteer.toJSON()) - ); - done(); - }); - }); - }); -}); - -describe("POST create volunteer", function() { - async function storeAll() { - await util.roleBinding.storeAll(); - await util.role.storeAll(); - await util.volunteer.storeAll(); - await util.account.storeOneOfEach(); - } - beforeEach(function(done) { - this.timeout(60000); - storeAll() - .then(() => { - done(); - }) - .catch((error) => { - done(error); - }); - }); - it("should FAIL to create a new volunteer due to lack of authentication", function(done) { - chai.request(server.app) - .post(`/api/volunteer`) - .type("application/json") - .send(util.volunteer.newVolunteer0) - .end(function(err, res) { - res.should.have.status(401); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal(Constants.Error.AUTH_401_MESSAGE); - - done(); - }); - }); - - // fail on admin case - it("fail to create a volunteer when the logged in account is not a volunteer /api/volunteer POST", function(done) { - util.auth.login(agent, Admin0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .post(`/api/volunteer`) - .type("application/json") - .send(invalidVolunteer0) - .end(function(err, res) { - res.should.have.status(409); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.ACCOUNT_TYPE_409_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - }); - }); - - // succeed on user case - it("should create a volunteer for the user /api/volunteer POST", function(done) { - util.auth.login(agent, newVolunteerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .post(`/api/volunteer`) - .type("application/json") - .send(newVolunteer0) - .end(function(err, res) { - res.should.have.status(200); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Success.VOLUNTEER_CREATE - ); - res.body.should.have.property("data"); - - // deleting id because that was generated, and not part of original data - delete res.body.data.id; - chai.assert.equal( - JSON.stringify(res.body.data), - JSON.stringify(newVolunteer0) - ); - done(); - }); - }); - }); - - // fail due to duplicate accountId - it("should create a volunteer for the user /api/volunteer POST", function(done) { - util.auth.login(agent, newVolunteerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .post(`/api/volunteer`) - .type("application/json") - .send(duplicateVolunteer) - .end(function(err, res) { - res.should.have.status(409); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.VOLUNTEER_ID_409_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - }); - }); - - // fail on non-volunteer type account trying to create volunteer - it("should FAIL to create a volunteer due to authorization /api/volunteer POST", function(done) { - util.auth.login(agent, HackerAccount0, (error) => { - if (error) { - agent.close(); - return done(error); - } - return agent - .post(`/api/volunteer`) - .type("application/json") - .send(util.volunteer.newVolunteer1) - .end(function(err, res) { - res.should.have.status(403); - res.should.be.json; - res.body.should.have.property("message"); - res.body.message.should.equal( - Constants.Error.AUTH_403_MESSAGE - ); - res.body.should.have.property("data"); - - done(); - }); - }); - }); -}); From 6b2d8bb9179911d64e3c986bcf880ef3ecf105d3 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Thu, 20 Jan 2022 20:50:58 -0500 Subject: [PATCH 45/72] refactor: remove marketing e-mails. --- src/assets/email/marketingEmail/3Days.mjml | 82 ------------------- .../email/marketingEmail/EmailBlast.mjml | 72 ---------------- 2 files changed, 154 deletions(-) delete mode 100644 src/assets/email/marketingEmail/3Days.mjml delete mode 100644 src/assets/email/marketingEmail/EmailBlast.mjml diff --git a/src/assets/email/marketingEmail/3Days.mjml b/src/assets/email/marketingEmail/3Days.mjml deleted file mode 100644 index abf88b0b..00000000 --- a/src/assets/email/marketingEmail/3Days.mjml +++ /dev/null @@ -1,82 +0,0 @@ - - - McHacks is back! - - - - - - - - - - There’s just 3 days left to apply to Canada’s favorite hackathon! Have - you started your McHacks 7 application yet? What are you waiting for? - - - - McHacks is back this winter for round 7! Join us February 1-2, 2020 in - the beautiful city of Montreal for a weekend full of engaging workshops, - making new friends, impressive tech, and awesome hacking. - - - - 🚀 Update complete. You're now ready for McHacks 7! 😀🎉 - - - - Canada's favorite hackathon is back again this winter and better than - ever! Join us on February 1-2, 2020 for a weekend full of engaging - workshops, impressive tech, exceptional food, and awesome hacking. - - - - Learn something, make new friends, and help build the future in the - beautiful city of Montreal. We hope to see you there, whether it's your - first hackathon or your 10th. - - - - - Apply Now! - - - - - If you're ahead of the game and applied already, feel free to recycle - this email to a friend and help us keep the hype going! -

- Follow us on -
Facebook, - Twitter, - and - Instagram - for important updates and news about McHacks! If you have any - questions, feel free to reach out at - contact@mchacks.ca. - - - - If you’ve already applied, share this email with your friends and don’t - forget to respond to our - Facebook event. - We hope to see you there! - - - - McHacks Team -
- mchacks.ca -
- - - - Unsubscribe - - - - - - - - diff --git a/src/assets/email/marketingEmail/EmailBlast.mjml b/src/assets/email/marketingEmail/EmailBlast.mjml deleted file mode 100644 index 2475ce6a..00000000 --- a/src/assets/email/marketingEmail/EmailBlast.mjml +++ /dev/null @@ -1,72 +0,0 @@ - - - McHacks is back! - - - - - - - - - - 💾 Installing HackMcGill firmware… - - - - 💻 Getting the latest McHacks update... - - - - 🚀 Update complete. You're now ready for McHacks 7! 😀🎉 - - - - Canada's favorite hackathon is back again this winter and better than - ever! Join us on February 1-2, 2020 for a weekend full of engaging - workshops, impressive tech, exceptional food, and awesome hacking. - - - - Learn something, make new friends, and help build the future in the - beautiful city of Montreal. We hope to see you there, whether it's your - first hackathon or your 10th. - - - - - Apply Now! - - - - - If you're ahead of the game and applied already, feel free to recycle - this email to a friend and help us keep the hype going! -

- Follow us on - Facebook, - Twitter, - and - Instagram - for important updates and news about McHacks! If you have any - questions, feel free to reach out at - contact@mchacks.ca. -
- - - McHacks Team -
- mchacks.ca -
- - - - Unsubscribe - - -
-
- - -
-
From fcaea807a51776df181bfc62d48591408450537b Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Thu, 3 Feb 2022 04:29:22 -0500 Subject: [PATCH 46/72] feat(app.ts,index.ts): rewrite app launch file to support testing. --- src/app.ts | 126 +++++++++++++++++++++++++++++---------------------- src/index.ts | 7 +++ 2 files changed, 80 insertions(+), 53 deletions(-) create mode 100755 src/index.ts diff --git a/src/app.ts b/src/app.ts index 7414da71..9f1c248d 100755 --- a/src/app.ts +++ b/src/app.ts @@ -1,80 +1,103 @@ -import { attachControllerInstances } from "@decorators/express"; -import express from "express"; -import passport from "passport"; +import { config } from "dotenv"; +import express, { + Application as ExpressApplication, + json, + Router, + urlencoded +} from "express"; import { join } from "path"; import { container } from "tsyringe"; +import cors from "cors"; +import { Connection, createConnection } from "typeorm"; +import { attachControllerInstances } from "@decorators/express"; import { AccountController } from "@controllers/account.controller"; import { AuthenticationController } from "@controllers/authentication.controller"; import { HackerController } from "@controllers/hacker.controller"; import { SearchController } from "@controllers/search.controller"; +import { SettingsController } from "@controllers/settings.controller"; import { SponsorController } from "@controllers/sponsor.controller"; import { TeamController } from "@controllers/team.controller"; import { TravelController } from "@controllers/travel.controller"; -import { SettingsController } from "@controllers/settings.controller"; -import { DatabaseService } from "@services/database.service"; -import { EnvService } from "@services/env.service"; -import { LoggerService } from "@services/logger.service"; import cookieParser from "cookie-parser"; import cookieSession from "cookie-session"; -import cors from "cors"; - -(async () => { - const application = express(); +import passport from "passport"; +import { LoggerService } from "./services/logger.service"; - const envService: EnvService = container.resolve(EnvService); +async function createApplication(): Promise { + const application: ExpressApplication = express(); const loggerService: LoggerService = container.resolve(LoggerService); - const databaseService: DatabaseService = container.resolve(DatabaseService); - await databaseService.connect(); - let corsOptions = {}; + useLogging(application, loggerService); + useEnvironmentFile(); + useCors(application); + useMiddleware(application); + await useDatabase(loggerService); + useControllers(application); - if (!envService.isProduction()) { - corsOptions = { - origin: [`http://${process.env.FRONTEND_ADDRESS_DEV}`], - credentials: true - }; - } else { - // TODO: change this when necessary - corsOptions = { - origin: [ - `https://${process.env.FRONTEND_ADDRESS_DEPLOY}`, - `https://${process.env.FRONTEND_ADDRESS_BETA}`, - `https://docs.mchacks.ca` - ], - credentials: true - }; - } + return application; +} - application.use(cors(corsOptions)); - - application.use( +function useLogging(express: ExpressApplication, loggerService: LoggerService) { + express.use( loggerService.getRequestLogger(), loggerService.getErrorLogger() ); +} - application.use( - express.json(), - express.urlencoded({ - extended: false - }) - ); +function useEnvironmentFile(): void { + const { error } = config({ + path: join(__dirname, "../", `.env.${process.env.NODE_ENV}`) + }); + + if (error) throw error; +} - //Cookie-based session tracking - application.use( +function useCors(express: ExpressApplication): void { + const options = + process.env.NODE_ENV === "production" + ? { + origin: [ + `${process.env.FRONTEND_ADDRESS}`, + `https://docs.mchacks.ca` + ], + credentials: true + } + : { + origin: [`${process.env.FRONTEND_ADDRESS}`], + credentials: true + }; + express.use(cors(options)); +} + +function useMiddleware(express: ExpressApplication): void { + express.use(json(), urlencoded({ extended: false })); + express.use( cookieParser(), cookieSession({ name: "session", - keys: [process.env.COOKIE_SECRET], + keys: [`${process.env.COOKIE_SECRET}`], // Cookie Options maxAge: 48 * 60 * 60 * 1000 //Logged in for 48 hours }) ); + express.use(passport.initialize(), passport.session()); +} - application.use(passport.initialize(), passport.session()); //persistent login session - - application.use(express.static(join(__dirname, "public"))); +async function useDatabase(loggerService: LoggerService): Promise { + await createConnection() + .then((connection: Connection) => { + loggerService.getLogger().info("Connected to the database."); + container.registerInstance(Connection, connection); + }) + .catch((error) => + loggerService + .getLogger() + .error(`Failed to connect to the database. ${error}`) + ); +} - const router = express.Router(); +function useControllers(express: ExpressApplication): void { + const router: Router = Router(); attachControllerInstances(router, [ container.resolve(AccountController), container.resolve(AuthenticationController), @@ -85,10 +108,7 @@ import cors from "cors"; container.resolve(SearchController), container.resolve(SettingsController) ]); - application.use("/api", router); + express.use("/api", router); +} - const port = process.env.PORT ?? 3000; - application.listen(port, () => { - loggerService.getLogger().info(`Listening on port ${port}...`); - }); -})(); +export default createApplication; diff --git a/src/index.ts b/src/index.ts new file mode 100755 index 00000000..40339069 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,7 @@ +import "reflect-metadata"; +import createApplication from "./app"; + +(async () => { + const application = await createApplication(); + application.listen(process.env.PORT || 3000); +})(); From d78aed76d80c6ecda6afbbf1be7d2af09ea1b61e Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Thu, 3 Feb 2022 04:35:00 -0500 Subject: [PATCH 47/72] chore(package.json,package.lock.json): remove unused packages & add testing packages. --- package-lock.json | 7221 ++++++++++++++++++++++++++++++++++++++------- package.json | 28 +- 2 files changed, 6173 insertions(+), 1076 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8e2963c5..7c25c499 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,6 +36,7 @@ "ts-node-dev": "^1.1.8", "tsyringe": "^4.6.0", "typeorm": "^0.2.41", + "typeorm-extension": "^1.1.0", "typescript": "^4.5.2", "winston": "^3.3.3" }, @@ -47,6 +48,7 @@ "@types/express": "^4.17.13", "@types/express-winston": "^4.0.0", "@types/google-cloud__storage": "^1.7.2", + "@types/jest": "^27.4.0", "@types/jsonwebtoken": "^8.5.6", "@types/mjml": "^4.7.0", "@types/multer": "^1.4.7", @@ -55,17 +57,18 @@ "@types/passport-local": "^1.0.34", "@types/qrcode": "^1.4.2", "@types/superagent": "^4.1.13", + "@types/supertest": "^2.0.11", "@types/validator": "^13.7.0", - "@typescript-eslint/eslint-plugin": "^5.8.1", - "@typescript-eslint/parser": "^5.8.1", + "@typescript-eslint/eslint-plugin": "^5.10.0", + "@typescript-eslint/parser": "^5.10.0", "apidoc": "^0.28.1", - "chai": "^4.3.4", - "chai-http": "^4.3.0", - "eslint": "7.31.0", - "eslint-config-prettier": "8.3.0", - "eslint-plugin-prettier": "3.4.0", - "mocha": "^9.0.3", + "eslint": "^7.31.0", + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-prettier": "^3.4.0", + "jest": "^27.4.5", "prettier": "1.19.1", + "supertest": "^6.1.6", + "ts-jest": "^27.1.2", "tsconfig-paths": "^3.12.0" } }, @@ -78,6 +81,277 @@ "@babel/highlight": "^7.10.4" } }, + "node_modules/@babel/compat-data": { + "version": "7.16.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.4.tgz", + "integrity": "sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.7.tgz", + "integrity": "sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.16.7", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helpers": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/core/node_modules/json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/core/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/@babel/core/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/core/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.7.tgz", + "integrity": "sha512-/ST3Sg8MLGY5HVYmrjOgL60ENux/HfO/CsUh7y4MalThufhE/Ff/6EibFDHi4jiDCaWfJKoqbE6oTh21c5hrRg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", + "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.16.4", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.17.5", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", + "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", + "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-get-function-arity": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", + "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz", + "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", + "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", + "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-validator-identifier": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", @@ -87,6 +361,29 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-validator-option": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.7.tgz", + "integrity": "sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/highlight": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz", @@ -172,89 +469,373 @@ "node": ">=4" } }, - "node_modules/@babel/runtime": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz", - "integrity": "sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA==", - "dependencies": { - "regenerator-runtime": "^0.13.4" + "node_modules/@babel/parser": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.7.tgz", + "integrity": "sha512-sR4eaSrnM7BV7QPzGfEX5paG/6wrZM3I0HDzfIAK06ESvo9oy3xBuVBxE3MbQaKNhvg8g/ixjMWo2CGpzpHsDA==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" }, "engines": { - "node": ">=6.9.0" + "node": ">=6.0.0" } }, - "node_modules/@dabh/diagnostics": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", - "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==", + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, "dependencies": { - "colorspace": "1.1.x", - "enabled": "2.0.x", - "kuler": "^2.0.0" + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@decorators/di": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@decorators/di/-/di-1.0.3.tgz", - "integrity": "sha512-wafyQo5lqGABT+Lh7Od9/qULg7DG/kZFU3mLUKZFuiV/KATYlnv198yQxaZUZerhUDoTl/cZKu9t4mJa0rZK4Q==", + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, "dependencies": { - "reflect-metadata": "0.1.13" + "@babel/helper-plugin-utils": "^7.8.0" }, - "engines": { - "node": ">=7.1.0" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@decorators/express": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@decorators/express/-/express-2.6.0.tgz", - "integrity": "sha512-th/LqSAHAAW1ob2CU6hxtsfnryGThmz0AmGP45rA3Yoi0Q7+FHAZVfH7NJSYHITai/uXjjOtZPPW/V0gFfbgUw==", - "engines": { - "node": ">=7.1.0" + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" }, "peerDependencies": { - "@decorators/di": ">=1.0.2", - "express": ">=4.16.3" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" + "@babel/helper-plugin-utils": "^7.10.4" }, - "engines": { - "node": "^10.12.0 || >=12.0.0" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@eslint/eslintrc/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "dev": true, "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" + "@babel/helper-plugin-utils": "^7.8.0" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@eslint/eslintrc/node_modules/ms": { - "version": "2.1.2", + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", + "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz", + "integrity": "sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA==", + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template/node_modules/@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.7.tgz", + "integrity": "sha512-8KWJPIb8c2VvY8AJrydh6+fVRo2ODx1wYBU2398xJVq0JomuLBZmVQzLPBblJgHIGYG4znCpUZUZ0Pt2vdmVYQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/traverse/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/@babel/types": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.7.tgz", + "integrity": "sha512-E8HuV7FO9qLpx6OtoGfUQ2cjIYnbFwvZWYBS+87EwtdMvmUPJSwykpovFB+8insbpF0uJcpr8KMUi64XZntZcg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", + "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "node_modules/@decorators/di": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@decorators/di/-/di-1.0.3.tgz", + "integrity": "sha512-wafyQo5lqGABT+Lh7Od9/qULg7DG/kZFU3mLUKZFuiV/KATYlnv198yQxaZUZerhUDoTl/cZKu9t4mJa0rZK4Q==", + "dependencies": { + "reflect-metadata": "0.1.13" + }, + "engines": { + "node": ">=7.1.0" + } + }, + "node_modules/@decorators/express": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@decorators/express/-/express-2.6.0.tgz", + "integrity": "sha512-th/LqSAHAAW1ob2CU6hxtsfnryGThmz0AmGP45rA3Yoi0Q7+FHAZVfH7NJSYHITai/uXjjOtZPPW/V0gFfbgUw==", + "engines": { + "node": ">=7.1.0" + }, + "peerDependencies": { + "@decorators/di": ">=1.0.2", + "express": ">=4.16.3" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "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 @@ -378,56 +959,391 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, - "node_modules/@mapbox/node-pre-gyp": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.8.tgz", - "integrity": "sha512-CMGKi28CF+qlbXh26hDe6NxCd7amqeAzEqnS6IHeO6LoaKyM/n+Xw3HT1COdq8cuioOdlKdqn/hCmqPUOMOywg==", - "dependencies": { - "detect-libc": "^1.0.3", - "https-proxy-agent": "^5.0.0", - "make-dir": "^3.1.0", - "node-fetch": "^2.6.5", - "nopt": "^5.0.0", - "npmlog": "^5.0.1", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.11" - }, - "bin": { - "node-pre-gyp": "bin/node-pre-gyp" - } - }, - "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==", + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" }, "engines": { - "node": ">= 8" + "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==", + "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, "engines": { - "node": ">= 8" + "node": ">=6" } }, - "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==", + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.4.2.tgz", + "integrity": "sha512-xknHThRsPB/To1FUbi6pCe43y58qFC03zfb6R7fDb/FfC7k2R3i1l+izRBJf8DI46KhYGRaF14Eo9A3qbBoixg==", + "dev": true, + "dependencies": { + "@jest/types": "^27.4.2", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^27.4.2", + "jest-util": "^27.4.2", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/core": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.4.5.tgz", + "integrity": "sha512-3tm/Pevmi8bDsgvo73nX8p/WPng6KWlCyScW10FPEoN1HU4pwI83tJ3TsFvi1FfzsjwUlMNEPowgb/rPau/LTQ==", + "dev": true, + "dependencies": { + "@jest/console": "^27.4.2", + "@jest/reporters": "^27.4.5", + "@jest/test-result": "^27.4.2", + "@jest/transform": "^27.4.5", + "@jest/types": "^27.4.2", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-changed-files": "^27.4.2", + "jest-config": "^27.4.5", + "jest-haste-map": "^27.4.5", + "jest-message-util": "^27.4.2", + "jest-regex-util": "^27.4.0", + "jest-resolve": "^27.4.5", + "jest-resolve-dependencies": "^27.4.5", + "jest-runner": "^27.4.5", + "jest-runtime": "^27.4.5", + "jest-snapshot": "^27.4.5", + "jest-util": "^27.4.2", + "jest-validate": "^27.4.2", + "jest-watcher": "^27.4.2", + "micromatch": "^4.0.4", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "27.4.4", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.4.4.tgz", + "integrity": "sha512-q+niMx7cJgt/t/b6dzLOh4W8Ef/8VyKG7hxASK39jakijJzbFBGpptx3RXz13FFV7OishQ9lTbv+dQ5K3EhfDQ==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^27.4.2", + "@jest/types": "^27.4.2", + "@types/node": "*", + "jest-mock": "^27.4.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.4.2.tgz", + "integrity": "sha512-f/Xpzn5YQk5adtqBgvw1V6bF8Nx3hY0OIRRpCvWcfPl0EAjdqWPdhH3t/3XpiWZqtjIEHDyMKP9ajpva1l4Zmg==", + "dev": true, + "dependencies": { + "@jest/types": "^27.4.2", + "@sinonjs/fake-timers": "^8.0.1", + "@types/node": "*", + "jest-message-util": "^27.4.2", + "jest-mock": "^27.4.2", + "jest-util": "^27.4.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "27.4.4", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.4.4.tgz", + "integrity": "sha512-bqpqQhW30BOreXM8bA8t8JbOQzsq/WnPTnBl+It3UxAD9J8yxEAaBEylHx1dtBapAr/UBk8GidXbzmqnee8tYQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.4.4", + "@jest/types": "^27.4.2", + "expect": "^27.4.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.4.5.tgz", + "integrity": "sha512-3orsG4vi8zXuBqEoy2LbnC1kuvkg1KQUgqNxmxpQgIOQEPeV0onvZu+qDQnEoX8qTQErtqn/xzcnbpeTuOLSiA==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^27.4.2", + "@jest/test-result": "^27.4.2", + "@jest/transform": "^27.4.5", + "@jest/types": "^27.4.2", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.4", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^4.0.3", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "jest-haste-map": "^27.4.5", + "jest-resolve": "^27.4.5", + "jest-util": "^27.4.2", + "jest-worker": "^27.4.5", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^8.1.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/source-map": { + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.4.0.tgz", + "integrity": "sha512-Ntjx9jzP26Bvhbm93z/AKcPRj/9wrkI88/gK60glXDx1q+IeI0rf7Lw2c89Ch6ofonB0On/iRDreQuQ6te9pgQ==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.4", + "source-map": "^0.6.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.4.2.tgz", + "integrity": "sha512-kr+bCrra9jfTgxHXHa2UwoQjxvQk3Am6QbpAiJ5x/50LW8llOYrxILkqY0lZRW/hu8FXesnudbql263+EW9iNA==", + "dev": true, + "dependencies": { + "@jest/console": "^27.4.2", + "@jest/types": "^27.4.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.4.5.tgz", + "integrity": "sha512-n5woIn/1v+FT+9hniymHPARA9upYUmfi5Pw9ewVwXCDlK4F5/Gkees9v8vdjGdAIJ2MPHLHodiajLpZZanWzEQ==", + "dev": true, + "dependencies": { + "@jest/test-result": "^27.4.2", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.4.5", + "jest-runtime": "^27.4.5" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.4.5.tgz", + "integrity": "sha512-PuMet2UlZtlGzwc6L+aZmR3I7CEBpqadO03pU40l2RNY2fFJ191b9/ITB44LNOhVtsyykx0OZvj0PCyuLm7Eew==", + "dev": true, + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.4.2", + "babel-plugin-istanbul": "^6.0.0", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.4.5", + "jest-regex-util": "^27.4.0", + "jest-util": "^27.4.2", + "micromatch": "^4.0.4", + "pirates": "^4.0.1", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/types": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", + "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.8.tgz", + "integrity": "sha512-CMGKi28CF+qlbXh26hDe6NxCd7amqeAzEqnS6IHeO6LoaKyM/n+Xw3HT1COdq8cuioOdlKdqn/hCmqPUOMOywg==", + "dependencies": { + "detect-libc": "^1.0.3", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.5", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "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" } @@ -441,6 +1357,24 @@ "node": ">=6" } }, + "node_modules/@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, "node_modules/@sqltools/formatter": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.3.tgz", @@ -466,6 +1400,52 @@ "node": ">= 10" } }, + "node_modules/@trapi/query": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@trapi/query/-/query-2.0.3.tgz", + "integrity": "sha512-4N7pQyCPQfkd/LyKhowNVdgQMkhTdxPO9Yb4qrl0AGlPL3Duhu8vexZaQeBRSiPxQ/3giHM1OYRYHDk6hGtLGg==" + }, + "node_modules/@types/babel__core": { + "version": "7.1.18", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.18.tgz", + "integrity": "sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", + "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.3.0" + } + }, "node_modules/@types/bcrypt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.0.tgz", @@ -499,12 +1479,6 @@ "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==", "dev": true }, - "node_modules/@types/chai": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.0.tgz", - "integrity": "sha512-/ceqdqeRraGolFTcfoXNiqjyQhZzbINDngeoAq9GoHa8PPK1yNzTaxWjA6BFWp5Ua9JpXEMSS4s5i9tS0hOJtw==", - "dev": true - }, "node_modules/@types/connect": { "version": "3.4.35", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", @@ -588,6 +1562,49 @@ "@types/request": "*" } }, + "node_modules/@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.4.0.tgz", + "integrity": "sha512-gHl8XuC1RZ8H2j5sHv/JqsaxXkDDM9iDOgu0Wp8sjs4u/snb2PVehyWXJPr+ORA0RPpgw231mnutWI1+0hgjIQ==", + "dev": true, + "dependencies": { + "jest-diff": "^27.0.0", + "pretty-format": "^27.0.0" + } + }, "node_modules/@types/json-schema": { "version": "7.0.9", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", @@ -698,6 +1715,12 @@ "@types/passport": "*" } }, + "node_modules/@types/prettier": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.2.tgz", + "integrity": "sha512-ekoj4qOQYp7CvjX8ZDBgN86w3MqQhLE1hczEJbEIjgFEumDy+na/4AJAbLXfgEWFNB2pKadM5rPFtuSGMWK7xA==", + "dev": true + }, "node_modules/@types/qrcode": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.4.2.tgz", @@ -741,6 +1764,12 @@ "@types/node": "*" } }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, "node_modules/@types/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", @@ -761,6 +1790,15 @@ "@types/node": "*" } }, + "node_modules/@types/supertest": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-2.0.11.tgz", + "integrity": "sha512-uci4Esokrw9qGb9bvhhSVEjd6rkny/dk5PK/Qz4yxKiyppEI+dOPlNrZBahE3i+PoKFYyDxChVXZ/ysS/nrm1Q==", + "dev": true, + "dependencies": { + "@types/superagent": "*" + } + }, "node_modules/@types/tough-cookie": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.1.tgz", @@ -773,19 +1811,35 @@ "integrity": "sha512-I6OUIZ5cYRk5lp14xSOAiXjWrfVoMZVjDuevBYgQDYzZIjsf2CAISpEcXOkFAtpAHbmWIDLcZObejqny/9xq5Q==", "dev": true }, + "node_modules/@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "20.2.1", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", + "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", + "dev": true + }, "node_modules/@types/zen-observable": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.3.tgz", "integrity": "sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw==" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.8.1.tgz", - "integrity": "sha512-wTZ5oEKrKj/8/366qTM366zqhIKAp6NCMweoRONtfuC07OAU9nVI2GZZdqQ1qD30WAAtcPdkH+npDwtRFdp4Rw==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.10.0.tgz", + "integrity": "sha512-XXVKnMsq2fuu9K2KsIxPUGqb6xAImz8MEChClbXmE3VbveFtBUU5bzM6IPVWqzyADIgdkS2Ws/6Xo7W2TeZWjQ==", "dev": true, "dependencies": { - "@typescript-eslint/experimental-utils": "5.8.1", - "@typescript-eslint/scope-manager": "5.8.1", + "@typescript-eslint/scope-manager": "5.10.0", + "@typescript-eslint/type-utils": "5.10.0", + "@typescript-eslint/utils": "5.10.0", "debug": "^4.3.2", "functional-red-black-tree": "^1.0.1", "ignore": "^5.1.8", @@ -810,16 +1864,42 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/experimental-utils": { - "version": "5.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.8.1.tgz", - "integrity": "sha512-fbodVnjIDU4JpeXWRDsG5IfIjYBxEvs8EBO8W1+YVdtrc2B9ppfof5sZhVEDOtgTfFHnYQJDI8+qdqLYO4ceww==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.10.0.tgz", + "integrity": "sha512-TzlyTmufJO5V886N+hTJBGIfnjQDQ32rJYxPaeiyWKdjsv2Ld5l8cbS7pxim4DeNs62fKzRSt8Q14Evs4JnZyQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "5.10.0", + "debug": "^4.3.2", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.10.0.tgz", + "integrity": "sha512-IGYwlt1CVcFoE2ueW4/ioEwybR60RAdGeiJX/iDAw0t5w0wK3S7QncDwpmsM70nKgGTuVchEWB8lwZwHqPAWRg==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.8.1", - "@typescript-eslint/types": "5.8.1", - "@typescript-eslint/typescript-estree": "5.8.1", + "@typescript-eslint/scope-manager": "5.10.0", + "@typescript-eslint/types": "5.10.0", + "@typescript-eslint/typescript-estree": "5.10.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0" }, @@ -834,7 +1914,7 @@ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/experimental-utils/node_modules/eslint-utils": { + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils/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==", @@ -885,14 +1965,14 @@ "dev": true }, "node_modules/@typescript-eslint/parser": { - "version": "5.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.8.1.tgz", - "integrity": "sha512-K1giKHAjHuyB421SoXMXFHHVI4NdNY603uKw92++D3qyxSeYvC10CBJ/GE5Thpo4WTUvu1mmJI2/FFkz38F2Gw==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.10.0.tgz", + "integrity": "sha512-pJB2CCeHWtwOAeIxv8CHVGJhI5FNyJAIpx5Pt72YkK3QfEzt6qAlXZuyaBmyfOdM62qU0rbxJzNToPTVeJGrQw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.8.1", - "@typescript-eslint/types": "5.8.1", - "@typescript-eslint/typescript-estree": "5.8.1", + "@typescript-eslint/scope-manager": "5.10.0", + "@typescript-eslint/types": "5.10.0", + "@typescript-eslint/typescript-estree": "5.10.0", "debug": "^4.3.2" }, "engines": { @@ -935,13 +2015,13 @@ "dev": true }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.8.1.tgz", - "integrity": "sha512-DGxJkNyYruFH3NIZc3PwrzwOQAg7vvgsHsHCILOLvUpupgkwDZdNq/cXU3BjF4LNrCsVg0qxEyWasys5AiJ85Q==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.10.0.tgz", + "integrity": "sha512-tgNgUgb4MhqK6DoKn3RBhyZ9aJga7EQrw+2/OiDk5hKf3pTVZWyqBi7ukP+Z0iEEDMF5FDa64LqODzlfE4O/Dg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.8.1", - "@typescript-eslint/visitor-keys": "5.8.1" + "@typescript-eslint/types": "5.10.0", + "@typescript-eslint/visitor-keys": "5.10.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -952,9 +2032,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.8.1.tgz", - "integrity": "sha512-L/FlWCCgnjKOLefdok90/pqInkomLnAcF9UAzNr+DSqMC3IffzumHTQTrINXhP1gVp9zlHiYYjvozVZDPleLcA==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.10.0.tgz", + "integrity": "sha512-wUljCgkqHsMZbw60IbOqT/puLfyqqD5PquGiBo1u1IS3PLxdi3RDGlyf032IJyh+eQoGhz9kzhtZa+VC4eWTlQ==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -965,13 +2045,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.8.1.tgz", - "integrity": "sha512-26lQ8l8tTbG7ri7xEcCFT9ijU5Fk+sx/KRRyyzCv7MQ+rZZlqiDPtMKWLC8P7o+dtCnby4c+OlxuX1tp8WfafQ==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.10.0.tgz", + "integrity": "sha512-x+7e5IqfwLwsxTdliHRtlIYkgdtYXzE0CkFeV6ytAqq431ZyxCFzNMNR5sr3WOlIG/ihVZr9K/y71VHTF/DUQA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.8.1", - "@typescript-eslint/visitor-keys": "5.8.1", + "@typescript-eslint/types": "5.10.0", + "@typescript-eslint/visitor-keys": "5.10.0", "debug": "^4.3.2", "globby": "^11.0.4", "is-glob": "^4.0.3", @@ -1015,12 +2095,12 @@ "dev": true }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.8.1.tgz", - "integrity": "sha512-SWgiWIwocK6NralrJarPZlWdr0hZnj5GXHIgfdm8hNkyKvpeQuFyLP6YjSIe9kf3YBIfU6OHSZLYkQ+smZwtNg==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.10.0.tgz", + "integrity": "sha512-GMxj0K1uyrFLPKASLmZzCuSddmjZVbVj3Ouy5QVuIGKZopxvOr24JsS7gruz6C3GExE01mublZ3mIBOaon9zuQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.8.1", + "@typescript-eslint/types": "5.10.0", "eslint-visitor-keys": "^3.0.0" }, "engines": { @@ -1032,18 +2112,18 @@ } }, "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz", - "integrity": "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz", + "integrity": "sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "node_modules/abab": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", "dev": true }, "node_modules/abbrev": { @@ -1086,6 +2166,16 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -1095,6 +2185,15 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -1160,6 +2259,33 @@ "node": ">=6" } }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -1304,15 +2430,6 @@ "node": ">=8" } }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -1350,6 +2467,123 @@ "node": ">= 4.0.0" } }, + "node_modules/babel-jest": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.4.5.tgz", + "integrity": "sha512-3uuUTjXbgtODmSv/DXO9nZfD52IyC2OYTFaXGRzL0kpykzroaquCrD5+lZNafTvZlnNqZHt5pb0M08qVBZnsnA==", + "dev": true, + "dependencies": { + "@jest/transform": "^27.4.5", + "@jest/types": "^27.4.2", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.0.0", + "babel-preset-jest": "^27.4.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", + "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.4.0.tgz", + "integrity": "sha512-Jcu7qS4OX5kTWBc45Hz7BMmgXuJqRnhatqpUhnzGC3OBYpOmf2tv6jFNwZpwM7wU7MUuv2r9IPS/ZlYOuburVw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.4.0.tgz", + "integrity": "sha512-NK4jGYpnBvNxcGo7/ZpZJr51jCGT+3bwwpVIDY2oNfTxJJldRtB4VAcYdgp1loDE50ODuTu+yBjpMAswv5tlpg==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^27.4.0", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1554,12 +2788,56 @@ "node": ">=8" } }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", "dev": true }, + "node_modules/browserslist": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", + "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", + "dev": true, + "dependencies": { + "caniuse-lite": "^1.0.30001286", + "electron-to-chromium": "^1.4.17", + "escalade": "^3.1.1", + "node-releases": "^2.0.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, "node_modules/bson": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", @@ -1735,49 +3013,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/chai": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.4.tgz", - "integrity": "sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==", - "dev": true, - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^3.0.1", - "get-func-name": "^2.0.0", - "pathval": "^1.1.1", - "type-detect": "^4.0.5" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chai-http": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/chai-http/-/chai-http-4.3.0.tgz", - "integrity": "sha512-zFTxlN7HLMv+7+SPXZdkd5wUlK+KxH6Q7bIEMiEx0FK3zuuMqL7cwICAQ0V1+yYRozBburYuxN1qZstgHpFZQg==", - "dev": true, - "dependencies": { - "@types/chai": "4", - "@types/superagent": "^3.8.3", - "cookiejar": "^2.1.1", - "is-ip": "^2.0.0", - "methods": "^1.1.2", - "qs": "^6.5.1", - "superagent": "^3.7.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chai-http/node_modules/@types/superagent": { - "version": "3.8.7", - "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-3.8.7.tgz", - "integrity": "sha512-9KhCkyXv268A2nZ1Wvu7rQWM+BmdYUVkycFeNnYrUL5Zwu7o8wPQ3wBfW59dDP+wuoxw0ww8YKgTNv8j/cgscA==", + "node_modules/caniuse-lite": { + "version": "1.0.30001295", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001295.tgz", + "integrity": "sha512-lSP16vcyC0FEy0R4ECc9duSPoKoZy+YkpGkue9G4D81OfPnliopaZrU10+qtPdT8PbGXad/PNx43TIQrOmJZSQ==", "dev": true, - "dependencies": { - "@types/cookiejar": "*", - "@types/node": "*" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" } }, "node_modules/chalk": { @@ -1795,13 +3038,13 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/check-error": { + "node_modules/char-regex": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true, "engines": { - "node": "*" + "node": ">=10" } }, "node_modules/cheerio": { @@ -1873,6 +3116,12 @@ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "dev": true }, + "node_modules/cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true + }, "node_modules/class-transformer": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", @@ -1954,6 +3203,22 @@ "mimic-response": "^1.0.0" } }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, "node_modules/color": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", @@ -2155,6 +3420,21 @@ "node": ">= 0.6" } }, + "node_modules/convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/convert-source-map/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==", + "dev": true + }, "node_modules/cookie": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", @@ -2282,6 +3562,79 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + }, + "node_modules/data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "dependencies": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/data-urls/node_modules/tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/data-urls/node_modules/webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true, + "engines": { + "node": ">=10.4" + } + }, + "node_modules/data-urls/node_modules/whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dev": true, + "dependencies": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/date-and-time": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-2.0.1.tgz", @@ -2295,17 +3648,11 @@ "ms": "^2.1.1" } }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "node_modules/decimal.js": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", + "dev": true }, "node_modules/decompress-response": { "version": "3.3.0", @@ -2319,17 +3666,11 @@ "node": ">=4" } }, - "node_modules/deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", - "dev": true, - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=0.12" - } + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true }, "node_modules/deep-extend": { "version": "0.6.0", @@ -2346,6 +3687,15 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/defer-to-connect": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", @@ -2398,9 +3748,18 @@ "node": ">=0.10" } }, - "node_modules/detect-node": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==" }, "node_modules/dicer": { @@ -2436,13 +3795,13 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" }, - "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "node_modules/diff-sequences": { + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.4.0.tgz", + "integrity": "sha512-YqiQzkrsmHMH5uuh8OdQFU9/ZpADnwzml8z0O5HvRNda+5UZsaX/xN+AAxfR2hWq1Y7HZnAzO9J5lJXOuDz2Ww==", "dev": true, "engines": { - "node": ">=0.3.1" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/dijkstrajs": { @@ -2498,6 +3857,27 @@ } ] }, + "node_modules/domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dev": true, + "dependencies": { + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/domhandler": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", @@ -2618,6 +3998,24 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "node_modules/electron-to-chromium": { + "version": "1.4.31", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.31.tgz", + "integrity": "sha512-t3XVQtk+Frkv6aTD4RRk0OqosU+VLe1dQFW83MDer78ZD6a52frgXuYOIsLYTQiH2Lm+JB2OKYcn7zrX+YGAiQ==", + "dev": true + }, + "node_modules/emittery": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -2705,6 +4103,88 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "dev": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/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/escodegen/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/eslint": { "version": "7.31.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.31.0.tgz", @@ -2976,6 +4456,67 @@ "node": ">=6" } }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.4.2.tgz", + "integrity": "sha512-BjAXIDC6ZOW+WBFNg96J22D27Nq5ohn+oGcuP2rtOtcjuxNoV9McpQ60PcQWhdFOSBIQdR72e+4HdnbZTFSTyg==", + "dev": true, + "dependencies": { + "@jest/types": "^27.4.2", + "ansi-styles": "^5.0.0", + "jest-get-type": "^27.4.0", + "jest-matcher-utils": "^27.4.2", + "jest-message-util": "^27.4.2", + "jest-regex-util": "^27.4.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/expect/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/express": { "version": "4.17.2", "resolved": "https://registry.npmjs.org/express/-/express-4.17.2.tgz", @@ -3145,9 +4686,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -3157,7 +4698,7 @@ "micromatch": "^4.0.4" }, "engines": { - "node": ">=8" + "node": ">=8.6.0" } }, "node_modules/fast-json-stable-stringify": { @@ -3172,6 +4713,12 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true + }, "node_modules/fast-text-encoding": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", @@ -3186,6 +4733,15 @@ "reusify": "^1.0.4" } }, + "node_modules/fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, "node_modules/fecha": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz", @@ -3244,31 +4800,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, - "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": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } - }, "node_modules/flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -3455,6 +4986,15 @@ "node": ">=10" } }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -3463,15 +5003,6 @@ "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/get-intrinsic": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", @@ -3486,6 +5017,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -3567,16 +5107,16 @@ } }, "node_modules/globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", "slash": "^3.0.0" }, "engines": { @@ -3667,15 +5207,6 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" }, - "node_modules/growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true, - "engines": { - "node": ">=4.x" - } - }, "node_modules/gtoken": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.3.1.tgz", @@ -3775,6 +5306,24 @@ "node": "*" } }, + "node_modules/html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^1.0.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, "node_modules/html-minifier": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-4.0.0.tgz", @@ -3909,6 +5458,15 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -3980,6 +5538,22 @@ "node": ">=4" } }, + "node_modules/import-local": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz", + "integrity": "sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -4007,15 +5581,6 @@ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, - "node_modules/ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -4079,6 +5644,15 @@ "node": ">=8" } }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -4106,18 +5680,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ip/-/is-ip-2.0.0.tgz", - "integrity": "sha1-aO6gfooKCpTC0IDdZ0xzGrKkYas=", - "dev": true, - "dependencies": { - "ip-regex": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/is-npm": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", @@ -4155,14 +5717,11 @@ "node": ">=8" } }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "engines": { - "node": ">=8" - } + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true }, "node_modules/is-stream": { "version": "2.0.1", @@ -4180,18 +5739,6 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-yarn-global": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", @@ -4209,42 +5756,944 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "node_modules/js-beautify": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.0.tgz", - "integrity": "sha512-yuck9KirNSCAwyNJbqW+BxJqJ0NLJ4PwBUzQQACl5O3qHMBXVkXb/rD0ilh/Lat/tn88zSZ+CAHOlk0DsY7GuQ==", + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, "dependencies": { - "config-chain": "^1.1.12", - "editorconfig": "^0.15.3", - "glob": "^7.1.3", - "nopt": "^5.0.0" + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, "bin": { - "css-beautify": "js/bin/css-beautify.js", - "html-beautify": "js/bin/html-beautify.js", - "js-beautify": "js/bin/js-beautify.js" + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/istanbul-lib-source-maps/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/istanbul-reports": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.3.tgz", + "integrity": "sha512-x9LtDVtfm/t1GFiLl3NffC7hz+I1ragvgX1P/Lg1NlIagifZDKUkuuaAxH/qpwj2IuEfD8G2Bs/UKp+sZ/pKkg==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.4.5.tgz", + "integrity": "sha512-uT5MiVN3Jppt314kidCk47MYIRilJjA/l2mxwiuzzxGUeJIvA8/pDaJOAX5KWvjAo7SCydcW0/4WEtgbLMiJkg==", + "dev": true, + "dependencies": { + "@jest/core": "^27.4.5", + "import-local": "^3.0.2", + "jest-cli": "^27.4.5" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.4.2.tgz", + "integrity": "sha512-/9x8MjekuzUQoPjDHbBiXbNEBauhrPU2ct7m8TfCg69ywt1y/N+yYwGh3gCpnqUS3klYWDU/lSNgv+JhoD2k1A==", + "dev": true, + "dependencies": { + "@jest/types": "^27.4.2", + "execa": "^5.0.0", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.4.5.tgz", + "integrity": "sha512-eTNWa9wsvBwPykhMMShheafbwyakcdHZaEYh5iRrQ0PFJxkDP/e3U/FvzGuKWu2WpwUA3C3hPlfpuzvOdTVqnw==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.4.4", + "@jest/test-result": "^27.4.2", + "@jest/types": "^27.4.2", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.4.2", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.4.2", + "jest-matcher-utils": "^27.4.2", + "jest-message-util": "^27.4.2", + "jest-runtime": "^27.4.5", + "jest-snapshot": "^27.4.5", + "jest-util": "^27.4.2", + "pretty-format": "^27.4.2", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-cli": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.4.5.tgz", + "integrity": "sha512-hrky3DSgE0u7sQxaCL7bdebEPHx5QzYmrGuUjaPLmPE8jx5adtvGuOlRspvMoVLTTDOHRnZDoRLYJuA+VCI7Hg==", + "dev": true, + "dependencies": { + "@jest/core": "^27.4.5", + "@jest/test-result": "^27.4.2", + "@jest/types": "^27.4.2", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "import-local": "^3.0.2", + "jest-config": "^27.4.5", + "jest-util": "^27.4.2", + "jest-validate": "^27.4.2", + "prompts": "^2.0.1", + "yargs": "^16.2.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.4.5.tgz", + "integrity": "sha512-t+STVJtPt+fpqQ8GBw850NtSQbnDOw/UzdPfzDaHQ48/AylQlW7LHj3dH+ndxhC1UxJ0Q3qkq7IH+nM1skwTwA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^27.4.5", + "@jest/types": "^27.4.2", + "babel-jest": "^27.4.5", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.4", + "jest-circus": "^27.4.5", + "jest-environment-jsdom": "^27.4.4", + "jest-environment-node": "^27.4.4", + "jest-get-type": "^27.4.0", + "jest-jasmine2": "^27.4.5", + "jest-regex-util": "^27.4.0", + "jest-resolve": "^27.4.5", + "jest-runner": "^27.4.5", + "jest-util": "^27.4.2", + "jest-validate": "^27.4.2", + "micromatch": "^4.0.4", + "pretty-format": "^27.4.2", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/ci-info": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", + "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", + "dev": true + }, + "node_modules/jest-diff": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.4.2.tgz", + "integrity": "sha512-ujc9ToyUZDh9KcqvQDkk/gkbf6zSaeEg9AiBxtttXW59H/AcqEYp1ciXAtJp+jXWva5nAf/ePtSsgWwE5mqp4Q==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^27.4.0", + "jest-get-type": "^27.4.0", + "pretty-format": "^27.4.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.4.0.tgz", + "integrity": "sha512-7TBazUdCKGV7svZ+gh7C8esAnweJoG+SvcF6Cjqj4l17zA2q1cMwx2JObSioubk317H+cjcHgP+7fTs60paulg==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-each": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.4.2.tgz", + "integrity": "sha512-53V2MNyW28CTruB3lXaHNk6PkiIFuzdOC9gR3C6j8YE/ACfrPnz+slB0s17AgU1TtxNzLuHyvNlLJ+8QYw9nBg==", + "dev": true, + "dependencies": { + "@jest/types": "^27.4.2", + "chalk": "^4.0.0", + "jest-get-type": "^27.4.0", + "jest-util": "^27.4.2", + "pretty-format": "^27.4.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-jsdom": { + "version": "27.4.4", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.4.4.tgz", + "integrity": "sha512-cYR3ndNfHBqQgFvS1RL7dNqSvD//K56j/q1s2ygNHcfTCAp12zfIromO1w3COmXrxS8hWAh7+CmZmGCIoqGcGA==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.4.4", + "@jest/fake-timers": "^27.4.2", + "@jest/types": "^27.4.2", + "@types/node": "*", + "jest-mock": "^27.4.2", + "jest-util": "^27.4.2", + "jsdom": "^16.6.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "27.4.4", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.4.4.tgz", + "integrity": "sha512-D+v3lbJ2GjQTQR23TK0kY3vFVmSeea05giInI41HHOaJnAwOnmUHTZgUaZL+VxUB43pIzoa7PMwWtCVlIUoVoA==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.4.4", + "@jest/fake-timers": "^27.4.2", + "@jest/types": "^27.4.2", + "@types/node": "*", + "jest-mock": "^27.4.2", + "jest-util": "^27.4.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", + "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.4.5.tgz", + "integrity": "sha512-oJm1b5qhhPs78K24EDGifWS0dELYxnoBiDhatT/FThgB9yxqUm5F6li3Pv+Q+apMBmmPNzOBnZ7ZxWMB1Leq1Q==", + "dev": true, + "dependencies": { + "@jest/types": "^27.4.2", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-regex-util": "^27.4.0", + "jest-serializer": "^27.4.0", + "jest-util": "^27.4.2", + "jest-worker": "^27.4.5", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-jasmine2": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.4.5.tgz", + "integrity": "sha512-oUnvwhJDj2LhOiUB1kdnJjkx8C5PwgUZQb9urF77mELH9DGR4e2GqpWQKBOYXWs5+uTN9BGDqRz3Aeg5Wts7aw==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^27.4.4", + "@jest/source-map": "^27.4.0", + "@jest/test-result": "^27.4.2", + "@jest/types": "^27.4.2", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.4.2", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.4.2", + "jest-matcher-utils": "^27.4.2", + "jest-message-util": "^27.4.2", + "jest-runtime": "^27.4.5", + "jest-snapshot": "^27.4.5", + "jest-util": "^27.4.2", + "pretty-format": "^27.4.2", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-leak-detector": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.4.2.tgz", + "integrity": "sha512-ml0KvFYZllzPBJWDei3mDzUhyp/M4ubKebX++fPaudpe8OsxUE+m+P6ciVLboQsrzOCWDjE20/eXew9QMx/VGw==", + "dev": true, + "dependencies": { + "jest-get-type": "^27.4.0", + "pretty-format": "^27.4.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.4.2.tgz", + "integrity": "sha512-jyP28er3RRtMv+fmYC/PKG8wvAmfGcSNproVTW2Y0P/OY7/hWUOmsPfxN1jOhM+0u2xU984u2yEagGivz9OBGQ==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^27.4.2", + "jest-get-type": "^27.4.0", + "pretty-format": "^27.4.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.4.2.tgz", + "integrity": "sha512-OMRqRNd9E0DkBLZpFtZkAGYOXl6ZpoMtQJWTAREJKDOFa0M6ptB7L67tp+cszMBkvSgKOhNtQp2Vbcz3ZZKo/w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.4.2", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.4", + "pretty-format": "^27.4.2", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-message-util/node_modules/@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/jest-mock": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.4.2.tgz", + "integrity": "sha512-PDDPuyhoukk20JrQKeofK12hqtSka7mWH0QQuxSNgrdiPsrnYYLS6wbzu/HDlxZRzji5ylLRULeuI/vmZZDrYA==", + "dev": true, + "dependencies": { + "@jest/types": "^27.4.2", + "@types/node": "*" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.4.0.tgz", + "integrity": "sha512-WeCpMpNnqJYMQoOjm1nTtsgbR4XHAk1u00qDoNBQoykM280+/TmgA5Qh5giC1ecy6a5d4hbSsHzpBtu5yvlbEg==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.4.5.tgz", + "integrity": "sha512-xU3z1BuOz/hUhVUL+918KqUgK+skqOuUsAi7A+iwoUldK6/+PW+utK8l8cxIWT9AW7IAhGNXjSAh1UYmjULZZw==", + "dev": true, + "dependencies": { + "@jest/types": "^27.4.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.4.5", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.4.2", + "jest-validate": "^27.4.2", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.4.5.tgz", + "integrity": "sha512-elEVvkvRK51y037NshtEkEnukMBWvlPzZHiL847OrIljJ8yIsujD2GXRPqDXC4rEVKbcdsy7W0FxoZb4WmEs7w==", + "dev": true, + "dependencies": { + "@jest/types": "^27.4.2", + "jest-regex-util": "^27.4.0", + "jest-snapshot": "^27.4.5" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runner": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.4.5.tgz", + "integrity": "sha512-/irauncTfmY1WkTaRQGRWcyQLzK1g98GYG/8QvIPviHgO1Fqz1JYeEIsSfF+9mc/UTA6S+IIHFgKyvUrtiBIZg==", + "dev": true, + "dependencies": { + "@jest/console": "^27.4.2", + "@jest/environment": "^27.4.4", + "@jest/test-result": "^27.4.2", + "@jest/transform": "^27.4.5", + "@jest/types": "^27.4.2", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-docblock": "^27.4.0", + "jest-environment-jsdom": "^27.4.4", + "jest-environment-node": "^27.4.4", + "jest-haste-map": "^27.4.5", + "jest-leak-detector": "^27.4.2", + "jest-message-util": "^27.4.2", + "jest-resolve": "^27.4.5", + "jest-runtime": "^27.4.5", + "jest-util": "^27.4.2", + "jest-worker": "^27.4.5", + "source-map-support": "^0.5.6", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.4.5.tgz", + "integrity": "sha512-CIYqwuJQXHQtPd/idgrx4zgJ6iCb6uBjQq1RSAGQrw2S8XifDmoM1Ot8NRd80ooAm+ZNdHVwsktIMGlA1F1FAQ==", + "dev": true, + "dependencies": { + "@jest/console": "^27.4.2", + "@jest/environment": "^27.4.4", + "@jest/globals": "^27.4.4", + "@jest/source-map": "^27.4.0", + "@jest/test-result": "^27.4.2", + "@jest/transform": "^27.4.5", + "@jest/types": "^27.4.2", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.4.5", + "jest-message-util": "^27.4.2", + "jest-mock": "^27.4.2", + "jest-regex-util": "^27.4.0", + "jest-resolve": "^27.4.5", + "jest-snapshot": "^27.4.5", + "jest-util": "^27.4.2", + "jest-validate": "^27.4.2", + "slash": "^3.0.0", + "strip-bom": "^4.0.0", + "yargs": "^16.2.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runtime/node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-serializer": { + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.4.0.tgz", + "integrity": "sha512-RDhpcn5f1JYTX2pvJAGDcnsNTnsV9bjYPU8xcV+xPwOXnUPOQwf4ZEuiU6G9H1UztH+OapMgu/ckEVwO87PwnQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "graceful-fs": "^4.2.4" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.4.5.tgz", + "integrity": "sha512-eCi/iM1YJFrJWiT9de4+RpWWWBqsHiYxFG9V9o/n0WXs6GpW4lUt4FAHAgFPTLPqCUVzrMQmSmTZSgQzwqR7IQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/parser": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.4.5", + "@jest/types": "^27.4.2", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^27.4.2", + "graceful-fs": "^4.2.4", + "jest-diff": "^27.4.2", + "jest-get-type": "^27.4.0", + "jest-haste-map": "^27.4.5", + "jest-matcher-utils": "^27.4.2", + "jest-message-util": "^27.4.2", + "jest-resolve": "^27.4.5", + "jest-util": "^27.4.2", + "natural-compare": "^1.4.0", + "pretty-format": "^27.4.2", + "semver": "^7.3.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-util": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.4.2.tgz", + "integrity": "sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA==", + "dev": true, + "dependencies": { + "@jest/types": "^27.4.2", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.4", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-util/node_modules/ci-info": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", + "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", + "dev": true + }, + "node_modules/jest-validate": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.4.2.tgz", + "integrity": "sha512-hWYsSUej+Fs8ZhOm5vhWzwSLmVaPAxRy+Mr+z5MzeaHm9AxUpXdoVMEW4R86y5gOobVfBsMFLk4Rb+QkiEpx1A==", + "dev": true, + "dependencies": { + "@jest/types": "^27.4.2", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.4.0", + "leven": "^3.1.0", + "pretty-format": "^27.4.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-watcher": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.4.2.tgz", + "integrity": "sha512-NJvMVyyBeXfDezhWzUOCOYZrUmkSCiatpjpm+nFUid74OZEHk6aMLrZAukIiFDwdbqp6mTM6Ui1w4oc+8EobQg==", + "dev": true, + "dependencies": { + "@jest/test-result": "^27.4.2", + "@jest/types": "^27.4.2", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^27.4.2", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-worker": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.5.tgz", + "integrity": "sha512-f2s8kEdy15cv9r7q4KkzGXvlY0JTcmCbMHZBfSQDwW77REr45IDWwd0lksDFeVHH2jJ5pqb90T77XscrjeGzzg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-beautify": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.0.tgz", + "integrity": "sha512-yuck9KirNSCAwyNJbqW+BxJqJ0NLJ4PwBUzQQACl5O3qHMBXVkXb/rD0ilh/Lat/tn88zSZ+CAHOlk0DsY7GuQ==", + "dependencies": { + "config-chain": "^1.1.12", + "editorconfig": "^0.15.3", + "glob": "^7.1.3", + "nopt": "^5.0.0" + }, + "bin": { + "css-beautify": "js/bin/css-beautify.js", + "html-beautify": "js/bin/html-beautify.js", + "js-beautify": "js/bin/js-beautify.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "dev": true, + "dependencies": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jsdom/node_modules/acorn": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/jsdom/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jsdom/node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jsdom/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/jsdom/node_modules/tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" }, "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "node_modules/jsdom/node_modules/webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true, + "engines": { + "node": ">=10.4" + } }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "node_modules/jsdom/node_modules/whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", "dev": true, "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, "bin": { - "js-yaml": "bin/js-yaml.js" + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" } }, "node_modules/json-bigint": { @@ -4424,6 +6873,15 @@ "graceful-fs": "^4.1.11" } }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/kuler": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", @@ -4441,6 +6899,15 @@ "node": ">=8" } }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -4468,21 +6935,6 @@ "uc.micro": "^1.0.1" } }, - "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", @@ -4518,6 +6970,12 @@ "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -4535,22 +6993,6 @@ "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", "dev": true }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/logform": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/logform/-/logform-2.3.0.tgz", @@ -4615,6 +7057,15 @@ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, "node_modules/markdown-it": { "version": "11.0.1", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-11.0.1.tgz", @@ -4666,6 +7117,12 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -4726,6 +7183,15 @@ "node": ">= 0.6" } }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/mimic-response": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", @@ -5183,125 +7649,6 @@ "mkdirp": "bin/cmd.js" } }, - "node_modules/mocha": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.1.3.tgz", - "integrity": "sha512-Xcpl9FqXOAYqI3j79pEtHBBnQgVXIhpULjGQa7DVb0Po+VzmSIK9kanAiWLHoRR/dbZ2qpdPshuXr8l1VaHCzw==", - "dev": true, - "dependencies": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.2", - "debug": "4.3.2", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.1.7", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "3.0.4", - "ms": "2.1.3", - "nanoid": "3.1.25", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "which": "2.0.2", - "workerpool": "6.1.5", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, - "node_modules/mocha/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/mocha/node_modules/debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/mocha/node_modules/debug/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/mocha/node_modules/glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/mocha/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/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/mongodb": { "version": "3.7.3", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.3.tgz", @@ -5466,18 +7813,6 @@ "thenify-all": "^1.0.0" } }, - "node_modules/nanoid": { - "version": "3.1.25", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz", - "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==", - "dev": true, - "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", @@ -5529,6 +7864,18 @@ "node": ">= 6.0.0" } }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", + "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==", + "dev": true + }, "node_modules/nodemailer": { "version": "6.7.2", "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.2.tgz", @@ -5627,6 +7974,18 @@ "node": ">=8" } }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/npmlog": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", @@ -5649,6 +8008,12 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, + "node_modules/nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -5701,6 +8066,21 @@ "fn.name": "1.x.x" } }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optional-require": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz", @@ -5749,21 +8129,6 @@ "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/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -5917,15 +8282,6 @@ "node": ">=8" } }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/pause": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", @@ -5982,38 +8338,117 @@ "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==" }, - "node_modules/pg-types": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", - "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.4.tgz", + "integrity": "sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, "dependencies": { - "pg-int8": "1.0.1", - "postgres-array": "~2.0.0", - "postgres-bytea": "~1.0.0", - "postgres-date": "~1.0.4", - "postgres-interval": "^1.1.0" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/pgpass": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", - "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, "dependencies": { - "split2": "^4.1.0" + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/picomatch": { + "node_modules/pkg-dir/node_modules/p-limit": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, "engines": { - "node": ">=8.6" + "node": ">=6" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" } }, "node_modules/pngjs": { @@ -6101,6 +8536,33 @@ "node": ">=6.0.0" } }, + "node_modules/pretty-format": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.2.tgz", + "integrity": "sha512-p0wNtJ9oLuvgOQDEIZ9zQjZffK7KtyR6Si0jnXULIDwrlNF8Cuir3AZP0hHv0jmKuNN/edOnbMjnzd4uTcmWiw==", + "dev": true, + "dependencies": { + "@jest/types": "^27.4.2", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -6115,6 +8577,19 @@ "node": ">=0.4.0" } }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", @@ -6137,6 +8612,12 @@ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, + "node_modules/psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, "node_modules/pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", @@ -6360,15 +8841,6 @@ } ] }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -6426,6 +8898,12 @@ "node": ">=0.10.0" } }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, "node_modules/readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -6551,6 +9029,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -6560,6 +9059,15 @@ "node": ">=4" } }, + "node_modules/resolve.exports": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", + "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/responselike": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", @@ -6703,6 +9211,18 @@ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", @@ -6793,15 +9313,6 @@ "node": ">=4" } }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, "node_modules/serve-static": { "version": "1.14.2", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", @@ -6896,6 +9407,12 @@ "is-arrayish": "^0.3.1" } }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -6988,6 +9505,27 @@ "node": "*" } }, + "node_modules/stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -7025,6 +9563,19 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -7057,6 +9608,15 @@ "node": ">=4" } }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -7074,67 +9634,88 @@ "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=" }, - "node_modules/superagent": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", - "integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==", + "node_modules/supertest": { + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.1.6.tgz", + "integrity": "sha512-0hACYGNJ8OHRg8CRITeZOdbjur7NLuNs0mBjVhdpxi7hP6t3QIbOzLON5RTUmZcy2I9riuII3+Pr2C7yztrIIg==", "dev": true, "dependencies": { - "component-emitter": "^1.2.0", - "cookiejar": "^2.1.0", - "debug": "^3.1.0", - "extend": "^3.0.0", - "form-data": "^2.3.1", - "formidable": "^1.2.0", - "methods": "^1.1.1", - "mime": "^1.4.1", - "qs": "^6.5.1", - "readable-stream": "^2.3.5" + "methods": "^1.1.2", + "superagent": "^6.1.0" }, "engines": { - "node": ">= 4.0" + "node": ">=6.0.0" } }, - "node_modules/superagent/node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "node_modules/supertest/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", "dev": true, - "bin": { - "mime": "cli.js" + "dependencies": { + "ms": "2.1.2" }, "engines": { - "node": ">=4" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/superagent/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==", + "node_modules/supertest/node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", "dev": true, "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" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" } }, - "node_modules/superagent/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/supertest/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/supertest/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/superagent/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==", + "node_modules/supertest/node_modules/superagent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-6.1.0.tgz", + "integrity": "sha512-OUDHEssirmplo3F+1HWKUrUjvnQuA+nZI6i/JJBdXb5eq9IyEQwPyPpqND+SSsxf6TygpBEkUjISVRN4/VOpeg==", "dev": true, "dependencies": { - "safe-buffer": "~5.1.0" + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.2", + "debug": "^4.1.1", + "fast-safe-stringify": "^2.0.7", + "form-data": "^3.0.0", + "formidable": "^1.2.2", + "methods": "^1.1.2", + "mime": "^2.4.6", + "qs": "^6.9.4", + "readable-stream": "^3.6.0", + "semver": "^7.3.2" + }, + "engines": { + "node": ">= 7.0.0" } }, "node_modules/supports-color": { @@ -7148,6 +9729,25 @@ "node": ">=8" } }, + "node_modules/supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, "node_modules/table": { "version": "6.7.5", "resolved": "https://registry.npmjs.org/table/-/table-6.7.5.tgz", @@ -7228,6 +9828,36 @@ "node": ">=10" } }, + "node_modules/terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", @@ -7255,7 +9885,28 @@ "thenify": ">= 3.1.0 < 4" }, "engines": { - "node": ">=0.8" + "node": ">=0.8" + } + }, + "node_modules/throat": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", + "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", + "dev": true + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true, + "engines": { + "node": ">=4" } }, "node_modules/to-readable-stream": { @@ -7313,6 +9964,29 @@ "node": "*" } }, + "node_modules/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "dev": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -7331,6 +10005,65 @@ "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" }, + "node_modules/ts-jest": { + "version": "27.1.2", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.2.tgz", + "integrity": "sha512-eSOiJOWq6Hhs6Khzk5wKC5sgWIXgXqOCiIl1+3lfnearu58Hj4QpE5tUhQcA3xtZrELbcvAGCsd6HB8OsaVaTA==", + "dev": true, + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^27.0.0", + "json5": "2.x", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "20.x" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@types/jest": "^27.0.0", + "babel-jest": ">=27.0.0 <28", + "esbuild": "~0.14.0", + "jest": "^27.0.0", + "typescript": ">=3.8 <5.0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@types/jest": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/ts-node": { "version": "9.1.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", @@ -7651,6 +10384,46 @@ } } }, + "node_modules/typeorm-extension": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/typeorm-extension/-/typeorm-extension-1.1.0.tgz", + "integrity": "sha512-UNDZPZhX4vL7SAJK+EIMHB3uiNWMomaKUYVAdhSGUDSLliqrxQ/V7/ZMar6YDJjdpWSdphDzFrroxaIDwkF5nw==", + "dependencies": { + "@trapi/query": "^2.0.3", + "glob": "^7.1.7", + "reflect-metadata": "^0.1.13", + "typeorm": "^0.2.41", + "yargs": "^17.3.1" + }, + "bin": { + "typeorm-extension": "dist/cli/index.js" + } + }, + "node_modules/typeorm-extension/node_modules/yargs": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz", + "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/typeorm-extension/node_modules/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==", + "engines": { + "node": ">=12" + } + }, "node_modules/typeorm/node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -7876,6 +10649,29 @@ "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, + "node_modules/v8-to-istanbul": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz", + "integrity": "sha512-/PRhfd8aTNp9Ggr62HPzXg2XasNFGy5PBt0Rp04du7/8GNNSgxFL6WBTkgMKSL9bFjH+8kKEG3f37FmxiTqUUA==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/v8-to-istanbul/node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/valid-data-url": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/valid-data-url/-/valid-data-url-3.0.1.tgz", @@ -7900,6 +10696,36 @@ "node": ">= 0.8" } }, + "node_modules/w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "dev": true, + "dependencies": { + "browser-process-hrtime": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dev": true, + "dependencies": { + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, "node_modules/web-resource-inliner": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/web-resource-inliner/-/web-resource-inliner-5.0.0.tgz", @@ -7968,6 +10794,33 @@ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" }, + "node_modules/whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "dependencies": { + "iconv-lite": "0.4.24" + } + }, + "node_modules/whatwg-encoding/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==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", @@ -8063,12 +10916,6 @@ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" }, - "node_modules/workerpool": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.5.tgz", - "integrity": "sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw==", - "dev": true - }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -8101,6 +10948,27 @@ "typedarray-to-buffer": "^3.1.5" } }, + "node_modules/ws": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", + "integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/xdg-basedir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", @@ -8109,6 +10977,12 @@ "node": ">=8" } }, + "node_modules/xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, "node_modules/xml2js": { "version": "0.4.23", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", @@ -8129,6 +11003,12 @@ "node": ">=4.0" } }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -8175,21 +11055,6 @@ "node": ">=10" } }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", @@ -8231,7 +11096,209 @@ "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", "dev": true, "requires": { - "@babel/highlight": "^7.10.4" + "@babel/highlight": "^7.10.4" + } + }, + "@babel/compat-data": { + "version": "7.16.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.4.tgz", + "integrity": "sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q==", + "dev": true + }, + "@babel/core": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.7.tgz", + "integrity": "sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.16.7", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helpers": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0", + "source-map": "^0.5.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.16.7" + } + }, + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "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 + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.7.tgz", + "integrity": "sha512-/ST3Sg8MLGY5HVYmrjOgL60ENux/HfO/CsUh7y4MalThufhE/Ff/6EibFDHi4jiDCaWfJKoqbE6oTh21c5hrRg==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-compilation-targets": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", + "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.16.4", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.17.5", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/helper-environment-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", + "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-function-name": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", + "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", + "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-module-imports": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-module-transforms": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz", + "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", + "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", + "dev": true + }, + "@babel/helper-simple-access": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", + "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" } }, "@babel/helper-validator-identifier": { @@ -8240,6 +11307,23 @@ "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", "dev": true }, + "@babel/helper-validator-option": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", + "dev": true + }, + "@babel/helpers": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.7.tgz", + "integrity": "sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw==", + "dev": true, + "requires": { + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, "@babel/highlight": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz", @@ -8309,6 +11393,129 @@ } } }, + "@babel/parser": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.7.tgz", + "integrity": "sha512-sR4eaSrnM7BV7QPzGfEX5paG/6wrZM3I0HDzfIAK06ESvo9oy3xBuVBxE3MbQaKNhvg8g/ixjMWo2CGpzpHsDA==", + "dev": true + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", + "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7" + } + }, "@babel/runtime": { "version": "7.16.5", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz", @@ -8317,6 +11524,94 @@ "regenerator-runtime": "^0.13.4" } }, + "@babel/template": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.16.7" + } + } + } + }, + "@babel/traverse": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.7.tgz", + "integrity": "sha512-8KWJPIb8c2VvY8AJrydh6+fVRo2ODx1wYBU2398xJVq0JomuLBZmVQzLPBblJgHIGYG4znCpUZUZ0Pt2vdmVYQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.16.7" + } + }, + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.7.tgz", + "integrity": "sha512-E8HuV7FO9qLpx6OtoGfUQ2cjIYnbFwvZWYBS+87EwtdMvmUPJSwykpovFB+8insbpF0uJcpr8KMUi64XZntZcg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + } + }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, "@dabh/diagnostics": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", @@ -8470,6 +11765,267 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true + }, + "@jest/console": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.4.2.tgz", + "integrity": "sha512-xknHThRsPB/To1FUbi6pCe43y58qFC03zfb6R7fDb/FfC7k2R3i1l+izRBJf8DI46KhYGRaF14Eo9A3qbBoixg==", + "dev": true, + "requires": { + "@jest/types": "^27.4.2", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^27.4.2", + "jest-util": "^27.4.2", + "slash": "^3.0.0" + } + }, + "@jest/core": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.4.5.tgz", + "integrity": "sha512-3tm/Pevmi8bDsgvo73nX8p/WPng6KWlCyScW10FPEoN1HU4pwI83tJ3TsFvi1FfzsjwUlMNEPowgb/rPau/LTQ==", + "dev": true, + "requires": { + "@jest/console": "^27.4.2", + "@jest/reporters": "^27.4.5", + "@jest/test-result": "^27.4.2", + "@jest/transform": "^27.4.5", + "@jest/types": "^27.4.2", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-changed-files": "^27.4.2", + "jest-config": "^27.4.5", + "jest-haste-map": "^27.4.5", + "jest-message-util": "^27.4.2", + "jest-regex-util": "^27.4.0", + "jest-resolve": "^27.4.5", + "jest-resolve-dependencies": "^27.4.5", + "jest-runner": "^27.4.5", + "jest-runtime": "^27.4.5", + "jest-snapshot": "^27.4.5", + "jest-util": "^27.4.2", + "jest-validate": "^27.4.2", + "jest-watcher": "^27.4.2", + "micromatch": "^4.0.4", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "@jest/environment": { + "version": "27.4.4", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.4.4.tgz", + "integrity": "sha512-q+niMx7cJgt/t/b6dzLOh4W8Ef/8VyKG7hxASK39jakijJzbFBGpptx3RXz13FFV7OishQ9lTbv+dQ5K3EhfDQ==", + "dev": true, + "requires": { + "@jest/fake-timers": "^27.4.2", + "@jest/types": "^27.4.2", + "@types/node": "*", + "jest-mock": "^27.4.2" + } + }, + "@jest/fake-timers": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.4.2.tgz", + "integrity": "sha512-f/Xpzn5YQk5adtqBgvw1V6bF8Nx3hY0OIRRpCvWcfPl0EAjdqWPdhH3t/3XpiWZqtjIEHDyMKP9ajpva1l4Zmg==", + "dev": true, + "requires": { + "@jest/types": "^27.4.2", + "@sinonjs/fake-timers": "^8.0.1", + "@types/node": "*", + "jest-message-util": "^27.4.2", + "jest-mock": "^27.4.2", + "jest-util": "^27.4.2" + } + }, + "@jest/globals": { + "version": "27.4.4", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.4.4.tgz", + "integrity": "sha512-bqpqQhW30BOreXM8bA8t8JbOQzsq/WnPTnBl+It3UxAD9J8yxEAaBEylHx1dtBapAr/UBk8GidXbzmqnee8tYQ==", + "dev": true, + "requires": { + "@jest/environment": "^27.4.4", + "@jest/types": "^27.4.2", + "expect": "^27.4.2" + } + }, + "@jest/reporters": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.4.5.tgz", + "integrity": "sha512-3orsG4vi8zXuBqEoy2LbnC1kuvkg1KQUgqNxmxpQgIOQEPeV0onvZu+qDQnEoX8qTQErtqn/xzcnbpeTuOLSiA==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^27.4.2", + "@jest/test-result": "^27.4.2", + "@jest/transform": "^27.4.5", + "@jest/types": "^27.4.2", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.4", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^4.0.3", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "jest-haste-map": "^27.4.5", + "jest-resolve": "^27.4.5", + "jest-util": "^27.4.2", + "jest-worker": "^27.4.5", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^8.1.0" + } + }, + "@jest/source-map": { + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.4.0.tgz", + "integrity": "sha512-Ntjx9jzP26Bvhbm93z/AKcPRj/9wrkI88/gK60glXDx1q+IeI0rf7Lw2c89Ch6ofonB0On/iRDreQuQ6te9pgQ==", + "dev": true, + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.4", + "source-map": "^0.6.0" + } + }, + "@jest/test-result": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.4.2.tgz", + "integrity": "sha512-kr+bCrra9jfTgxHXHa2UwoQjxvQk3Am6QbpAiJ5x/50LW8llOYrxILkqY0lZRW/hu8FXesnudbql263+EW9iNA==", + "dev": true, + "requires": { + "@jest/console": "^27.4.2", + "@jest/types": "^27.4.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@jest/test-sequencer": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.4.5.tgz", + "integrity": "sha512-n5woIn/1v+FT+9hniymHPARA9upYUmfi5Pw9ewVwXCDlK4F5/Gkees9v8vdjGdAIJ2MPHLHodiajLpZZanWzEQ==", + "dev": true, + "requires": { + "@jest/test-result": "^27.4.2", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.4.5", + "jest-runtime": "^27.4.5" + } + }, + "@jest/transform": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.4.5.tgz", + "integrity": "sha512-PuMet2UlZtlGzwc6L+aZmR3I7CEBpqadO03pU40l2RNY2fFJ191b9/ITB44LNOhVtsyykx0OZvj0PCyuLm7Eew==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.4.2", + "babel-plugin-istanbul": "^6.0.0", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.4.5", + "jest-regex-util": "^27.4.0", + "jest-util": "^27.4.2", + "micromatch": "^4.0.4", + "pirates": "^4.0.1", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + } + }, + "@jest/types": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", + "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, "@mapbox/node-pre-gyp": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.8.tgz", @@ -8518,24 +12074,88 @@ "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", "dev": true }, + "@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, "@sqltools/formatter": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.3.tgz", "integrity": "sha512-O3uyB/JbkAEMZaP3YqyHH7TMnex7tWyCbCI4EfJdOCoN6HIhqdJBWTM6aCCiWQ/5f5wxjgU735QAIpJbjDvmzg==" }, - "@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==" + }, + "@trapi/query": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@trapi/query/-/query-2.0.3.tgz", + "integrity": "sha512-4N7pQyCPQfkd/LyKhowNVdgQMkhTdxPO9Yb4qrl0AGlPL3Duhu8vexZaQeBRSiPxQ/3giHM1OYRYHDk6hGtLGg==" + }, + "@types/babel__core": { + "version": "7.1.18", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.18.tgz", + "integrity": "sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", "dev": true, "requires": { - "defer-to-connect": "^1.0.1" + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" } }, - "@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==" + "@types/babel__traverse": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", + "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } }, "@types/bcrypt": { "version": "5.0.0", @@ -8570,12 +12190,6 @@ "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==", "dev": true }, - "@types/chai": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.0.tgz", - "integrity": "sha512-/ceqdqeRraGolFTcfoXNiqjyQhZzbINDngeoAq9GoHa8PPK1yNzTaxWjA6BFWp5Ua9JpXEMSS4s5i9tS0hOJtw==", - "dev": true - }, "@types/connect": { "version": "3.4.35", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", @@ -8658,6 +12272,49 @@ "@types/request": "*" } }, + "@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/jest": { + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.4.0.tgz", + "integrity": "sha512-gHl8XuC1RZ8H2j5sHv/JqsaxXkDDM9iDOgu0Wp8sjs4u/snb2PVehyWXJPr+ORA0RPpgw231mnutWI1+0hgjIQ==", + "dev": true, + "requires": { + "jest-diff": "^27.0.0", + "pretty-format": "^27.0.0" + } + }, "@types/json-schema": { "version": "7.0.9", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", @@ -8768,6 +12425,12 @@ "@types/passport": "*" } }, + "@types/prettier": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.2.tgz", + "integrity": "sha512-ekoj4qOQYp7CvjX8ZDBgN86w3MqQhLE1hczEJbEIjgFEumDy+na/4AJAbLXfgEWFNB2pKadM5rPFtuSGMWK7xA==", + "dev": true + }, "@types/qrcode": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.4.2.tgz", @@ -8811,6 +12474,12 @@ "@types/node": "*" } }, + "@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, "@types/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", @@ -8831,6 +12500,15 @@ "@types/node": "*" } }, + "@types/supertest": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-2.0.11.tgz", + "integrity": "sha512-uci4Esokrw9qGb9bvhhSVEjd6rkny/dk5PK/Qz4yxKiyppEI+dOPlNrZBahE3i+PoKFYyDxChVXZ/ysS/nrm1Q==", + "dev": true, + "requires": { + "@types/superagent": "*" + } + }, "@types/tough-cookie": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.1.tgz", @@ -8843,19 +12521,35 @@ "integrity": "sha512-I6OUIZ5cYRk5lp14xSOAiXjWrfVoMZVjDuevBYgQDYzZIjsf2CAISpEcXOkFAtpAHbmWIDLcZObejqny/9xq5Q==", "dev": true }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "20.2.1", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", + "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", + "dev": true + }, "@types/zen-observable": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.3.tgz", "integrity": "sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw==" }, "@typescript-eslint/eslint-plugin": { - "version": "5.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.8.1.tgz", - "integrity": "sha512-wTZ5oEKrKj/8/366qTM366zqhIKAp6NCMweoRONtfuC07OAU9nVI2GZZdqQ1qD30WAAtcPdkH+npDwtRFdp4Rw==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.10.0.tgz", + "integrity": "sha512-XXVKnMsq2fuu9K2KsIxPUGqb6xAImz8MEChClbXmE3VbveFtBUU5bzM6IPVWqzyADIgdkS2Ws/6Xo7W2TeZWjQ==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "5.8.1", - "@typescript-eslint/scope-manager": "5.8.1", + "@typescript-eslint/scope-manager": "5.10.0", + "@typescript-eslint/type-utils": "5.10.0", + "@typescript-eslint/utils": "5.10.0", "debug": "^4.3.2", "functional-red-black-tree": "^1.0.1", "ignore": "^5.1.8", @@ -8864,16 +12558,27 @@ "tsutils": "^3.21.0" }, "dependencies": { - "@typescript-eslint/experimental-utils": { - "version": "5.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.8.1.tgz", - "integrity": "sha512-fbodVnjIDU4JpeXWRDsG5IfIjYBxEvs8EBO8W1+YVdtrc2B9ppfof5sZhVEDOtgTfFHnYQJDI8+qdqLYO4ceww==", + "@typescript-eslint/type-utils": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.10.0.tgz", + "integrity": "sha512-TzlyTmufJO5V886N+hTJBGIfnjQDQ32rJYxPaeiyWKdjsv2Ld5l8cbS7pxim4DeNs62fKzRSt8Q14Evs4JnZyQ==", + "dev": true, + "requires": { + "@typescript-eslint/utils": "5.10.0", + "debug": "^4.3.2", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/utils": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.10.0.tgz", + "integrity": "sha512-IGYwlt1CVcFoE2ueW4/ioEwybR60RAdGeiJX/iDAw0t5w0wK3S7QncDwpmsM70nKgGTuVchEWB8lwZwHqPAWRg==", "dev": true, "requires": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.8.1", - "@typescript-eslint/types": "5.8.1", - "@typescript-eslint/typescript-estree": "5.8.1", + "@typescript-eslint/scope-manager": "5.10.0", + "@typescript-eslint/types": "5.10.0", + "@typescript-eslint/typescript-estree": "5.10.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0" }, @@ -8913,14 +12618,14 @@ } }, "@typescript-eslint/parser": { - "version": "5.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.8.1.tgz", - "integrity": "sha512-K1giKHAjHuyB421SoXMXFHHVI4NdNY603uKw92++D3qyxSeYvC10CBJ/GE5Thpo4WTUvu1mmJI2/FFkz38F2Gw==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.10.0.tgz", + "integrity": "sha512-pJB2CCeHWtwOAeIxv8CHVGJhI5FNyJAIpx5Pt72YkK3QfEzt6qAlXZuyaBmyfOdM62qU0rbxJzNToPTVeJGrQw==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.8.1", - "@typescript-eslint/types": "5.8.1", - "@typescript-eslint/typescript-estree": "5.8.1", + "@typescript-eslint/scope-manager": "5.10.0", + "@typescript-eslint/types": "5.10.0", + "@typescript-eslint/typescript-estree": "5.10.0", "debug": "^4.3.2" }, "dependencies": { @@ -8942,29 +12647,29 @@ } }, "@typescript-eslint/scope-manager": { - "version": "5.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.8.1.tgz", - "integrity": "sha512-DGxJkNyYruFH3NIZc3PwrzwOQAg7vvgsHsHCILOLvUpupgkwDZdNq/cXU3BjF4LNrCsVg0qxEyWasys5AiJ85Q==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.10.0.tgz", + "integrity": "sha512-tgNgUgb4MhqK6DoKn3RBhyZ9aJga7EQrw+2/OiDk5hKf3pTVZWyqBi7ukP+Z0iEEDMF5FDa64LqODzlfE4O/Dg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.8.1", - "@typescript-eslint/visitor-keys": "5.8.1" + "@typescript-eslint/types": "5.10.0", + "@typescript-eslint/visitor-keys": "5.10.0" } }, "@typescript-eslint/types": { - "version": "5.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.8.1.tgz", - "integrity": "sha512-L/FlWCCgnjKOLefdok90/pqInkomLnAcF9UAzNr+DSqMC3IffzumHTQTrINXhP1gVp9zlHiYYjvozVZDPleLcA==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.10.0.tgz", + "integrity": "sha512-wUljCgkqHsMZbw60IbOqT/puLfyqqD5PquGiBo1u1IS3PLxdi3RDGlyf032IJyh+eQoGhz9kzhtZa+VC4eWTlQ==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.8.1.tgz", - "integrity": "sha512-26lQ8l8tTbG7ri7xEcCFT9ijU5Fk+sx/KRRyyzCv7MQ+rZZlqiDPtMKWLC8P7o+dtCnby4c+OlxuX1tp8WfafQ==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.10.0.tgz", + "integrity": "sha512-x+7e5IqfwLwsxTdliHRtlIYkgdtYXzE0CkFeV6ytAqq431ZyxCFzNMNR5sr3WOlIG/ihVZr9K/y71VHTF/DUQA==", "dev": true, "requires": { - "@typescript-eslint/types": "5.8.1", - "@typescript-eslint/visitor-keys": "5.8.1", + "@typescript-eslint/types": "5.10.0", + "@typescript-eslint/visitor-keys": "5.10.0", "debug": "^4.3.2", "globby": "^11.0.4", "is-glob": "^4.0.3", @@ -8990,27 +12695,27 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "5.8.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.8.1.tgz", - "integrity": "sha512-SWgiWIwocK6NralrJarPZlWdr0hZnj5GXHIgfdm8hNkyKvpeQuFyLP6YjSIe9kf3YBIfU6OHSZLYkQ+smZwtNg==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.10.0.tgz", + "integrity": "sha512-GMxj0K1uyrFLPKASLmZzCuSddmjZVbVj3Ouy5QVuIGKZopxvOr24JsS7gruz6C3GExE01mublZ3mIBOaon9zuQ==", "dev": true, "requires": { - "@typescript-eslint/types": "5.8.1", + "@typescript-eslint/types": "5.10.0", "eslint-visitor-keys": "^3.0.0" }, "dependencies": { "eslint-visitor-keys": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz", - "integrity": "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz", + "integrity": "sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ==", "dev": true } } }, - "@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "abab": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", "dev": true }, "abbrev": { @@ -9041,6 +12746,16 @@ "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true }, + "acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, "acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -9048,6 +12763,12 @@ "dev": true, "requires": {} }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true + }, "agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -9097,6 +12818,23 @@ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==" }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + } + } + }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -9208,12 +12946,6 @@ "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" }, - "assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true - }, "astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -9245,6 +12977,98 @@ "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true }, + "babel-jest": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.4.5.tgz", + "integrity": "sha512-3uuUTjXbgtODmSv/DXO9nZfD52IyC2OYTFaXGRzL0kpykzroaquCrD5+lZNafTvZlnNqZHt5pb0M08qVBZnsnA==", + "dev": true, + "requires": { + "@jest/transform": "^27.4.5", + "@jest/types": "^27.4.2", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.0.0", + "babel-preset-jest": "^27.4.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "slash": "^3.0.0" + } + }, + "babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "dependencies": { + "istanbul-lib-instrument": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", + "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", + "dev": true, + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "babel-plugin-jest-hoist": { + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.4.0.tgz", + "integrity": "sha512-Jcu7qS4OX5kTWBc45Hz7BMmgXuJqRnhatqpUhnzGC3OBYpOmf2tv6jFNwZpwM7wU7MUuv2r9IPS/ZlYOuburVw==", + "dev": true, + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "requires": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + } + }, + "babel-preset-jest": { + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.4.0.tgz", + "integrity": "sha512-NK4jGYpnBvNxcGo7/ZpZJr51jCGT+3bwwpVIDY2oNfTxJJldRtB4VAcYdgp1loDE50ODuTu+yBjpMAswv5tlpg==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "^27.4.0", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -9405,12 +13229,43 @@ "fill-range": "^7.0.1" } }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", "dev": true }, + "browserslist": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", + "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001286", + "electron-to-chromium": "^1.4.17", + "escalade": "^3.1.1", + "node-releases": "^2.0.1", + "picocolors": "^1.0.0" + } + }, + "bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "requires": { + "fast-json-stable-stringify": "2.x" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "requires": { + "node-int64": "^0.4.0" + } + }, "bson": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", @@ -9540,46 +13395,11 @@ "integrity": "sha512-tVI4q5jjFV5CavAU8DXfza/TJcZutVKo/5Foskmsqcm0MsL91moHvwiGNnqaa2o6PF/7yT5ikDRcVcl8Rj6LCA==", "dev": true }, - "chai": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.4.tgz", - "integrity": "sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==", - "dev": true, - "requires": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^3.0.1", - "get-func-name": "^2.0.0", - "pathval": "^1.1.1", - "type-detect": "^4.0.5" - } - }, - "chai-http": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/chai-http/-/chai-http-4.3.0.tgz", - "integrity": "sha512-zFTxlN7HLMv+7+SPXZdkd5wUlK+KxH6Q7bIEMiEx0FK3zuuMqL7cwICAQ0V1+yYRozBburYuxN1qZstgHpFZQg==", - "dev": true, - "requires": { - "@types/chai": "4", - "@types/superagent": "^3.8.3", - "cookiejar": "^2.1.1", - "is-ip": "^2.0.0", - "methods": "^1.1.2", - "qs": "^6.5.1", - "superagent": "^3.7.0" - }, - "dependencies": { - "@types/superagent": { - "version": "3.8.7", - "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-3.8.7.tgz", - "integrity": "sha512-9KhCkyXv268A2nZ1Wvu7rQWM+BmdYUVkycFeNnYrUL5Zwu7o8wPQ3wBfW59dDP+wuoxw0ww8YKgTNv8j/cgscA==", - "dev": true, - "requires": { - "@types/cookiejar": "*", - "@types/node": "*" - } - } - } + "caniuse-lite": { + "version": "1.0.30001295", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001295.tgz", + "integrity": "sha512-lSP16vcyC0FEy0R4ECc9duSPoKoZy+YkpGkue9G4D81OfPnliopaZrU10+qtPdT8PbGXad/PNx43TIQrOmJZSQ==", + "dev": true }, "chalk": { "version": "4.1.2", @@ -9590,10 +13410,10 @@ "supports-color": "^7.1.0" } }, - "check-error": { + "char-regex": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true }, "cheerio": { @@ -9648,6 +13468,12 @@ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "dev": true }, + "cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true + }, "class-transformer": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", @@ -9715,6 +13541,18 @@ "mimic-response": "^1.0.0" } }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, "color": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", @@ -9893,6 +13731,23 @@ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.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==", + "dev": true + } + } + }, "cookie": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", @@ -9990,6 +13845,68 @@ "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==" }, + "cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "requires": { + "cssom": "~0.3.6" + }, + "dependencies": { + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + } + } + }, + "data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "requires": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + }, + "dependencies": { + "tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "requires": { + "punycode": "^2.1.1" + } + }, + "webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true + }, + "whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dev": true, + "requires": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + } + } + } + }, "date-and-time": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-2.0.1.tgz", @@ -10003,10 +13920,10 @@ "ms": "^2.1.1" } }, - "decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "decimal.js": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", "dev": true }, "decompress-response": { @@ -10018,14 +13935,11 @@ "mimic-response": "^1.0.0" } }, - "deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", - "dev": true, - "requires": { - "type-detect": "^4.0.0" - } + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true }, "deep-extend": { "version": "0.6.0", @@ -10039,6 +13953,12 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true + }, "defer-to-connect": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", @@ -10076,6 +13996,12 @@ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true + }, "detect-node": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", @@ -10113,10 +14039,10 @@ } } }, - "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "diff-sequences": { + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.4.0.tgz", + "integrity": "sha512-YqiQzkrsmHMH5uuh8OdQFU9/ZpADnwzml8z0O5HvRNda+5UZsaX/xN+AAxfR2hWq1Y7HZnAzO9J5lJXOuDz2Ww==", "dev": true }, "dijkstrajs": { @@ -10157,6 +14083,23 @@ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==" }, + "domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dev": true, + "requires": { + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true + } + } + }, "domhandler": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", @@ -10258,6 +14201,18 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "electron-to-chromium": { + "version": "1.4.31", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.31.tgz", + "integrity": "sha512-t3XVQtk+Frkv6aTD4RRk0OqosU+VLe1dQFW83MDer78ZD6a52frgXuYOIsLYTQiH2Lm+JB2OKYcn7zrX+YGAiQ==", + "dev": true + }, + "emittery": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "dev": true + }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -10327,6 +14282,66 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, + "escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "dev": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + } + } + }, "eslint": { "version": "7.31.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.31.0.tgz", @@ -10522,6 +14537,51 @@ "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "expect": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.4.2.tgz", + "integrity": "sha512-BjAXIDC6ZOW+WBFNg96J22D27Nq5ohn+oGcuP2rtOtcjuxNoV9McpQ60PcQWhdFOSBIQdR72e+4HdnbZTFSTyg==", + "dev": true, + "requires": { + "@jest/types": "^27.4.2", + "ansi-styles": "^5.0.0", + "jest-get-type": "^27.4.0", + "jest-matcher-utils": "^27.4.2", + "jest-message-util": "^27.4.2", + "jest-regex-util": "^27.4.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, "express": { "version": "4.17.2", "resolved": "https://registry.npmjs.org/express/-/express-4.17.2.tgz", @@ -10662,9 +14722,9 @@ "dev": true }, "fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -10686,6 +14746,12 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true + }, "fast-text-encoding": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", @@ -10700,6 +14766,15 @@ "reusify": "^1.0.4" } }, + "fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "dev": true, + "requires": { + "bser": "2.1.1" + } + }, "fecha": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz", @@ -10751,22 +14826,6 @@ } } }, - "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": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true - }, "flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -10909,17 +14968,17 @@ "stream-events": "^1.0.4" } }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, - "get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", - "dev": true - }, "get-intrinsic": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", @@ -10931,6 +14990,12 @@ "has-symbols": "^1.0.1" } }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true + }, "get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -10984,16 +15049,16 @@ } }, "globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "requires": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", "slash": "^3.0.0" }, "dependencies": { @@ -11064,12 +15129,6 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true - }, "gtoken": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.3.1.tgz", @@ -11137,6 +15196,21 @@ "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==" }, + "html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.5" + } + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, "html-minifier": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-4.0.0.tgz", @@ -11236,6 +15310,12 @@ } } }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, "iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -11278,6 +15358,16 @@ "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", "dev": true }, + "import-local": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz", + "integrity": "sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -11302,12 +15392,6 @@ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, - "ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", - "dev": true - }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -11353,6 +15437,12 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true + }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -11371,15 +15461,6 @@ "is-path-inside": "^3.0.2" } }, - "is-ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ip/-/is-ip-2.0.0.tgz", - "integrity": "sha1-aO6gfooKCpTC0IDdZ0xzGrKkYas=", - "dev": true, - "requires": { - "ip-regex": "^2.0.0" - } - }, "is-npm": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", @@ -11402,10 +15483,10 @@ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true }, - "is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true }, "is-stream": { @@ -11413,33 +15494,614 @@ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, + "requires": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "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 + } + } + }, + "istanbul-reports": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.3.tgz", + "integrity": "sha512-x9LtDVtfm/t1GFiLl3NffC7hz+I1ragvgX1P/Lg1NlIagifZDKUkuuaAxH/qpwj2IuEfD8G2Bs/UKp+sZ/pKkg==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "jest": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.4.5.tgz", + "integrity": "sha512-uT5MiVN3Jppt314kidCk47MYIRilJjA/l2mxwiuzzxGUeJIvA8/pDaJOAX5KWvjAo7SCydcW0/4WEtgbLMiJkg==", + "dev": true, + "requires": { + "@jest/core": "^27.4.5", + "import-local": "^3.0.2", + "jest-cli": "^27.4.5" + } + }, + "jest-changed-files": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.4.2.tgz", + "integrity": "sha512-/9x8MjekuzUQoPjDHbBiXbNEBauhrPU2ct7m8TfCg69ywt1y/N+yYwGh3gCpnqUS3klYWDU/lSNgv+JhoD2k1A==", + "dev": true, + "requires": { + "@jest/types": "^27.4.2", + "execa": "^5.0.0", + "throat": "^6.0.1" + } + }, + "jest-circus": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.4.5.tgz", + "integrity": "sha512-eTNWa9wsvBwPykhMMShheafbwyakcdHZaEYh5iRrQ0PFJxkDP/e3U/FvzGuKWu2WpwUA3C3hPlfpuzvOdTVqnw==", + "dev": true, + "requires": { + "@jest/environment": "^27.4.4", + "@jest/test-result": "^27.4.2", + "@jest/types": "^27.4.2", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.4.2", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.4.2", + "jest-matcher-utils": "^27.4.2", + "jest-message-util": "^27.4.2", + "jest-runtime": "^27.4.5", + "jest-snapshot": "^27.4.5", + "jest-util": "^27.4.2", + "pretty-format": "^27.4.2", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" + } + }, + "jest-cli": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.4.5.tgz", + "integrity": "sha512-hrky3DSgE0u7sQxaCL7bdebEPHx5QzYmrGuUjaPLmPE8jx5adtvGuOlRspvMoVLTTDOHRnZDoRLYJuA+VCI7Hg==", + "dev": true, + "requires": { + "@jest/core": "^27.4.5", + "@jest/test-result": "^27.4.2", + "@jest/types": "^27.4.2", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "import-local": "^3.0.2", + "jest-config": "^27.4.5", + "jest-util": "^27.4.2", + "jest-validate": "^27.4.2", + "prompts": "^2.0.1", + "yargs": "^16.2.0" + } + }, + "jest-config": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.4.5.tgz", + "integrity": "sha512-t+STVJtPt+fpqQ8GBw850NtSQbnDOw/UzdPfzDaHQ48/AylQlW7LHj3dH+ndxhC1UxJ0Q3qkq7IH+nM1skwTwA==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^27.4.5", + "@jest/types": "^27.4.2", + "babel-jest": "^27.4.5", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.4", + "jest-circus": "^27.4.5", + "jest-environment-jsdom": "^27.4.4", + "jest-environment-node": "^27.4.4", + "jest-get-type": "^27.4.0", + "jest-jasmine2": "^27.4.5", + "jest-regex-util": "^27.4.0", + "jest-resolve": "^27.4.5", + "jest-runner": "^27.4.5", + "jest-util": "^27.4.2", + "jest-validate": "^27.4.2", + "micromatch": "^4.0.4", + "pretty-format": "^27.4.2", + "slash": "^3.0.0" + }, + "dependencies": { + "ci-info": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", + "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", + "dev": true + } + } + }, + "jest-diff": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.4.2.tgz", + "integrity": "sha512-ujc9ToyUZDh9KcqvQDkk/gkbf6zSaeEg9AiBxtttXW59H/AcqEYp1ciXAtJp+jXWva5nAf/ePtSsgWwE5mqp4Q==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^27.4.0", + "jest-get-type": "^27.4.0", + "pretty-format": "^27.4.2" + } + }, + "jest-docblock": { + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.4.0.tgz", + "integrity": "sha512-7TBazUdCKGV7svZ+gh7C8esAnweJoG+SvcF6Cjqj4l17zA2q1cMwx2JObSioubk317H+cjcHgP+7fTs60paulg==", + "dev": true, + "requires": { + "detect-newline": "^3.0.0" + } + }, + "jest-each": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.4.2.tgz", + "integrity": "sha512-53V2MNyW28CTruB3lXaHNk6PkiIFuzdOC9gR3C6j8YE/ACfrPnz+slB0s17AgU1TtxNzLuHyvNlLJ+8QYw9nBg==", + "dev": true, + "requires": { + "@jest/types": "^27.4.2", + "chalk": "^4.0.0", + "jest-get-type": "^27.4.0", + "jest-util": "^27.4.2", + "pretty-format": "^27.4.2" + } + }, + "jest-environment-jsdom": { + "version": "27.4.4", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.4.4.tgz", + "integrity": "sha512-cYR3ndNfHBqQgFvS1RL7dNqSvD//K56j/q1s2ygNHcfTCAp12zfIromO1w3COmXrxS8hWAh7+CmZmGCIoqGcGA==", + "dev": true, + "requires": { + "@jest/environment": "^27.4.4", + "@jest/fake-timers": "^27.4.2", + "@jest/types": "^27.4.2", + "@types/node": "*", + "jest-mock": "^27.4.2", + "jest-util": "^27.4.2", + "jsdom": "^16.6.0" + } + }, + "jest-environment-node": { + "version": "27.4.4", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.4.4.tgz", + "integrity": "sha512-D+v3lbJ2GjQTQR23TK0kY3vFVmSeea05giInI41HHOaJnAwOnmUHTZgUaZL+VxUB43pIzoa7PMwWtCVlIUoVoA==", + "dev": true, + "requires": { + "@jest/environment": "^27.4.4", + "@jest/fake-timers": "^27.4.2", + "@jest/types": "^27.4.2", + "@types/node": "*", + "jest-mock": "^27.4.2", + "jest-util": "^27.4.2" + } + }, + "jest-get-type": { + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", + "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", + "dev": true + }, + "jest-haste-map": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.4.5.tgz", + "integrity": "sha512-oJm1b5qhhPs78K24EDGifWS0dELYxnoBiDhatT/FThgB9yxqUm5F6li3Pv+Q+apMBmmPNzOBnZ7ZxWMB1Leq1Q==", + "dev": true, + "requires": { + "@jest/types": "^27.4.2", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.4", + "jest-regex-util": "^27.4.0", + "jest-serializer": "^27.4.0", + "jest-util": "^27.4.2", + "jest-worker": "^27.4.5", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + } + }, + "jest-jasmine2": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.4.5.tgz", + "integrity": "sha512-oUnvwhJDj2LhOiUB1kdnJjkx8C5PwgUZQb9urF77mELH9DGR4e2GqpWQKBOYXWs5+uTN9BGDqRz3Aeg5Wts7aw==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^27.4.4", + "@jest/source-map": "^27.4.0", + "@jest/test-result": "^27.4.2", + "@jest/types": "^27.4.2", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.4.2", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.4.2", + "jest-matcher-utils": "^27.4.2", + "jest-message-util": "^27.4.2", + "jest-runtime": "^27.4.5", + "jest-snapshot": "^27.4.5", + "jest-util": "^27.4.2", + "pretty-format": "^27.4.2", + "throat": "^6.0.1" + } + }, + "jest-leak-detector": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.4.2.tgz", + "integrity": "sha512-ml0KvFYZllzPBJWDei3mDzUhyp/M4ubKebX++fPaudpe8OsxUE+m+P6ciVLboQsrzOCWDjE20/eXew9QMx/VGw==", + "dev": true, + "requires": { + "jest-get-type": "^27.4.0", + "pretty-format": "^27.4.2" + } + }, + "jest-matcher-utils": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.4.2.tgz", + "integrity": "sha512-jyP28er3RRtMv+fmYC/PKG8wvAmfGcSNproVTW2Y0P/OY7/hWUOmsPfxN1jOhM+0u2xU984u2yEagGivz9OBGQ==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^27.4.2", + "jest-get-type": "^27.4.0", + "pretty-format": "^27.4.2" + } + }, + "jest-message-util": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.4.2.tgz", + "integrity": "sha512-OMRqRNd9E0DkBLZpFtZkAGYOXl6ZpoMtQJWTAREJKDOFa0M6ptB7L67tp+cszMBkvSgKOhNtQp2Vbcz3ZZKo/w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.4.2", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.4", + "pretty-format": "^27.4.2", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.16.7" + } + } + } + }, + "jest-mock": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.4.2.tgz", + "integrity": "sha512-PDDPuyhoukk20JrQKeofK12hqtSka7mWH0QQuxSNgrdiPsrnYYLS6wbzu/HDlxZRzji5ylLRULeuI/vmZZDrYA==", + "dev": true, + "requires": { + "@jest/types": "^27.4.2", + "@types/node": "*" + } + }, + "jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true, + "requires": {} + }, + "jest-regex-util": { + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.4.0.tgz", + "integrity": "sha512-WeCpMpNnqJYMQoOjm1nTtsgbR4XHAk1u00qDoNBQoykM280+/TmgA5Qh5giC1ecy6a5d4hbSsHzpBtu5yvlbEg==", + "dev": true + }, + "jest-resolve": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.4.5.tgz", + "integrity": "sha512-xU3z1BuOz/hUhVUL+918KqUgK+skqOuUsAi7A+iwoUldK6/+PW+utK8l8cxIWT9AW7IAhGNXjSAh1UYmjULZZw==", + "dev": true, + "requires": { + "@jest/types": "^27.4.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.4.5", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.4.2", + "jest-validate": "^27.4.2", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + } + }, + "jest-resolve-dependencies": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.4.5.tgz", + "integrity": "sha512-elEVvkvRK51y037NshtEkEnukMBWvlPzZHiL847OrIljJ8yIsujD2GXRPqDXC4rEVKbcdsy7W0FxoZb4WmEs7w==", + "dev": true, + "requires": { + "@jest/types": "^27.4.2", + "jest-regex-util": "^27.4.0", + "jest-snapshot": "^27.4.5" + } + }, + "jest-runner": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.4.5.tgz", + "integrity": "sha512-/irauncTfmY1WkTaRQGRWcyQLzK1g98GYG/8QvIPviHgO1Fqz1JYeEIsSfF+9mc/UTA6S+IIHFgKyvUrtiBIZg==", + "dev": true, + "requires": { + "@jest/console": "^27.4.2", + "@jest/environment": "^27.4.4", + "@jest/test-result": "^27.4.2", + "@jest/transform": "^27.4.5", + "@jest/types": "^27.4.2", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-docblock": "^27.4.0", + "jest-environment-jsdom": "^27.4.4", + "jest-environment-node": "^27.4.4", + "jest-haste-map": "^27.4.5", + "jest-leak-detector": "^27.4.2", + "jest-message-util": "^27.4.2", + "jest-resolve": "^27.4.5", + "jest-runtime": "^27.4.5", + "jest-util": "^27.4.2", + "jest-worker": "^27.4.5", + "source-map-support": "^0.5.6", + "throat": "^6.0.1" + } + }, + "jest-runtime": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.4.5.tgz", + "integrity": "sha512-CIYqwuJQXHQtPd/idgrx4zgJ6iCb6uBjQq1RSAGQrw2S8XifDmoM1Ot8NRd80ooAm+ZNdHVwsktIMGlA1F1FAQ==", + "dev": true, + "requires": { + "@jest/console": "^27.4.2", + "@jest/environment": "^27.4.4", + "@jest/globals": "^27.4.4", + "@jest/source-map": "^27.4.0", + "@jest/test-result": "^27.4.2", + "@jest/transform": "^27.4.5", + "@jest/types": "^27.4.2", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.4.5", + "jest-message-util": "^27.4.2", + "jest-mock": "^27.4.2", + "jest-regex-util": "^27.4.0", + "jest-resolve": "^27.4.5", + "jest-snapshot": "^27.4.5", + "jest-util": "^27.4.2", + "jest-validate": "^27.4.2", + "slash": "^3.0.0", + "strip-bom": "^4.0.0", + "yargs": "^16.2.0" + }, + "dependencies": { + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + } + } + }, + "jest-serializer": { + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.4.0.tgz", + "integrity": "sha512-RDhpcn5f1JYTX2pvJAGDcnsNTnsV9bjYPU8xcV+xPwOXnUPOQwf4ZEuiU6G9H1UztH+OapMgu/ckEVwO87PwnQ==", + "dev": true, + "requires": { + "@types/node": "*", + "graceful-fs": "^4.2.4" + } + }, + "jest-snapshot": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.4.5.tgz", + "integrity": "sha512-eCi/iM1YJFrJWiT9de4+RpWWWBqsHiYxFG9V9o/n0WXs6GpW4lUt4FAHAgFPTLPqCUVzrMQmSmTZSgQzwqR7IQ==", + "dev": true, + "requires": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/parser": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.4.5", + "@jest/types": "^27.4.2", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^27.4.2", + "graceful-fs": "^4.2.4", + "jest-diff": "^27.4.2", + "jest-get-type": "^27.4.0", + "jest-haste-map": "^27.4.5", + "jest-matcher-utils": "^27.4.2", + "jest-message-util": "^27.4.2", + "jest-resolve": "^27.4.5", + "jest-util": "^27.4.2", + "natural-compare": "^1.4.0", + "pretty-format": "^27.4.2", + "semver": "^7.3.2" + } }, - "is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true + "jest-util": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.4.2.tgz", + "integrity": "sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA==", + "dev": true, + "requires": { + "@jest/types": "^27.4.2", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.4", + "picomatch": "^2.2.3" + }, + "dependencies": { + "ci-info": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", + "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", + "dev": true + } + } }, - "is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", - "dev": true + "jest-validate": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.4.2.tgz", + "integrity": "sha512-hWYsSUej+Fs8ZhOm5vhWzwSLmVaPAxRy+Mr+z5MzeaHm9AxUpXdoVMEW4R86y5gOobVfBsMFLk4Rb+QkiEpx1A==", + "dev": true, + "requires": { + "@jest/types": "^27.4.2", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.4.0", + "leven": "^3.1.0", + "pretty-format": "^27.4.2" + } }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "jest-watcher": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.4.2.tgz", + "integrity": "sha512-NJvMVyyBeXfDezhWzUOCOYZrUmkSCiatpjpm+nFUid74OZEHk6aMLrZAukIiFDwdbqp6mTM6Ui1w4oc+8EobQg==", + "dev": true, + "requires": { + "@jest/test-result": "^27.4.2", + "@jest/types": "^27.4.2", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^27.4.2", + "string-length": "^4.0.1" + } }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true + "jest-worker": { + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.5.tgz", + "integrity": "sha512-f2s8kEdy15cv9r7q4KkzGXvlY0JTcmCbMHZBfSQDwW77REr45IDWwd0lksDFeVHH2jJ5pqb90T77XscrjeGzzg==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } }, "js-beautify": { "version": "1.14.0", @@ -11468,6 +16130,124 @@ "esprima": "^4.0.0" } }, + "jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "dev": true, + "requires": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true + }, + "acorn": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "dev": true + }, + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, + "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 + }, + "tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "requires": { + "punycode": "^2.1.1" + } + }, + "webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true + }, + "whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dev": true, + "requires": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + } + } + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, "json-bigint": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", @@ -11625,6 +16405,12 @@ "graceful-fs": "^4.1.11" } }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, "kuler": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", @@ -11639,6 +16425,12 @@ "package-json": "^6.3.0" } }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -11663,15 +16455,6 @@ "uc.micro": "^1.0.1" } }, - "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", @@ -11707,6 +16490,12 @@ "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -11724,16 +16513,6 @@ "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", "dev": true }, - "log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - } - }, "logform": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/logform/-/logform-2.3.0.tgz", @@ -11785,6 +16564,15 @@ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" }, + "makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "requires": { + "tmpl": "1.0.5" + } + }, "markdown-it": { "version": "11.0.1", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-11.0.1.tgz", @@ -11830,6 +16618,12 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, "merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -11869,6 +16663,12 @@ "mime-db": "1.51.0" } }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, "mimic-response": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", @@ -12298,95 +17098,6 @@ "minimist": "^1.2.5" } }, - "mocha": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.1.3.tgz", - "integrity": "sha512-Xcpl9FqXOAYqI3j79pEtHBBnQgVXIhpULjGQa7DVb0Po+VzmSIK9kanAiWLHoRR/dbZ2qpdPshuXr8l1VaHCzw==", - "dev": true, - "requires": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.2", - "debug": "4.3.2", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.1.7", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "3.0.4", - "ms": "2.1.3", - "nanoid": "3.1.25", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "which": "2.0.2", - "workerpool": "6.1.5", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "dependencies": { - "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 - }, - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "requires": { - "ms": "2.1.2" - }, - "dependencies": { - "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 - } - } - }, - "glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "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" - } - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, "mongodb": { "version": "3.7.3", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.3.tgz", @@ -12511,12 +17222,6 @@ "thenify-all": "^1.0.0" } }, - "nanoid": { - "version": "3.1.25", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz", - "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==", - "dev": true - }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -12559,6 +17264,18 @@ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node-releases": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", + "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==", + "dev": true + }, "nodemailer": { "version": "6.7.2", "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.2.tgz", @@ -12624,6 +17341,15 @@ "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", "dev": true }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, "npmlog": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", @@ -12643,6 +17369,12 @@ "boolbase": "^1.0.0" } }, + "nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -12683,6 +17415,15 @@ "fn.name": "1.x.x" } }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, "optional-require": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz", @@ -12716,15 +17457,6 @@ "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" - } - }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -12844,12 +17576,6 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, - "pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true - }, "pause": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", @@ -12910,11 +17636,71 @@ "split2": "^4.1.0" } }, - "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" - }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" + }, + "pirates": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.4.tgz", + "integrity": "sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + } + } + }, "pngjs": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", @@ -12970,6 +17756,26 @@ "fast-diff": "^1.1.2" } }, + "pretty-format": { + "version": "27.4.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.2.tgz", + "integrity": "sha512-p0wNtJ9oLuvgOQDEIZ9zQjZffK7KtyR6Si0jnXULIDwrlNF8Cuir3AZP0hHv0jmKuNN/edOnbMjnzd4uTcmWiw==", + "dev": true, + "requires": { + "@jest/types": "^27.4.2", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -12981,6 +17787,16 @@ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, + "prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, "proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", @@ -13000,6 +17816,12 @@ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, "pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", @@ -13163,15 +17985,6 @@ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -13218,6 +18031,12 @@ } } }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, "readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -13310,12 +18129,35 @@ "path-parse": "^1.0.6" } }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, "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 }, + "resolve.exports": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", + "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "dev": true + }, "responselike": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", @@ -13406,6 +18248,15 @@ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, + "saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "requires": { + "xmlchars": "^2.2.0" + } + }, "semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", @@ -13478,15 +18329,6 @@ } } }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, "serve-static": { "version": "1.14.2", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", @@ -13566,6 +18408,12 @@ "is-arrayish": "^0.3.1" } }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -13637,6 +18485,23 @@ "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" }, + "stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -13668,6 +18533,16 @@ "safe-buffer": "~5.2.0" } }, + "string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } + }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -13691,6 +18566,12 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -13702,58 +18583,65 @@ "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=" }, - "superagent": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", - "integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==", + "supertest": { + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.1.6.tgz", + "integrity": "sha512-0hACYGNJ8OHRg8CRITeZOdbjur7NLuNs0mBjVhdpxi7hP6t3QIbOzLON5RTUmZcy2I9riuII3+Pr2C7yztrIIg==", "dev": true, "requires": { - "component-emitter": "^1.2.0", - "cookiejar": "^2.1.0", - "debug": "^3.1.0", - "extend": "^3.0.0", - "form-data": "^2.3.1", - "formidable": "^1.2.0", - "methods": "^1.1.1", - "mime": "^1.4.1", - "qs": "^6.5.1", - "readable-stream": "^2.3.5" + "methods": "^1.1.2", + "superagent": "^6.1.0" }, "dependencies": { - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "requires": { + "ms": "2.1.2" + } }, - "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==", + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" } }, - "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==", + "mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", "dev": true }, - "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==", + "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 + }, + "superagent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-6.1.0.tgz", + "integrity": "sha512-OUDHEssirmplo3F+1HWKUrUjvnQuA+nZI6i/JJBdXb5eq9IyEQwPyPpqND+SSsxf6TygpBEkUjISVRN4/VOpeg==", "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.2", + "debug": "^4.1.1", + "fast-safe-stringify": "^2.0.7", + "form-data": "^3.0.0", + "formidable": "^1.2.2", + "methods": "^1.1.2", + "mime": "^2.4.6", + "qs": "^6.9.4", + "readable-stream": "^3.6.0", + "semver": "^7.3.2" } } } @@ -13766,6 +18654,22 @@ "has-flag": "^4.0.0" } }, + "supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + } + }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, "table": { "version": "6.7.5", "resolved": "https://registry.npmjs.org/table/-/table-6.7.5.tgz", @@ -13831,6 +18735,27 @@ "uuid": "^8.0.0" } }, + "terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, "text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", @@ -13858,6 +18783,24 @@ "thenify": ">= 3.1.0 < 4" } }, + "throat": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", + "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", + "dev": true + }, + "tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, "to-readable-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", @@ -13897,6 +18840,25 @@ } } }, + "tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "dev": true, + "requires": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" + }, + "dependencies": { + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + } + } + }, "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -13912,6 +18874,33 @@ "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" }, + "ts-jest": { + "version": "27.1.2", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.2.tgz", + "integrity": "sha512-eSOiJOWq6Hhs6Khzk5wKC5sgWIXgXqOCiIl1+3lfnearu58Hj4QpE5tUhQcA3xtZrELbcvAGCsd6HB8OsaVaTA==", + "dev": true, + "requires": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^27.0.0", + "json5": "2.x", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "20.x" + }, + "dependencies": { + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + } + } + }, "ts-node": { "version": "9.1.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", @@ -14159,6 +19148,39 @@ } } }, + "typeorm-extension": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/typeorm-extension/-/typeorm-extension-1.1.0.tgz", + "integrity": "sha512-UNDZPZhX4vL7SAJK+EIMHB3uiNWMomaKUYVAdhSGUDSLliqrxQ/V7/ZMar6YDJjdpWSdphDzFrroxaIDwkF5nw==", + "requires": { + "@trapi/query": "^2.0.3", + "glob": "^7.1.7", + "reflect-metadata": "^0.1.13", + "typeorm": "^0.2.41", + "yargs": "^17.3.1" + }, + "dependencies": { + "yargs": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz", + "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + } + }, + "yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==" + } + } + }, "typescript": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz", @@ -14266,6 +19288,25 @@ "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, + "v8-to-istanbul": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz", + "integrity": "sha512-/PRhfd8aTNp9Ggr62HPzXg2XasNFGy5PBt0Rp04du7/8GNNSgxFL6WBTkgMKSL9bFjH+8kKEG3f37FmxiTqUUA==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, "valid-data-url": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/valid-data-url/-/valid-data-url-3.0.1.tgz", @@ -14281,6 +19322,33 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, + "w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "dev": true, + "requires": { + "browser-process-hrtime": "^1.0.0" + } + }, + "w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dev": true, + "requires": { + "xml-name-validator": "^3.0.0" + } + }, + "walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "requires": { + "makeerror": "1.0.12" + } + }, "web-resource-inliner": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/web-resource-inliner/-/web-resource-inliner-5.0.0.tgz", @@ -14330,6 +19398,32 @@ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "requires": { + "iconv-lite": "0.4.24" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, "whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", @@ -14407,12 +19501,6 @@ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" }, - "workerpool": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.5.tgz", - "integrity": "sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw==", - "dev": true - }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -14439,11 +19527,24 @@ "typedarray-to-buffer": "^3.1.5" } }, + "ws": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", + "integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==", + "dev": true, + "requires": {} + }, "xdg-basedir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==" }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, "xml2js": { "version": "0.4.23", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", @@ -14458,6 +19559,12 @@ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -14492,18 +19599,6 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==" }, - "yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "requires": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - } - }, "yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/package.json b/package.json index 8e31f870..960223df 100644 --- a/package.json +++ b/package.json @@ -4,13 +4,13 @@ "private": true, "license": "MIT", "scripts": { - "start": "DEBUG=hackboard:* NODE_ENV=test ts-node-dev --respawn --pretty -r tsconfig-paths/register --transpile-only src/app.ts", - "start-windows": "set DEBUG=hackboard:* && set NODE_ENV=test && ts-node-dev --respawn --pretty --transpile-only src/app.ts", + "start": "DEBUG=hackboard:* NODE_ENV=development ts-node-dev --respawn --pretty -r tsconfig-paths/register --transpile-only src/index.ts", + "start-windows": "set DEBUG=hackboard:* && set NODE_ENV=test && ts-node-dev --respawn --pretty --transpile-only src/index.ts", "deploy": "NODE_ENV=deployment node ./bin/www.js", - "test": "DEBUG=hackboard:* NODE_ENV=test mocha --parallel --reporter spec tests/**.js --exit", "docs": "apidoc -i ./routes -o ./docs/api/", "format": "prettier --write 'src/**/*.ts'", - "lint": "eslint --fix 'src/**/*.ts'" + "lint": "eslint --fix 'src/**/*.ts'", + "test": "DEBUG=hackboard:* NODE_ENV=test jest --detectOpenHandles" }, "dependencies": { "@decorators/di": "^1.0.3", @@ -29,7 +29,6 @@ "jsonwebtoken": "^8.5.1", "memory-cache": "^0.2.0", "mjml": "^4.11.0", - "mongoose": "^5.13.3", "multer": "^1.4.2", "nodemailer": "^6.7.2", "passport": "^0.4.1", @@ -40,6 +39,7 @@ "ts-node-dev": "^1.1.8", "tsyringe": "^4.6.0", "typeorm": "^0.2.41", + "typeorm-extension": "^1.1.0", "typescript": "^4.5.2", "winston": "^3.3.3" }, @@ -51,6 +51,7 @@ "@types/express": "^4.17.13", "@types/express-winston": "^4.0.0", "@types/google-cloud__storage": "^1.7.2", + "@types/jest": "^27.4.0", "@types/jsonwebtoken": "^8.5.6", "@types/mjml": "^4.7.0", "@types/multer": "^1.4.7", @@ -59,17 +60,18 @@ "@types/passport-local": "^1.0.34", "@types/qrcode": "^1.4.2", "@types/superagent": "^4.1.13", + "@types/supertest": "^2.0.11", "@types/validator": "^13.7.0", - "@typescript-eslint/eslint-plugin": "^5.8.1", - "@typescript-eslint/parser": "^5.8.1", + "@typescript-eslint/eslint-plugin": "^5.10.0", + "@typescript-eslint/parser": "^5.10.0", "apidoc": "^0.28.1", - "chai": "^4.3.4", - "chai-http": "^4.3.0", - "eslint": "7.31.0", - "eslint-config-prettier": "8.3.0", - "eslint-plugin-prettier": "3.4.0", - "mocha": "^9.0.3", + "eslint": "^7.31.0", + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-prettier": "^3.4.0", + "jest": "^27.4.5", "prettier": "1.19.1", + "supertest": "^6.1.6", + "ts-jest": "^27.1.2", "tsconfig-paths": "^3.12.0" } } From 53861e93631ae764c5183a6f0bd4823e0fc2a3ae Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Thu, 3 Feb 2022 04:38:33 -0500 Subject: [PATCH 48/72] feat: configure jest - add visual studio code launch configurations for tests. - reconfigure tsconfig.json to ignore tests. - add initial jest configuration with path/module aliases. --- .vscode/launch.json | 232 ++++-------------------------------------- .vscode/settings.json | 4 +- jest.config.js | 15 +++ tsconfig.json | 3 +- 4 files changed, 41 insertions(+), 213 deletions(-) create mode 100644 jest.config.js diff --git a/.vscode/launch.json b/.vscode/launch.json index 47a77a8d..53bd2b5a 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -6,223 +6,35 @@ "configurations": [ { "type": "node", - "runtimeVersion": "10.17.0", + "name": "Jest Tests - All", "request": "launch", - "name": "Mocha Tests - Current File", - "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen", + "disableOptimisticBPs": true, + "cwd": "${workspaceFolder}", + "runtimeExecutable": "npm", "args": [ - "-u", - "bdd", - "--timeout", - "999999", - "--colors", - "${workspaceFolder}/tests/setup.spec.js", - "${file}" - ], - "internalConsoleOptions": "openOnSessionStart" + "run", + "test", + "--" + ] }, { "type": "node", - "runtimeVersion": "10.17.0", + "name": "vscode-jest-tests", "request": "launch", - "name": "Mocha Tests", - "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen", + "disableOptimisticBPs": true, + "cwd": "${workspaceFolder}", + "runtimeExecutable": "npm", "args": [ - "-u", - "bdd", - "--timeout", - "999999", - "--colors", - "${workspaceFolder}/tests" - ], - "internalConsoleOptions": "openOnSessionStart" - }, - { - "type": "node", - "runtimeVersion": "10.17.0", - "request": "launch", - "name": "Mocha Tests - Hacker", - "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", - "args": [ - "-u", - "bdd", - "--timeout", - "999999", - "--colors", - "${workspaceFolder}/tests/setup.spec.js", - "${workspaceFolder}/tests/hacker.test.js" - ], - "internalConsoleOptions": "openOnSessionStart" - }, - { - "type": "node", - "runtimeVersion": "10.17.0", - "request": "launch", - "name": "Mocha Tests - Sponsor", - "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", - "args": [ - "-u", - "bdd", - "--timeout", - "999999", - "--colors", - "${workspaceFolder}/tests/setup.spec.js", - "${workspaceFolder}/tests/sponsor.test.js" - ], - "internalConsoleOptions": "openOnSessionStart" - }, - { - "type": "node", - "runtimeVersion": "10.17.0", - "request": "launch", - "name": "Mocha Tests - Volunteer", - "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", - "args": [ - "-u", - "bdd", - "--timeout", - "999999", - "--colors", - "${workspaceFolder}/tests/setup.spec.js", - "${workspaceFolder}/tests/volunteer.test.js" - ], - "internalConsoleOptions": "openOnSessionStart" - }, - { - "type": "node", - "runtimeVersion": "10.17.0", - "request": "launch", - "name": "Mocha Tests - Account", - "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", - "args": [ - "-u", - "bdd", - "--timeout", - "999999", - "--colors", - "${workspaceFolder}/tests/setup.spec.js", - "${workspaceFolder}/tests/account.test.js" - ], - "internalConsoleOptions": "openOnSessionStart" - }, - { - "type": "node", - "runtimeVersion": "10.17.0", - "request": "launch", - "name": "Mocha Tests - Team", - "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", - "args": [ - "-u", - "bdd", - "--timeout", - "999999", - "--colors", - "${workspaceFolder}/tests/setup.spec.js", - "${workspaceFolder}/tests/team.test.js" - ], - "internalConsoleOptions": "openOnSessionStart" - }, - { - "type": "node", - "runtimeVersion": "10.17.0", - "request": "launch", - "name": "Mocha Tests - Storage", - "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", - "args": [ - "-u", - "bdd", - "--timeout", - "999999", - "--colors", - "${workspaceFolder}/tests/setup.spec.js", - "${workspaceFolder}/tests/storage.spec.js" - ], - "internalConsoleOptions": "openOnSessionStart" - }, - { - "type": "node", - "runtimeVersion": "10.17.0", - "request": "launch", - "name": "Mocha Tests - Search", - "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", - "args": [ - "-u", - "bdd", - "--timeout", - "999999", - "--colors", - "${workspaceFolder}/tests/setup.spec.js", - "${workspaceFolder}/tests/search.service.spec.js" - ], - "internalConsoleOptions": "openOnSessionStart" - }, - { - "type": "node", - "runtimeVersion": "10.17.0", - "request": "launch", - "name": "Mocha Tests - Settings", - "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", - "args": [ - "-u", - "bdd", - "--timeout", - "999999", - "--colors", - "${workspaceFolder}/tests/setup.spec.js", - "${workspaceFolder}/tests/settings.test.js" - ], - "internalConsoleOptions": "openOnSessionStart" - }, - { - "type": "node", - "runtimeVersion": "10.17.0", - "request": "launch", - "name": "Mocha Tests - Email", - "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", - "args": [ - "-u", - "bdd", - "--timeout", - "999999", - "--colors", - "${workspaceFolder}/tests/setup.spec.js", - "${workspaceFolder}/tests/email.service.spec.js" - ], - "internalConsoleOptions": "openOnSessionStart" - }, - { - "type": "node", - "runtimeVersion": "10.17.0", - "request": "launch", - "name": "Mocha Tests - Auth", - "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", - "args": [ - "-u", - "bdd", - "--timeout", - "999999", - "--colors", - "${workspaceFolder}/tests/setup.spec.js", - "${workspaceFolder}/tests/auth.test.js" - ], - "internalConsoleOptions": "openOnSessionStart" - }, - { - "type": "node", - "runtimeVersion": "10.17.0", - "request": "launch", - "name": "Mocha Tests - Role", - "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", - "args": [ - "-u", - "bdd", - "--timeout", - "999999", - "--colors", - "${workspaceFolder}/tests/setup.spec.js", - "${workspaceFolder}/tests/role.test.js" - ], - "internalConsoleOptions": "openOnSessionStart" + "run", + "test", + "--", + "--runInBand", + "--watchAll=false" + ] } ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index aee26f6c..f19d8f9d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,7 @@ { - "search.usePCRE2": true, "editor.formatOnSave": true, "files.insertFinalNewline": true, "files.trimFinalNewlines": true, - "editor.tabSize": 4 + "editor.tabSize": 4, + "jest.jestCommandLine": "npm run test --" } diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 00000000..ed35f4e6 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,15 @@ +/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + moduleNameMapper: { + "@app/(.*)$": "/src/$1", + "@models/(.*)$": "/src/models/$1", + "@controllers/(.*)$": "/src/controllers/$1", + "@middlewares/(.*)$": "/src/middlewares/$1", + "@services/(.*)$": "/src/services/$1", + "@constants/(.*)$": "/src/constants/$1", + "@assets/(.*)$": "/src/assets/$1", + "@strategies/(.*)$": "/src/strategies/$1", + } +}; diff --git a/tsconfig.json b/tsconfig.json index a4887de7..51a9db26 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,6 +15,7 @@ "emitDecoratorMetadata": true, "baseUrl": "src/", "paths": { + "@app/*": ["./*"], "@models/*": ["models/*"], "@controllers/*": ["controllers/*"], "@services/*": ["services/*"], @@ -25,5 +26,5 @@ } }, "include": ["./src/**/*", "./.env"], - "exclude": ["node_modules", "src/**/*.spec.ts", ".vscode", ".github", "docs", "scripts", "./src/tests"] + "exclude": ["node_modules", ".vscode", ".github", "docs", "scripts", "tests"] } From e9c00e7f5c9857ef75e998eaa4b35cf6a00c7c0f Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Thu, 3 Feb 2022 04:44:40 -0500 Subject: [PATCH 49/72] chore(.nvmrc): update to the node lts --- .nvmrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.nvmrc b/.nvmrc index 958b5a36..53a42214 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v14 +v16.13.2 From d0b0beadf3f266fcd4da90f77fccd85978002cd9 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Thu, 3 Feb 2022 04:45:37 -0500 Subject: [PATCH 50/72] chore(.gitignore): ammend to ignore all .env files --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 69842024..7adf4096 100755 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ node_modules #env file -.env +.env.* #creds gcp_creds.json From baa2022e74b757e9a9c2a01d0c9028743943fd43 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Thu, 3 Feb 2022 05:16:31 -0500 Subject: [PATCH 51/72] refactor: remove env & db service --- src/controllers/authentication.controller.ts | 28 ++++----- src/services/account-confirmation.service.ts | 19 ++---- src/services/database.service.ts | 31 ---------- src/services/email.service.ts | 26 ++++----- src/services/env.service.ts | 61 -------------------- src/services/hacker.service.ts | 17 +----- src/services/logger.service.ts | 19 ++---- src/services/password-reset.service.ts | 15 +---- src/services/storage.service.ts | 8 +-- 9 files changed, 36 insertions(+), 188 deletions(-) delete mode 100644 src/services/database.service.ts delete mode 100644 src/services/env.service.ts diff --git a/src/controllers/authentication.controller.ts b/src/controllers/authentication.controller.ts index 212a0c68..4c91d408 100644 --- a/src/controllers/authentication.controller.ts +++ b/src/controllers/authentication.controller.ts @@ -26,7 +26,6 @@ import PasswordReset from "@models/password-reset-token.model"; import { EmailService } from "@services/email.service"; import { join } from "path"; import jwt from "jsonwebtoken"; -import { EnvService } from "@services/env.service"; import { AccountConfirmationService } from "@services/account-confirmation.service"; import AccountConfirmation from "@models/account-confirmation-token.model"; import { EnsureAuthorization } from "@middlewares/authorization.middleware"; @@ -40,8 +39,7 @@ export class AuthenticationController { private readonly accountService: AccountService, private readonly passwordResetService: PasswordResetService, private readonly accountConfirmationService: AccountConfirmationService, - private readonly mailer: EmailService, - private readonly envService: EnvService + private readonly mailer: EmailService ) {} @Post("/sign-in") @@ -141,10 +139,7 @@ export class AuthenticationController { @Body("password") password: string ) { // Check if the JWT is valid and provide deconstructed object of identifier and account identiifer. - const data = jwt.verify( - token, - this.envService.get("JWT_RESET_PWD_SECRET")! - ) as { + const data = jwt.verify(token, process.env.JWT_RESET_PWD_SECRET!) as { identifier: number; }; @@ -210,12 +205,14 @@ export class AuthenticationController { @Response() response: ExpressResponse ) { // We use the non-null asseration opearator as we are sure that the user exists befure of the EnsureAuthenticated middleware. - const account: Account = (await this.accountService.findByIdentifier( + const account: + | Account + | undefined = await this.accountService.findByIdentifier( //@ts-ignore request.user?.identifier - ))!; + ); - if (account.confirmed) + if (account!.confirmed) response.status(422).send({ message: "Account already confirmed" }); @@ -223,7 +220,7 @@ export class AuthenticationController { const model: | AccountConfirmation | undefined = await this.accountConfirmationService.findByAccount( - account.identifier + account!.identifier ); if (!model) @@ -233,7 +230,7 @@ export class AuthenticationController { await this.mailer.send( { - to: account.email, + to: account?.email, subject: "Account Confirmation Instructions", html: join( __dirname, @@ -245,7 +242,7 @@ export class AuthenticationController { "confirm", this.accountConfirmationService.generateToken( model!.identifier, - account.identifier + account!.identifier ) ) }, @@ -270,10 +267,7 @@ export class AuthenticationController { @Params("token") token: string ) { // Check if the JWT is valid and provide deconstructed object of identifier and account identiifer. - const data = jwt.verify( - token, - this.envService.get("JWT_CONFIRM_ACC_SECRET")! - ) as { + const data = jwt.verify(token, process.env.JWT_CONFIRM_ACC_SECRET!) as { identifier: number; account: number; }; diff --git a/src/services/account-confirmation.service.ts b/src/services/account-confirmation.service.ts index 754b4118..857a46f7 100644 --- a/src/services/account-confirmation.service.ts +++ b/src/services/account-confirmation.service.ts @@ -1,8 +1,7 @@ import { autoInjectable, singleton } from "tsyringe"; -import { getRepository, Repository } from "typeorm"; +import { DeleteResult, getRepository, Repository } from "typeorm"; import AccountConfirmation from "@models/account-confirmation-token.model"; import jwt from "jsonwebtoken"; -import { EnvService } from "@services/env.service"; @autoInjectable() @singleton() @@ -11,7 +10,7 @@ export class AccountConfirmationService { AccountConfirmation >; - constructor(private readonly envService: EnvService) { + constructor() { this.accountConfirmationRepository = getRepository(AccountConfirmation); } @@ -39,24 +38,14 @@ export class AccountConfirmationService { return await this.accountConfirmationRepository.save(confirmation); } - public async delete(identifier: number) { + public async delete(identifier: number): Promise { return await this.accountConfirmationRepository.delete({ identifier: identifier }); } public generateLink(route: string, token: string): string { - const domain = this.getDomain()!; - const protocol = domain.includes("localhost") ? "http" : "https"; - return `${protocol}://${domain}/${route}?token=${token}`; - } - - private getDomain() { - return this.envService.isDevelopment() - ? this.envService.get(`FRONTEND_ADDRESS_DEV`) - : this.envService.isProduction() - ? this.envService.get(`FRONTEND_ADDRESS_DEPLOY`) - : this.envService.get(`FRONTEND_ADDRESS_DEV`); + return `${process.env.FRONTEND_ADDRESS_DEV}/${route}?token=${token}`; } public generateToken(identifier: number, account: number): string { diff --git a/src/services/database.service.ts b/src/services/database.service.ts deleted file mode 100644 index f71d12b4..00000000 --- a/src/services/database.service.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { createConnection } from "typeorm"; - -import { autoInjectable, singleton } from "tsyringe"; -import { EnvService } from "@services/env.service"; - -@autoInjectable() -@singleton() -export class DatabaseService { - constructor(private readonly envService: EnvService) {} - - public async connect() { - await createConnection({ - type: "postgres", - host: this.getDatabaseAttribute("HOST"), - port: parseInt(this.getDatabaseAttribute("PORT")!), - username: this.getDatabaseAttribute("USER"), - password: this.getDatabaseAttribute("PASSPORT"), - database: this.getDatabaseAttribute("NAME"), - synchronize: true, - entities: [__dirname + "/../**/**.model{.ts,.js}"] - }); - } - - private getDatabaseAttribute(name: string) { - return this.envService.isDevelopment() - ? this.envService.get(`DB_${name}_DEV`) - : this.envService.isProduction() - ? this.envService.get(`DB_${name}_DEPLOY`) - : this.envService.get(`DB_${name}_TEST`); - } -} diff --git a/src/services/email.service.ts b/src/services/email.service.ts index c7091cc0..88331608 100644 --- a/src/services/email.service.ts +++ b/src/services/email.service.ts @@ -1,6 +1,5 @@ import { readFileSync } from "fs"; import { autoInjectable } from "tsyringe"; -import { EnvService } from "@services/env.service"; import { createTransport } from "nodemailer"; import { compile } from "handlebars"; import mjml2html from "mjml"; @@ -10,10 +9,7 @@ import { LoggerService } from "@services/logger.service"; export class EmailService { protected readonly mailer; - constructor( - private readonly envService: EnvService, - private readonly loggerService: LoggerService - ) { + constructor(private readonly loggerService: LoggerService) { this.mailer = createTransport({ host: this.getEmailAttribute("HOST"), port: parseInt(this.getEmailAttribute("PORT")!), @@ -27,12 +23,16 @@ export class EmailService { .catch((error) => this.loggerService .getLogger() - .error(`Failed to connect to SMTP server. Error: ${error}`) + .error(`Failed to connect to SMTP server. ${error}`) ); } - public async send({ ...args }: any, { ...context }: any, callback?: any) { - args.from = this.envService.get("NO_REPLY_EMAIL"); + public async send( + { ...args }: any, + { ...context }: any, + callback?: any + ): Promise { + args.from = process.env.NO_REPLY_EMAIL; if (args.html) args.html = compile( mjml2html(readFileSync(args.html, "utf-8")).html @@ -40,16 +40,12 @@ export class EmailService { await this.mailer .sendMail({ ...args, - from: this.envService.get("NO_REPLY_EMAIL") + from: process.env.NO_REPLY_EMAIL }) .catch((error) => callback(error)); } - private getEmailAttribute(name: string) { - return this.envService.isDevelopment() - ? this.envService.get(`EMAIL_${name}_DEV`) - : this.envService.isProduction() - ? this.envService.get(`EMAIL_${name}_DEPLOY`) - : this.envService.get(`EMAIL_${name}_TEST`); + private getEmailAttribute(name: string): string | undefined { + return process.env[`EMAIL_${name}`]; } } diff --git a/src/services/env.service.ts b/src/services/env.service.ts deleted file mode 100644 index da8695c7..00000000 --- a/src/services/env.service.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { config, DotenvConfigOutput } from "dotenv"; -import * as fs from "fs"; -import { join } from "path"; -import { autoInjectable, singleton } from "tsyringe"; - -interface GoogleCloudPlatformCredentials { - type: string | undefined; - project_id: string | undefined; - private_key_id: string | undefined; - private_key: string | undefined; - client_email: string | undefined; - client_id: string | undefined; - auth_uri: string | undefined; - token_uri: string | undefined; - auth_provider_x509_cert_url: string | undefined; - client_x509_cert_url: string | undefined; -} - -@autoInjectable() -@singleton() -export class EnvService { - constructor() { - const result: DotenvConfigOutput = config({ - path: join(__dirname, "../../.env") - }); - if (result.error) throw result.error; - this.createGoogleCloudPlatformFile(); - } - - private createGoogleCloudPlatformFile() { - const credentials: GoogleCloudPlatformCredentials = { - type: process.env.TYPE, - project_id: process.env.PROJECT_ID, - private_key_id: process.env.PRIVATE_KEY_ID, - private_key: process.env.PRIVATE_KEY, - client_email: process.env.CLIENT_EMAIL, - client_id: process.env.CLIENT_ID, - auth_uri: process.env.AUTH_URI, - token_uri: process.env.TOKEN_URI, - auth_provider_x509_cert_url: - process.env.AUTH_PROVIDER_X509_CERT_URL, - client_x509_cert_url: process.env.CLIENT_X509_CERT_URL - }; - - const stringified = JSON.stringify(credentials); - const unEscaped = stringified.replace(/\\\\n/g, "\\n"); - const fileLocation = join(__dirname, "../../gcp_creds.json"); - fs.writeFileSync(fileLocation, unEscaped); - process.env.GOOGLE_APPLICATION_CREDENTIALS = fileLocation; - } - - public get(key: string) { - return process.env[key]; - } - - public isDevelopment = (): boolean => process.env.NODE_ENV === "test"; - - public isProduction = (): boolean => process.env.NODE_ENV === "deployment"; - - public isTest = (): boolean => process.env.NODE_ENV === "test"; -} diff --git a/src/services/hacker.service.ts b/src/services/hacker.service.ts index 8e9808de..3a9f4a86 100644 --- a/src/services/hacker.service.ts +++ b/src/services/hacker.service.ts @@ -2,16 +2,13 @@ import { autoInjectable, singleton } from "tsyringe"; import { getRepository, Repository, UpdateResult } from "typeorm"; import Hacker from "@models/hacker.model"; import { toDataURL } from "qrcode"; -import { EnvService } from "@services/env.service"; - -const cache = require("memory-cache"); @autoInjectable() @singleton() export class HackerService { private readonly hackerRepository: Repository; - constructor(private readonly envService: EnvService) { + constructor() { this.hackerRepository = getRepository(Hacker); } @@ -68,17 +65,7 @@ export class HackerService { } public generateHackerApplicationViewLink(identifier: string): string { - const domain = this.getDomain()!; - const protocol = domain.includes("localhost") ? "http" : "https"; - return `${protocol}://${domain}/application/view/${identifier}`; - } - - private getDomain() { - return this.envService.isDevelopment() - ? this.envService.get(`FRONTEND_ADDRESS_DEV`) - : this.envService.isProduction() - ? this.envService.get(`FRONTEND_ADDRESS_DEPLOY`) - : this.envService.get(`FRONTEND_ADDRESS_DEV`); + return `${process.env.FRONTEND_ADDRESS}/application/view/${identifier}`; } } diff --git a/src/services/logger.service.ts b/src/services/logger.service.ts index 24660060..3cb0521f 100755 --- a/src/services/logger.service.ts +++ b/src/services/logger.service.ts @@ -1,27 +1,16 @@ -import winston, { - error, - warn, - info, - log, - verbose, - debug, - silly, - Logger -} from "winston"; +import winston, { Logger } from "winston"; import expressWinston from "express-winston"; -import { inject, injectable, singleton } from "tsyringe"; +import { singleton } from "tsyringe"; import { ErrorRequestHandler, Handler } from "express"; -import { EnvService } from "@services/env.service"; import { Format } from "logform"; -@injectable() @singleton() export class LoggerService { private readonly logger: Logger; private readonly requestLogger: Handler; private readonly errorLogger: ErrorRequestHandler; - constructor(@inject(EnvService) envService: EnvService) { + constructor() { const format: Format = winston.format.combine( winston.format.colorize({ all: true }), winston.format.timestamp({ @@ -40,7 +29,7 @@ export class LoggerService { this.requestLogger = expressWinston.logger({ transports: [new winston.transports.Console()], format: format, - colorize: !envService.isProduction(), + colorize: process.env.NODE_ENV != "production", msg: `{{res.statusCode}} {{req.method}} {{res.responseTime}}ms {{req.url}}` }); diff --git a/src/services/password-reset.service.ts b/src/services/password-reset.service.ts index 288a80a0..178aad03 100644 --- a/src/services/password-reset.service.ts +++ b/src/services/password-reset.service.ts @@ -3,12 +3,11 @@ import { DeleteResult, getRepository, Repository } from "typeorm"; import Account from "@models/account.model"; import PasswordReset from "@models/password-reset-token.model"; import jwt from "jsonwebtoken"; -import { EnvService } from "@services/env.service"; @autoInjectable() export class PasswordResetService { private readonly passwordResetRepository: Repository; - constructor(private readonly envService: EnvService) { + constructor() { this.passwordResetRepository = getRepository(PasswordReset); } @@ -42,17 +41,7 @@ export class PasswordResetService { } public generateLink(route: string, token: string): string { - const domain = this.getDomain()!; - const protocol = domain.includes("localhost") ? "http" : "https"; - return `${protocol}://${domain}/${route}?token=${token}`; - } - - private getDomain() { - return this.envService.isDevelopment() - ? this.envService.get(`FRONTEND_ADDRESS_DEV`) - : this.envService.isProduction() - ? this.envService.get(`FRONTEND_ADDRESS_DEPLOY`) - : this.envService.get(`FRONTEND_ADDRESS_DEV`); + return `${process.env.FRONTEND_ADDRESS}/${route}?token=${token}`; } public generateToken(identifier: number, account: number): string { diff --git a/src/services/storage.service.ts b/src/services/storage.service.ts index 0366ce31..338df912 100644 --- a/src/services/storage.service.ts +++ b/src/services/storage.service.ts @@ -1,7 +1,6 @@ // Imports the Google Cloud client library import * as GStorage from "@google-cloud/storage"; import { autoInjectable } from "tsyringe"; -import { EnvService } from "@services/env.service"; import { LoggerService } from "@services/logger.service"; @autoInjectable() @@ -10,17 +9,14 @@ export class StorageService { storage: any; bucket: any; - constructor( - private readonly envService: EnvService, - loggerService: LoggerService - ) { + constructor(loggerService: LoggerService) { this.bucketName = process.env.BUCKET_NAME || ""; try { this.storage = new GStorage.Storage(); } catch (error) { loggerService.getLogger().error(error); } - if (this.envService.isProduction()) + if (process.env.NODE_ENV !== "production") this.bucket = this.storage.bucket(this.bucketName); } From 9d6686ddc1f7568ae2b549c7b6a2c2956d393ea9 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Thu, 3 Feb 2022 05:17:43 -0500 Subject: [PATCH 52/72] fix(authenticated.middleware.ts): fix bug where 401 response is not sent --- src/middlewares/authenticated.middleware.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/middlewares/authenticated.middleware.ts b/src/middlewares/authenticated.middleware.ts index 5da74997..cb679dd2 100644 --- a/src/middlewares/authenticated.middleware.ts +++ b/src/middlewares/authenticated.middleware.ts @@ -13,12 +13,11 @@ export class EnsureAuthenticated implements Middleware { ParsedQs, Record >, - _: Response>, + response: Response>, next: NextFunction ): void { if (request.isUnauthenticated()) - return next({ - status: 401, + response.status(401).send({ message: ErrorConstants.AUTH_401_MESSAGE, error: { route: request.path } }); From 22da9397248011259b1624d8d8663b1f29fd33fd Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Thu, 3 Feb 2022 05:18:41 -0500 Subject: [PATCH 53/72] fix(authorization.middleware.ts): allow 404's for entities to be returned --- src/middlewares/authorization.middleware.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/middlewares/authorization.middleware.ts b/src/middlewares/authorization.middleware.ts index 45441318..6e93e851 100644 --- a/src/middlewares/authorization.middleware.ts +++ b/src/middlewares/authorization.middleware.ts @@ -62,7 +62,9 @@ export function EnsureAuthorization( if ( !noIdentifierCheck && //@ts-ignore - query?.identifier !== request.user?.identifier + query && + //@ts-ignore + query.identifier !== request.user?.identifier ) return response.status(403).json({ message: ErrorConstants.AUTH_403_MESSAGE, From 7b74fe07f23ff680f6b45d62f73e33c243edfd63 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Thu, 3 Feb 2022 05:19:06 -0500 Subject: [PATCH 54/72] feat: validation middleware for models - leverage class-validator to validate against entities. - retrieve errors and flatmap them to allow for a clean output back to the dashboard. --- src/middlewares/validator.middleware.ts | 35 +++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/middlewares/validator.middleware.ts diff --git a/src/middlewares/validator.middleware.ts b/src/middlewares/validator.middleware.ts new file mode 100644 index 00000000..309fe052 --- /dev/null +++ b/src/middlewares/validator.middleware.ts @@ -0,0 +1,35 @@ +import { Middleware } from "@decorators/express"; +import { plainToClass } from "class-transformer"; +import { validateOrReject } from "class-validator"; +import { Request, Response, NextFunction } from "express"; +import { ParamsDictionary } from "express-serve-static-core"; +import { ParsedQs } from "qs"; +import * as ErrorConstants from "@constants/error.constant"; + +export function Validator(model: any): any { + class ValidatorMiddleware implements Middleware { + async use( + request: Request< + ParamsDictionary, + any, + any, + ParsedQs, + Record + >, + response: Response>, + next: NextFunction + ): Promise { + await validateOrReject(plainToClass(model, request.body)) + .then(() => next()) + .catch((errors) => { + response.status(422).send({ + message: ErrorConstants.VALIDATION_422_MESSAGE, + errors: errors.flatMap((error: any) => + Object.values(error["constraints"]) + ) + }); + }); + } + } + return new ValidatorMiddleware(); +} From 59b16f2a079f50c976cea8965d1cb91b517cdadd Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Thu, 3 Feb 2022 10:25:53 -0500 Subject: [PATCH 55/72] fix: remove validation for account identifier --- src/models/account.model.ts | 10 ++++------ src/services/account.service.ts | 5 ++++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/models/account.model.ts b/src/models/account.model.ts index 8edc3706..016e2583 100644 --- a/src/models/account.model.ts +++ b/src/models/account.model.ts @@ -1,21 +1,19 @@ import { Column, Entity, PrimaryGeneratedColumn } from "typeorm"; import { compareSync } from "bcrypt"; import { - IsDate, IsEmail, IsEnum, - IsInt, + IsOptional, IsPhoneNumber, IsString, Length } from "class-validator"; import { UserType } from "@constants/general.constant"; -import { classToPlain, Exclude } from "class-transformer"; +import { Exclude, instanceToPlain } from "class-transformer"; @Entity() class Account { @PrimaryGeneratedColumn() - @IsInt() readonly identifier: number; @Column({ nullable: false }) @@ -53,11 +51,11 @@ class Account { enum: UserType, default: UserType.Hacker }) + @IsOptional() @IsEnum(UserType) accountType: string; @Column("date", { nullable: false }) - @IsDate() birthDate: Date; @Column() @@ -65,7 +63,7 @@ class Account { phoneNumber: string; toJSON() { - return classToPlain(this); + return instanceToPlain(this); } /** diff --git a/src/services/account.service.ts b/src/services/account.service.ts index 0e76463c..d22f11e1 100644 --- a/src/services/account.service.ts +++ b/src/services/account.service.ts @@ -45,7 +45,10 @@ export class AccountService { }); } - public async updatePassword(identifier: number, password: string) { + public async updatePassword( + identifier: number, + password: string + ): Promise { return await this.accountRepository.update(identifier, { password: this.hashPassword(password) }); From 294d88dc63481ea070a23537e6c4aabe858b7b79 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Thu, 3 Feb 2022 10:39:57 -0500 Subject: [PATCH 56/72] fix(hacker.controller.ts): use nullability operator --- src/controllers/hacker.controller.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/controllers/hacker.controller.ts b/src/controllers/hacker.controller.ts index cadfa527..c56796ea 100644 --- a/src/controllers/hacker.controller.ts +++ b/src/controllers/hacker.controller.ts @@ -144,8 +144,9 @@ export class HackerController { const hacker: | Hacker | undefined = await this.hackerService.findByIdentifier(identifier); + const resume = await this.storageService.download( - hacker?.application.general.URL.resume + hacker!.application.general.URL.resume ); resume From 8acb79e0860ed5b3ca5bec9e12496a4421675bdf Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Thu, 3 Feb 2022 10:59:45 -0500 Subject: [PATCH 57/72] feat: add ability for partial types to be validated --- src/middlewares/validator.middleware.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/middlewares/validator.middleware.ts b/src/middlewares/validator.middleware.ts index 309fe052..2fc9a50b 100644 --- a/src/middlewares/validator.middleware.ts +++ b/src/middlewares/validator.middleware.ts @@ -19,7 +19,12 @@ export function Validator(model: any): any { response: Response>, next: NextFunction ): Promise { - await validateOrReject(plainToClass(model, request.body)) + await validateOrReject( + plainToClass(model, request.body), + request.method === "PATCH" + ? { skipMissingProperties: true } + : {} + ) .then(() => next()) .catch((errors) => { response.status(422).send({ From 4ea22e7bc153960f85b1d7e4d50884b90210f140 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Thu, 3 Feb 2022 11:06:22 -0500 Subject: [PATCH 58/72] feat: add validation on post and patch routes --- src/controllers/account.controller.ts | 18 ++++++++---------- src/controllers/hacker.controller.ts | 6 ++++-- src/controllers/sponsor.controller.ts | 7 +++++-- src/controllers/team.controller.ts | 7 +++++-- src/controllers/travel.controller.ts | 10 +++++++--- 5 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/controllers/account.controller.ts b/src/controllers/account.controller.ts index 03a21147..5c3e63e4 100644 --- a/src/controllers/account.controller.ts +++ b/src/controllers/account.controller.ts @@ -24,6 +24,7 @@ import { AccountConfirmationService } from "@services/account-confirmation.servi import { EmailService } from "@services/email.service"; import * as GeneralConstants from "@constants/general.constant"; import { join } from "path"; +import { Validator } from "@app/middlewares/validator.middleware"; @autoInjectable() @Controller("/account") @@ -112,7 +113,7 @@ export class AccountController { }); } - @Post("/") + @Post("/", [Validator(Account)]) async create( @Response() response: ExpressResponse, @Body() account: Account @@ -155,14 +156,10 @@ export class AccountController { ); } - return result - ? response.status(200).send({ - message: SuccessConstants.ACCOUNT_CREATE, - data: result - }) - : response.status(422).send({ - message: ErrorConstants.ACCOUNT_DUPLICATE_422_MESSAGE - }); + return response.status(200).send({ + message: SuccessConstants.ACCOUNT_CREATE, + data: result + }); } // (Add middleware for sendConfirmAccountEmail and update database confirmed: false, email: newEmail) @@ -171,7 +168,8 @@ export class AccountController { EnsureAuthorization([ AuthorizationLevel.Staff, AuthorizationLevel.Account - ]) + ]), + Validator(Account) ]) async update( @Response() response: ExpressResponse, diff --git a/src/controllers/hacker.controller.ts b/src/controllers/hacker.controller.ts index c56796ea..2b1da149 100644 --- a/src/controllers/hacker.controller.ts +++ b/src/controllers/hacker.controller.ts @@ -22,6 +22,7 @@ import { } from "express"; import { StorageService } from "@services/storage.service"; import { upload } from "@middlewares/multer.middleware"; +import { Validator } from "@app/middlewares/validator.middleware"; @autoInjectable() @Controller("/hacker") @@ -84,7 +85,7 @@ export class HackerController { }); } - @Post("/", [EnsureAuthenticated]) + @Post("/", [EnsureAuthenticated, Validator(Hacker)]) async create( @Response() response: ExpressResponse, @Body() hacker: Hacker @@ -108,7 +109,8 @@ export class HackerController { EnsureAuthorization([ AuthorizationLevel.Staff, AuthorizationLevel.Hacker - ]) + ]), + Validator(Hacker) ]) async update( @Response() response: ExpressResponse, diff --git a/src/controllers/sponsor.controller.ts b/src/controllers/sponsor.controller.ts index 8e42e530..4f9a5581 100644 --- a/src/controllers/sponsor.controller.ts +++ b/src/controllers/sponsor.controller.ts @@ -16,6 +16,7 @@ import { SponsorService } from "@services/sponsor.service"; import { Response as ExpressResponse } from "express"; import * as SuccessConstants from "@constants/success.constant"; import * as ErrorConstants from "@constants/error.constant"; +import { Validator } from "@app/middlewares/validator.middleware"; @autoInjectable() @Controller("/sponsor") @@ -51,7 +52,8 @@ export class SponsorController { @Post("/", [ EnsureAuthenticated, - EnsureAuthorization([AuthorizationLevel.Staff]) + EnsureAuthorization([AuthorizationLevel.Staff]), + Validator(Sponsor) ]) async create( @Response() response: ExpressResponse, @@ -74,7 +76,8 @@ export class SponsorController { EnsureAuthorization([ AuthorizationLevel.Staff, AuthorizationLevel.Sponsor - ]) + ]), + Validator(Sponsor) ]) async update( @Response() response: ExpressResponse, diff --git a/src/controllers/team.controller.ts b/src/controllers/team.controller.ts index e2630a38..c577070d 100644 --- a/src/controllers/team.controller.ts +++ b/src/controllers/team.controller.ts @@ -22,6 +22,7 @@ import * as SuccessConstants from "@constants/success.constant"; import * as ErrorConstants from "@constants/error.constant"; import { HackerService } from "@services/hacker.service"; import Hacker from "@models/hacker.model"; +import { Validator } from "@app/middlewares/validator.middleware"; interface MemberInfo { firstName: string; @@ -86,7 +87,8 @@ export class TeamController { EnsureAuthorization([ AuthorizationLevel.Staff, AuthorizationLevel.Hacker - ]) + ]), + Validator(Team) ]) async create(@Response() response: ExpressResponse, @Body() team: Team) { const result = await this.teamService.save(team); @@ -112,7 +114,8 @@ export class TeamController { EnsureAuthorization([ AuthorizationLevel.Staff, AuthorizationLevel.Hacker - ]) + ]), + Validator(Team) ]) async update( @Response() response: ExpressResponse, diff --git a/src/controllers/travel.controller.ts b/src/controllers/travel.controller.ts index bee311bd..d3ae549d 100644 --- a/src/controllers/travel.controller.ts +++ b/src/controllers/travel.controller.ts @@ -19,6 +19,7 @@ import { } from "express"; import * as SuccessConstants from "@constants/success.constant"; import * as ErrorConstants from "@constants/error.constant"; +import { Validator } from "@app/middlewares/validator.middleware"; @autoInjectable() @Controller("/travel") @@ -55,7 +56,8 @@ export class TravelController { EnsureAuthorization([ AuthorizationLevel.Staff, AuthorizationLevel.Hacker - ]) + ]), + Validator(Travel) ]) async create( @Response() response: ExpressResponse, @@ -82,7 +84,8 @@ export class TravelController { @Patch("/:identifier", [ EnsureAuthenticated, - EnsureAuthorization([AuthorizationLevel.Staff]) + EnsureAuthorization([AuthorizationLevel.Staff]), + Validator(Travel) ]) async updateByStaff( @Response() response: ExpressResponse, @@ -106,7 +109,8 @@ export class TravelController { @Patch("/", [ EnsureAuthenticated, - EnsureAuthorization([AuthorizationLevel.Hacker]) + EnsureAuthorization([AuthorizationLevel.Hacker]), + Validator(Travel) ]) async update( @Request() request: ExpressRequest, From 956c97eef8bf01c99ff55350a3e4d661229763cf Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Thu, 3 Feb 2022 12:17:15 -0500 Subject: [PATCH 59/72] feat(email.service.ts): add sendgrid transport for production --- package-lock.json | 1126 ++++++++++++++++++++++++--------- package.json | 2 + src/services/email.service.ts | 23 +- 3 files changed, 838 insertions(+), 313 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7c25c499..23c6e65f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,9 +25,9 @@ "jsonwebtoken": "^8.5.1", "memory-cache": "^0.2.0", "mjml": "^4.11.0", - "mongoose": "^5.13.3", "multer": "^1.4.2", "nodemailer": "^6.7.2", + "nodemailer-sendgrid": "^1.0.3", "passport": "^0.4.1", "passport-local": "^1.0.0", "pg": "^8.7.1", @@ -53,6 +53,7 @@ "@types/mjml": "^4.7.0", "@types/multer": "^1.4.7", "@types/nodemailer": "^6.4.4", + "@types/nodemailer-sendgrid": "^1.0.0", "@types/passport": "^1.0.7", "@types/passport-local": "^1.0.34", "@types/qrcode": "^1.4.2", @@ -1348,6 +1349,107 @@ "node": ">= 8" } }, + "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/helpers/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/@sendgrid/helpers/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/@sendgrid/helpers/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/@sendgrid/helpers/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "node_modules/@sendgrid/helpers/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": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@sendgrid/helpers/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "engines": { + "node": ">=4" + } + }, + "node_modules/@sendgrid/helpers/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/@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/@sindresorhus/is": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", @@ -1465,19 +1567,10 @@ "@types/node": "*" } }, - "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==", - "dev": true + "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==" }, "node_modules/@types/connect": { "version": "3.4.35", @@ -1653,15 +1746,6 @@ "integrity": "sha512-k5IRafi93tyZBGF+0BTrcBDvG47OueI+Q7TC4V4UjGQn0AMVvL3Y+S26QF/UHMmMJW5r1hxLyv3StX2/+FatFg==", "dev": true }, - "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/multer": { "version": "1.4.7", "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.7.tgz", @@ -1685,6 +1769,15 @@ "@types/node": "*" } }, + "node_modules/@types/nodemailer-sendgrid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/nodemailer-sendgrid/-/nodemailer-sendgrid-1.0.0.tgz", + "integrity": "sha512-7D3Ddd7vN4tTDNGUkv31zH+2Wr6a37V0ryk0v5dyyBow/NA5+Jx5L3HvN1xq2ArZ2DbL2/z0tR9rfJtnJZK/Gw==", + "dev": true, + "dependencies": { + "@types/nodemailer": "*" + } + }, "node_modules/@types/passport": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.7.tgz", @@ -1746,7 +1839,6 @@ "version": "2.48.7", "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.7.tgz", "integrity": "sha512-GWP9AZW7foLd4YQxyFZDBepl0lPsWLMEXDZUjQ/c1gqVPDPECrRZyEzuhJdnPWioFCq3Tv0qoGpMD6U+ygd4ZA==", - "dev": true, "dependencies": { "@types/caseless": "*", "@types/node": "*", @@ -1802,8 +1894,7 @@ "node_modules/@types/tough-cookie": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.1.tgz", - "integrity": "sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg==", - "dev": true + "integrity": "sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg==" }, "node_modules/@types/validator": { "version": "13.7.1", @@ -2230,7 +2321,6 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -2430,6 +2520,22 @@ "node": ">=8" } }, + "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": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "engines": { + "node": ">=0.8" + } + }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -2455,8 +2561,7 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "node_modules/at-least-node": { "version": "1.0.0", @@ -2467,6 +2572,19 @@ "node": ">= 4.0.0" } }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, "node_modules/babel-jest": { "version": "27.4.5", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.4.5.tgz", @@ -2621,6 +2739,14 @@ "node": ">= 10.0.0" } }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, "node_modules/bignumber.js": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", @@ -2641,6 +2767,8 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", + "optional": true, + "peer": true, "dependencies": { "readable-stream": "^2.3.5", "safe-buffer": "^5.1.1" @@ -2650,6 +2778,8 @@ "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "optional": true, + "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -2663,21 +2793,20 @@ "node_modules/bl/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==" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "optional": true, + "peer": true }, "node_modules/bl/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==", + "optional": true, + "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } }, - "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/body-parser": { "version": "1.19.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.1.tgz", @@ -2842,6 +2971,8 @@ "version": "1.1.6", "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==", + "optional": true, + "peer": true, "engines": { "node": ">=0.6.19" } @@ -3023,6 +3154,11 @@ "url": "https://opencollective.com/browserslist" } }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -3295,7 +3431,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -3586,6 +3721,17 @@ "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", "dev": true }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/data-urls": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", @@ -3691,7 +3837,6 @@ "version": "4.2.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -3706,7 +3851,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true, "engines": { "node": ">=0.4.0" } @@ -3720,6 +3864,8 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", + "optional": true, + "peer": true, "engines": { "node": ">=0.10" } @@ -3949,6 +4095,15 @@ "xtend": "^4.0.0" } }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "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", @@ -4673,11 +4828,18 @@ "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": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "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==", - "dev": true + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-diff": { "version": "1.2.0", @@ -4704,8 +4866,7 @@ "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==", - "dev": true + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "node_modules/fast-levenshtein": { "version": "2.0.6", @@ -4824,11 +4985,18 @@ "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "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==", - "dev": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", @@ -5037,6 +5205,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, "node_modules/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -5240,6 +5416,27 @@ "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": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "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", @@ -5425,6 +5622,20 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, "node_modules/https-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", @@ -5756,6 +5967,11 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, "node_modules/istanbul-lib-coverage": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", @@ -6531,6 +6747,11 @@ "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": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, "node_modules/jsdom": { "version": "16.7.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", @@ -6710,11 +6931,15 @@ "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", "dev": true }, + "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==", - "dev": true + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -6722,6 +6947,11 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "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": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, "node_modules/json5": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", @@ -6794,6 +7024,20 @@ "semver": "bin/semver" } }, + "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/juice": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/juice/-/juice-7.0.0.tgz", @@ -6839,11 +7083,6 @@ "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/keygrip": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", @@ -7105,7 +7344,8 @@ "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 + "optional": true, + "peer": true }, "node_modules/mensch": { "version": "0.3.4", @@ -7653,6 +7893,8 @@ "version": "3.7.3", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.3.tgz", "integrity": "sha512-Psm+g3/wHXhjBEktkxXsFMZvd3nemI0r3IPsE0bU+4//PnvNWKkzhZcEsbPcYiWqe8XqXJJEg4Tgtr7Raw67Yw==", + "optional": true, + "peer": true, "dependencies": { "bl": "^2.2.1", "bson": "^1.1.4", @@ -7691,6 +7933,8 @@ "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==", + "optional": true, + "peer": true, "dependencies": { "require-at": "^1.0.6" }, @@ -7698,88 +7942,6 @@ "node": ">=4" } }, - "node_modules/mongoose": { - "version": "5.13.13", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.13.tgz", - "integrity": "sha512-M55tpCr/p5i6vdJ54nm4MG6/7SKV4JqlWnqbx6yCRuAuW05CZ7u+gNuHVPQVF9dZ59ALXjOtPEUl+OXklAa7ng==", - "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/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/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "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.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -7884,6 +8046,14 @@ "node": ">=6.0.0" } }, + "node_modules/nodemailer-sendgrid": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/nodemailer-sendgrid/-/nodemailer-sendgrid-1.0.3.tgz", + "integrity": "sha512-To/veO2M4evjtv1XrY7BUgE+LDypgs/FBx4wOHb2UNTpvZhiARtvMaBI0685Yxkho0lIPJc4jS0cUE7v+XGNgg==", + "dependencies": { + "@sendgrid/mail": "^6.2.1" + } + }, "node_modules/nodemon": { "version": "2.0.15", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.15.tgz", @@ -8014,6 +8184,14 @@ "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", "dev": true }, + "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", @@ -8081,14 +8259,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "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", @@ -8287,6 +8457,11 @@ "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, "node_modules/pg": { "version": "8.7.1", "resolved": "https://registry.npmjs.org/pg/-/pg-8.7.1.tgz", @@ -8615,8 +8790,7 @@ "node_modules/psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" }, "node_modules/pstree.remy": { "version": "1.1.8", @@ -8647,7 +8821,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, "engines": { "node": ">=6" } @@ -8938,11 +9111,6 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" }, - "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", @@ -8987,10 +9155,85 @@ "node": ">= 0.10" } }, + "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/request/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/request/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/require-at": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/require-at/-/require-at-1.0.6.tgz", "integrity": "sha512-7i1auJbMUrXEAZCOQ0VNJgmcT2VOKPRl2YGJwgpHpC9CE91Mv4/4UYIUm4chGJaI381ZDq1JUicFii64Hapd8g==", + "optional": true, + "peer": true, "engines": { "node": ">=4" } @@ -9199,6 +9442,7 @@ "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", "optional": true, + "peer": true, "dependencies": { "sparse-bitfield": "^3.0.3" }, @@ -9384,11 +9628,6 @@ "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/sigmund": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", @@ -9439,11 +9678,6 @@ "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "node_modules/sliced": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", - "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" - }, "node_modules/slick": { "version": "1.12.2", "resolved": "https://registry.npmjs.org/slick/-/slick-1.12.2.tgz", @@ -9479,6 +9713,7 @@ "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", "optional": true, + "peer": true, "dependencies": { "memory-pager": "^1.0.2" } @@ -9497,6 +9732,30 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "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/stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", @@ -10233,6 +10492,22 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "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": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -10605,7 +10880,6 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, "dependencies": { "punycode": "^2.1.0" } @@ -10696,6 +10970,24 @@ "node": ">= 0.8" } }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "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": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, "node_modules/w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", @@ -12068,6 +12360,85 @@ "fastq": "^1.6.0" } }, + "@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" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "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" + } + } + } + }, + "@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" + } + }, "@sindresorhus/is": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", @@ -12176,19 +12547,10 @@ "@types/node": "*" } }, - "@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==", - "dev": true + "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==" }, "@types/connect": { "version": "3.4.35", @@ -12363,15 +12725,6 @@ "integrity": "sha512-k5IRafi93tyZBGF+0BTrcBDvG47OueI+Q7TC4V4UjGQn0AMVvL3Y+S26QF/UHMmMJW5r1hxLyv3StX2/+FatFg==", "dev": true }, - "@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/multer": { "version": "1.4.7", "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.7.tgz", @@ -12395,6 +12748,15 @@ "@types/node": "*" } }, + "@types/nodemailer-sendgrid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/nodemailer-sendgrid/-/nodemailer-sendgrid-1.0.0.tgz", + "integrity": "sha512-7D3Ddd7vN4tTDNGUkv31zH+2Wr6a37V0ryk0v5dyyBow/NA5+Jx5L3HvN1xq2ArZ2DbL2/z0tR9rfJtnJZK/Gw==", + "dev": true, + "requires": { + "@types/nodemailer": "*" + } + }, "@types/passport": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.7.tgz", @@ -12456,7 +12818,6 @@ "version": "2.48.7", "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.7.tgz", "integrity": "sha512-GWP9AZW7foLd4YQxyFZDBepl0lPsWLMEXDZUjQ/c1gqVPDPECrRZyEzuhJdnPWioFCq3Tv0qoGpMD6U+ygd4ZA==", - "dev": true, "requires": { "@types/caseless": "*", "@types/node": "*", @@ -12512,8 +12873,7 @@ "@types/tough-cookie": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.1.tgz", - "integrity": "sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg==", - "dev": true + "integrity": "sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg==" }, "@types/validator": { "version": "13.7.1", @@ -12796,7 +13156,6 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -12946,6 +13305,19 @@ "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" }, + "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": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, "astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -12968,8 +13340,7 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "at-least-node": { "version": "1.0.0", @@ -12977,6 +13348,16 @@ "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, "babel-jest": { "version": "27.4.5", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.4.5.tgz", @@ -13088,6 +13469,14 @@ "node-addon-api": "^3.1.0" } }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, "bignumber.js": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", @@ -13102,6 +13491,8 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", + "optional": true, + "peer": true, "requires": { "readable-stream": "^2.3.5", "safe-buffer": "^5.1.1" @@ -13111,6 +13502,8 @@ "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "optional": true, + "peer": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -13124,23 +13517,22 @@ "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==" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "optional": true, + "peer": true }, "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==", + "optional": true, + "peer": true, "requires": { "safe-buffer": "~5.1.0" } } } }, - "bluebird": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" - }, "body-parser": { "version": "1.19.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.1.tgz", @@ -13269,7 +13661,9 @@ "bson": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", - "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==" + "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==", + "optional": true, + "peer": true }, "buffer": { "version": "6.0.3", @@ -13401,6 +13795,11 @@ "integrity": "sha512-lSP16vcyC0FEy0R4ECc9duSPoKoZy+YkpGkue9G4D81OfPnliopaZrU10+qtPdT8PbGXad/PNx43TIQrOmJZSQ==", "dev": true }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -13622,7 +14021,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "requires": { "delayed-stream": "~1.0.0" } @@ -13868,6 +14266,14 @@ } } }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, "data-urls": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", @@ -13956,8 +14362,7 @@ "deepmerge": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" }, "defer-to-connect": { "version": "1.1.3", @@ -13968,8 +14373,7 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, "delegates": { "version": "1.0.0", @@ -13979,7 +14383,9 @@ "denque": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", - "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==" + "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", + "optional": true, + "peer": true }, "depd": { "version": "2.0.0", @@ -14156,6 +14562,15 @@ "xtend": "^4.0.0" } }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "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", @@ -14709,11 +15124,15 @@ "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": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, "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==", - "dev": true + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "fast-diff": { "version": "1.2.0", @@ -14737,8 +15156,7 @@ "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==", - "dev": true + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "fast-levenshtein": { "version": "2.0.6", @@ -14847,11 +15265,15 @@ "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, "form-data": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", - "dev": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", @@ -15001,6 +15423,14 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, "glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -15151,6 +15581,20 @@ "wordwrap": "^1.0.0" } }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "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", @@ -15286,6 +15730,16 @@ } } }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, "https-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", @@ -15516,6 +15970,11 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, "istanbul-lib-coverage": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", @@ -16130,6 +16589,11 @@ "esprima": "^4.0.0" } }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, "jsdom": { "version": "16.7.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", @@ -16262,11 +16726,15 @@ "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", "dev": true }, + "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==", - "dev": true + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -16274,6 +16742,11 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "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": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, "json5": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", @@ -16336,6 +16809,17 @@ } } }, + "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" + } + }, "juice": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/juice/-/juice-7.0.0.tgz", @@ -16374,11 +16858,6 @@ "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==" - }, "keygrip": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", @@ -16606,7 +17085,8 @@ "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 + "optional": true, + "peer": true }, "mensch": { "version": "0.3.4", @@ -17102,6 +17582,8 @@ "version": "3.7.3", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.3.tgz", "integrity": "sha512-Psm+g3/wHXhjBEktkxXsFMZvd3nemI0r3IPsE0bU+4//PnvNWKkzhZcEsbPcYiWqe8XqXJJEg4Tgtr7Raw67Yw==", + "optional": true, + "peer": true, "requires": { "bl": "^2.2.1", "bson": "^1.1.4", @@ -17115,83 +17597,14 @@ "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==", + "optional": true, + "peer": true, "requires": { "require-at": "^1.0.6" } } } }, - "mongoose": { - "version": "5.13.13", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.13.tgz", - "integrity": "sha512-M55tpCr/p5i6vdJ54nm4MG6/7SKV4JqlWnqbx6yCRuAuW05CZ7u+gNuHVPQVF9dZ59ALXjOtPEUl+OXklAa7ng==", - "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": { - "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": {} - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "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" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "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.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -17281,6 +17694,14 @@ "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.2.tgz", "integrity": "sha512-Dz7zVwlef4k5R71fdmxwR8Q39fiboGbu3xgswkzGwczUfjp873rVxt1O46+Fh0j1ORnAC6L9+heI8uUpO6DT7Q==" }, + "nodemailer-sendgrid": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/nodemailer-sendgrid/-/nodemailer-sendgrid-1.0.3.tgz", + "integrity": "sha512-To/veO2M4evjtv1XrY7BUgE+LDypgs/FBx4wOHb2UNTpvZhiARtvMaBI0685Yxkho0lIPJc4jS0cUE7v+XGNgg==", + "requires": { + "@sendgrid/mail": "^6.2.1" + } + }, "nodemon": { "version": "2.0.15", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.15.tgz", @@ -17375,6 +17796,11 @@ "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", "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", @@ -17424,11 +17850,6 @@ "mimic-fn": "^2.1.0" } }, - "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", @@ -17581,6 +18002,11 @@ "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, "pg": { "version": "8.7.1", "resolved": "https://registry.npmjs.org/pg/-/pg-8.7.1.tgz", @@ -17819,8 +18245,7 @@ "psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" }, "pstree.remy": { "version": "1.1.8", @@ -17850,8 +18275,7 @@ "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "pupa": { "version": "2.1.1", @@ -18065,11 +18489,6 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" }, - "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", @@ -18099,10 +18518,70 @@ "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=" }, + "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==" + }, + "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" + } + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } + } + }, "require-at": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/require-at/-/require-at-1.0.6.tgz", - "integrity": "sha512-7i1auJbMUrXEAZCOQ0VNJgmcT2VOKPRl2YGJwgpHpC9CE91Mv4/4UYIUm4chGJaI381ZDq1JUicFii64Hapd8g==" + "integrity": "sha512-7i1auJbMUrXEAZCOQ0VNJgmcT2VOKPRl2YGJwgpHpC9CE91Mv4/4UYIUm4chGJaI381ZDq1JUicFii64Hapd8g==", + "optional": true, + "peer": true }, "require-directory": { "version": "2.1.1", @@ -18239,6 +18718,7 @@ "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", "optional": true, + "peer": true, "requires": { "sparse-bitfield": "^3.0.3" } @@ -18385,11 +18865,6 @@ "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==" - }, "sigmund": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", @@ -18431,11 +18906,6 @@ "is-fullwidth-code-point": "^3.0.0" } }, - "sliced": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", - "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" - }, "slick": { "version": "1.12.2", "resolved": "https://registry.npmjs.org/slick/-/slick-1.12.2.tgz", @@ -18465,6 +18935,7 @@ "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", "optional": true, + "peer": true, "requires": { "memory-pager": "^1.0.2" } @@ -18480,6 +18951,22 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "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" + } + }, "stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", @@ -19025,6 +19512,19 @@ } } }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -19253,7 +19753,6 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, "requires": { "punycode": "^2.1.0" } @@ -19322,6 +19821,23 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "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": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + } + } + }, "w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", diff --git a/package.json b/package.json index 960223df..dbd8967c 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "mjml": "^4.11.0", "multer": "^1.4.2", "nodemailer": "^6.7.2", + "nodemailer-sendgrid": "^1.0.3", "passport": "^0.4.1", "passport-local": "^1.0.0", "pg": "^8.7.1", @@ -56,6 +57,7 @@ "@types/mjml": "^4.7.0", "@types/multer": "^1.4.7", "@types/nodemailer": "^6.4.4", + "@types/nodemailer-sendgrid": "^1.0.0", "@types/passport": "^1.0.7", "@types/passport-local": "^1.0.34", "@types/qrcode": "^1.4.2", diff --git a/src/services/email.service.ts b/src/services/email.service.ts index 88331608..2ac55ab0 100644 --- a/src/services/email.service.ts +++ b/src/services/email.service.ts @@ -4,20 +4,27 @@ import { createTransport } from "nodemailer"; import { compile } from "handlebars"; import mjml2html from "mjml"; import { LoggerService } from "@services/logger.service"; +import nodemailerSgTransport from "nodemailer-sendgrid"; @autoInjectable() export class EmailService { protected readonly mailer; constructor(private readonly loggerService: LoggerService) { - this.mailer = createTransport({ - host: this.getEmailAttribute("HOST"), - port: parseInt(this.getEmailAttribute("PORT")!), - auth: { - user: this.getEmailAttribute("USERNAME"), - pass: this.getEmailAttribute("PASSWORD") - } - }); + this.mailer = createTransport( + process.env.NODE_ENV !== "deployment" + ? { + host: this.getEmailAttribute("HOST"), + port: parseInt(this.getEmailAttribute("PORT")!), + auth: { + user: this.getEmailAttribute("USERNAME"), + pass: this.getEmailAttribute("PASSWORD") + } + } + : nodemailerSgTransport({ + apiKey: this.getEmailAttribute("SENDGRID_API_KEY")! + }) + ); this.mailer .verify() .catch((error) => From f4b0d01c9477815304755865b71e84bf60a378ab Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Thu, 3 Feb 2022 12:28:55 -0500 Subject: [PATCH 60/72] build(app.json): update heroku config to latest environment variables --- app.json | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/app.json b/app.json index 34439148..47f12558 100644 --- a/app.json +++ b/app.json @@ -4,17 +4,14 @@ "repository": "https://github.com/hackmcgill/hackerAPI", "keywords": ["node", "express", "mongo", "react", "hackathon"], "env": { - "FRONTEND_ADDRESS_DEPLOY": { + "FRONTEND_ADDRESS": { "description": "URL for application front end" }, - "DB_ADDRESS_DEPLOY": { - "description": "Connection string for MongoDB" + "TYPEORM_URL": { + "description": "Connection string for the database" }, - "DB_USER_DEPLOY": { - "description": "DB Username" - }, - "DB_PASS_DEPLOY": { - "description": "DB Password" + "TYPEORM_CONNECTION": { + "description": "Database type (Postgres, MySQL, SQLite, etc...)" }, "JWT_INVITE_SECRET": { "generator": "secret" @@ -25,13 +22,13 @@ "JWT_CONFIRM_ACC_SECRET": { "generator": "secret" }, - "SENDGRID_API_KEY": { + "EMAIL_SENDGRID_API_KEY": { "description": "Sendgrid API Key" }, "NO_REPLY_EMAIL": { - "description": "Noreply email address" + "description": "No reply email address" }, - "NO_REPLY_EMAIL": { + "BUCKET_NAME": { "description": "GCP Storage Bucket Name" }, "TYPE": { @@ -53,7 +50,7 @@ "description": "GCP Auth URI" }, "TOKEN_URI": { - "description": "GCP TOken URI" + "description": "GCP Token URI" }, "AUTH_PROVIDER_X509_CERT_URL": { "description": "GCP Provider Cert URL" From 319ab7cca6a92095d8369475d416ec91e5c0009b Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Thu, 3 Feb 2022 12:29:32 -0500 Subject: [PATCH 61/72] chore(.env.example): remove outdated example env --- .env.example | 55 ---------------------------------------------------- 1 file changed, 55 deletions(-) delete mode 100644 .env.example diff --git a/.env.example b/.env.example deleted file mode 100644 index 3767c1f4..00000000 --- a/.env.example +++ /dev/null @@ -1,55 +0,0 @@ -#The port on which to run the server -PORT= -#The address on which the server is being run: -ADDRESS= - -#front-end server -FRONTEND_ADDRESS_DEV=localhost:1337 -FRONTEND_ADDRESS_DEPLOY=app.mchacks.ca -FRONTEND_ADDRESS_BETA=develop--mchacks-dashboard.netlify.com - -#The info for the deployment database -DB_ADDRESS_DEPLOY= -DB_USER_DEPLOY= -DB_PASS_DEPLOY= - -#The info for the development database -DB_ADDRESS_DEV= -DB_USER_DEV= -DB_PASS_DEV= - -#The info for the test database -DB_ADDRESS_TEST= -DB_USER_TEST= -DB_PASS_TEST= - -#Secret key for the cookies -COOKIE_SECRET= - -#Secret key for the invite tokens -JWT_INVITE_SECRET= - -#Reset password secret -JWT_RESET_PWD_SECRET= - -#Secret key fo account confirmation token -JWT_CONFIRM_ACC_SECRET= - -#mail information -SENDGRID_API_KEY= -NO_REPLY_EMAIL= - -#Storage information -BUCKET_NAME= - -#Service account information (This is found in the json when you create a service account). -TYPE=service_account -PROJECT_ID= -PRIVATE_KEY_ID= -PRIVATE_KEY= -CLIENT_EMAIL= -CLIENT_ID= -AUTH_URI= -TOKEN_URI= -AUTH_PROVIDER_X509_CERT_URL= -CLIENT_X509_CERT_URL= From 3049e814ae153f1ffa4d6330646914ec4666d778 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Fri, 4 Feb 2022 16:45:01 -0500 Subject: [PATCH 62/72] feat: add settings model, controller, and service --- src/app.ts | 4 +- src/constants/success.constant.ts | 90 ++++++++++---------- src/controllers/setting.controller.ts | 90 ++++++++++++++++++++ src/controllers/settings.controller.ts | 24 ------ src/migrations/1643998687434-SeedSettings.ts | 40 +++++++++ src/models/setting.model.ts | 16 ++++ src/services/setting.service.ts | 37 ++++++++ 7 files changed, 231 insertions(+), 70 deletions(-) create mode 100644 src/controllers/setting.controller.ts delete mode 100644 src/controllers/settings.controller.ts create mode 100644 src/migrations/1643998687434-SeedSettings.ts create mode 100644 src/models/setting.model.ts create mode 100644 src/services/setting.service.ts diff --git a/src/app.ts b/src/app.ts index 9f1c248d..7fba53b4 100755 --- a/src/app.ts +++ b/src/app.ts @@ -14,7 +14,7 @@ import { AccountController } from "@controllers/account.controller"; import { AuthenticationController } from "@controllers/authentication.controller"; import { HackerController } from "@controllers/hacker.controller"; import { SearchController } from "@controllers/search.controller"; -import { SettingsController } from "@controllers/settings.controller"; +import { SettingController } from "@app/controllers/setting.controller"; import { SponsorController } from "@controllers/sponsor.controller"; import { TeamController } from "@controllers/team.controller"; import { TravelController } from "@controllers/travel.controller"; @@ -106,7 +106,7 @@ function useControllers(express: ExpressApplication): void { container.resolve(SponsorController), container.resolve(TravelController), container.resolve(SearchController), - container.resolve(SettingsController) + container.resolve(SettingController) ]); express.use("/api", router); } diff --git a/src/constants/success.constant.ts b/src/constants/success.constant.ts index 03174aef..4c194b23 100644 --- a/src/constants/success.constant.ts +++ b/src/constants/success.constant.ts @@ -37,6 +37,7 @@ const SEARCH_NO_RESULTS = "Query search successful. No results found."; const SETTINGS_PATCH = "Settings update successful."; const SETTINGS_GET = "Settings get successful."; +const SETTINGS_POST = "Settings create successful."; const SPONSOR_GET_BY_ID = "Sponsor found by id."; const SPONSOR_READ = "Sponsor retrieval successful."; @@ -54,48 +55,49 @@ const VOLUNTEER_GET_BY_ID = "Volunteer found by id"; const VOLUNTEER_CREATE = "Volunteer creation successful."; export { - ACCOUNT_GET_BY_EMAIL, - ACCOUNT_GET_BY_ID, - ACCOUNT_CREATE, - ACCOUNT_UPDATE, - ACCOUNT_INVITE, - ACCOUNT_GET_INVITES, - ACCOUNT_READ, - AUTH_LOGIN, - AUTH_LOGOUT, - AUTH_SEND_RESET_EMAIL, - AUTH_RESET_PASSWORD, - AUTH_CONFIRM_ACCOUNT, - AUTH_GET_ROLE_BINDINGS, - AUTH_SEND_CONFIRMATION_EMAIL, - AUTH_GET_ROLES, - HACKER_GET_BY_ID, - HACKER_READ, - HACKER_CREATE, - HACKER_UPDATE, - HACKER_UPDATE_BATCH, - HACKER_SENT_WEEK_OF, - HACKER_SENT_DAY_OF, - RESUME_UPLOAD, - RESUME_DOWNLOAD, - TRAVEL_READ, - TRAVEL_CREATE, - TRAVEL_UPDATE, - ROLE_CREATE, - SEARCH_QUERY, - SEARCH_NO_RESULTS, - SETTINGS_GET, - SETTINGS_PATCH, - SPONSOR_GET_BY_ID, - SPONSOR_CREATE, - SPONSOR_READ, - SPONSOR_UPDATE, - TEAM_GET_BY_ID, - TEAM_CREATE, - TEAM_JOIN, - TEAM_UPDATE, - TEAM_READ, - TEAM_HACKER_LEAVE, - VOLUNTEER_GET_BY_ID, - VOLUNTEER_CREATE, + ACCOUNT_GET_BY_EMAIL, + ACCOUNT_GET_BY_ID, + ACCOUNT_CREATE, + ACCOUNT_UPDATE, + ACCOUNT_INVITE, + ACCOUNT_GET_INVITES, + ACCOUNT_READ, + AUTH_LOGIN, + AUTH_LOGOUT, + AUTH_SEND_RESET_EMAIL, + AUTH_RESET_PASSWORD, + AUTH_CONFIRM_ACCOUNT, + AUTH_GET_ROLE_BINDINGS, + AUTH_SEND_CONFIRMATION_EMAIL, + AUTH_GET_ROLES, + HACKER_GET_BY_ID, + HACKER_READ, + HACKER_CREATE, + HACKER_UPDATE, + HACKER_UPDATE_BATCH, + HACKER_SENT_WEEK_OF, + HACKER_SENT_DAY_OF, + RESUME_UPLOAD, + RESUME_DOWNLOAD, + TRAVEL_READ, + TRAVEL_CREATE, + TRAVEL_UPDATE, + ROLE_CREATE, + SEARCH_QUERY, + SEARCH_NO_RESULTS, + SETTINGS_GET, + SETTINGS_PATCH, + SETTINGS_POST, + SPONSOR_GET_BY_ID, + SPONSOR_CREATE, + SPONSOR_READ, + SPONSOR_UPDATE, + TEAM_GET_BY_ID, + TEAM_CREATE, + TEAM_JOIN, + TEAM_UPDATE, + TEAM_READ, + TEAM_HACKER_LEAVE, + VOLUNTEER_GET_BY_ID, + VOLUNTEER_CREATE }; diff --git a/src/controllers/setting.controller.ts b/src/controllers/setting.controller.ts new file mode 100644 index 00000000..4fb9c137 --- /dev/null +++ b/src/controllers/setting.controller.ts @@ -0,0 +1,90 @@ +import { + Body, + Controller, + Get, + Params, + Patch, + Post, + Response +} from "@decorators/express"; +import { Response as ExpressResponse } from "express"; +import * as SuccessConstants from "@constants/success.constant"; +import * as ErrorConstants from "@constants/error.constant"; +import { SettingService } from "@app/services/setting.service"; +import { autoInjectable } from "tsyringe"; +import { EnsureAuthenticated } from "@app/middlewares/authenticated.middleware"; +import { EnsureAuthorization } from "@app/middlewares/authorization.middleware"; +import { AuthorizationLevel } from "@app/constants/authorization-level.constant"; +import { Setting } from "@app/models/setting.model"; +import { Validator } from "@app/middlewares/validator.middleware"; + +@autoInjectable() +@Controller("/settings") +export class SettingController { + constructor(private readonly settingService: SettingService) {} + + @Get("/") + async getAll(@Response() response: ExpressResponse) { + response.status(200).send({ + message: SuccessConstants.SETTINGS_GET, + data: await this.settingService.find() + }); + } + + @Get("/:key") + async getByKey( + @Response() response: ExpressResponse, + @Params("key") key: string + ) { + response.status(200).send({ + message: SuccessConstants.SETTINGS_GET, + data: await this.settingService.findByKey(key) + }); + } + + @Post("/", [ + EnsureAuthenticated, + EnsureAuthorization([AuthorizationLevel.Staff]), + Validator(Setting) + ]) + async create( + @Response() response: ExpressResponse, + @Body() setting: Setting + ) { + const result: Setting = await this.settingService.save(setting); + + return result + ? response.status(200).send({ + message: SuccessConstants.SETTINGS_POST, + data: result + }) + : response.status(422).send({ + message: ErrorConstants.SETTINGS_422_MESSAGE + }); + } + + @Patch("/:identifier", [ + EnsureAuthenticated, + EnsureAuthorization([AuthorizationLevel.Staff]), + Validator(Setting) + ]) + async update( + @Response() response: ExpressResponse, + @Params("identifier") identifier: number, + @Body() setting: Partial + ) { + const result = await this.settingService.update(identifier, setting); + + return result + ? response.status(200).json({ + message: SuccessConstants.SETTINGS_PATCH, + data: result + }) + : response.status(404).json({ + message: ErrorConstants.SETTINGS_404_MESSAGE, + data: { + identifier: identifier + } + }); + } +} diff --git a/src/controllers/settings.controller.ts b/src/controllers/settings.controller.ts deleted file mode 100644 index 343e0533..00000000 --- a/src/controllers/settings.controller.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Controller, Get, Response } from "@decorators/express"; -import { Response as ExpressResponse } from "express"; -import * as SuccessConstants from "@constants/success.constant"; - -@Controller("/settings") -export class SettingsController { - @Get("/") - getAll(@Response() response: ExpressResponse) { - response.status(200).send({ - message: SuccessConstants.SETTINGS_GET, - data: { - openTime: Date.now().toString(), - closeTime: (Date.now() + 31540000000 + 2628000000).toString(), - confirmTime: ( - Date.now() + - 31540000000 + - 2628000000 + - 2628000000 - ).toString(), - isRemote: false - } - }); - } -} diff --git a/src/migrations/1643998687434-SeedSettings.ts b/src/migrations/1643998687434-SeedSettings.ts new file mode 100644 index 00000000..346b2814 --- /dev/null +++ b/src/migrations/1643998687434-SeedSettings.ts @@ -0,0 +1,40 @@ +import { getRepository, MigrationInterface, QueryRunner } from "typeorm"; + +export const SettingsSeed = [ + { + key: "APPLICATION_OPEN", + value: `${Date.now() - 100}` + }, + { + key: "APPLICATION_CLOSE", + value: `${Date.now() + 10000000000}` + }, + { + key: "APPLICATION_CONFIRM", + value: `${Date.now() + 100000000000000}` + }, + { + key: "IS_REMOTE", + value: `${false}` + }, + { + key: "SOCIAL_MEDIA_FACEBOOK", + value: "https://www.facebook.com/mcgillhacks" + }, + { + key: "SOCIAL_MEDIA_TWITTER", + value: "https://twitter.com/mcgillhacks" + }, + { + key: "SOCIAL_MEDIA_DISCORD", + value: "" + } +]; + +export class SeedSettings1643998687434 implements MigrationInterface { + public async up(_: QueryRunner): Promise { + await getRepository("setting").save(SettingsSeed); + } + + public async down(_: QueryRunner): Promise {} +} diff --git a/src/models/setting.model.ts b/src/models/setting.model.ts new file mode 100644 index 00000000..5edc7ac7 --- /dev/null +++ b/src/models/setting.model.ts @@ -0,0 +1,16 @@ +import { IsString } from "class-validator"; +import { Column, Entity, PrimaryGeneratedColumn } from "typeorm"; + +@Entity() +export class Setting { + @PrimaryGeneratedColumn() + identifier: number; + + @Column() + @IsString() + key: string; + + @Column() + @IsString() + value: string; +} diff --git a/src/services/setting.service.ts b/src/services/setting.service.ts new file mode 100644 index 00000000..ff75da99 --- /dev/null +++ b/src/services/setting.service.ts @@ -0,0 +1,37 @@ +import { Setting } from "@app/models/setting.model"; +import { getRepository, Repository, UpdateResult } from "typeorm"; + +export class SettingService { + private readonly settingRepository: Repository; + + constructor() { + this.settingRepository = getRepository(Setting); + } + + public async find(): Promise> { + return await this.settingRepository.find(); + } + + public async findByIdentifier( + identifier: number + ): Promise { + return await this.settingRepository.findOne(identifier); + } + + public async findByKey(key: string): Promise { + return await this.settingRepository.findOne({ + where: { key: key } + }); + } + + public async save(setting: Setting): Promise { + return await this.settingRepository.save(setting); + } + + public async update( + identifier: number, + setting: Partial + ): Promise { + return await this.settingRepository.update(identifier, setting); + } +} From 74d14a09cc9963b3099dcac9d50e0f35c2e215cb Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Sun, 20 Mar 2022 15:51:29 -0400 Subject: [PATCH 63/72] feat: implement account invites - add ability to query all account confirmation tokens. - add ability on account creation endpoint to have invite token to set role and auto-confirmation. - add ability to create invites with /invite endpoint. --- src/controllers/account.controller.ts | 90 ++++++++++++++++++-- src/services/account-confirmation.service.ts | 4 + 2 files changed, 88 insertions(+), 6 deletions(-) diff --git a/src/controllers/account.controller.ts b/src/controllers/account.controller.ts index 5c3e63e4..6309ced0 100644 --- a/src/controllers/account.controller.ts +++ b/src/controllers/account.controller.ts @@ -10,6 +10,7 @@ import { Body, Controller, Get, + Headers, Params, Patch, Post, @@ -24,7 +25,9 @@ import { AccountConfirmationService } from "@services/account-confirmation.servi import { EmailService } from "@services/email.service"; import * as GeneralConstants from "@constants/general.constant"; import { join } from "path"; -import { Validator } from "@app/middlewares/validator.middleware"; +import { Validator } from "@middlewares/validator.middleware"; +import AccountConfirmation from "@models/account-confirmation-token.model"; +import * as jwt from "jsonwebtoken"; @autoInjectable() @Controller("/account") @@ -116,8 +119,28 @@ export class AccountController { @Post("/", [Validator(Account)]) async create( @Response() response: ExpressResponse, - @Body() account: Account + @Body() account: Account, + @Headers("X-Invite-Token") token: string ) { + if (token) { + const data = jwt.verify( + token, + process.env.JWT_CONFIRM_ACC_SECRET! + ) as { + identifier: number; + }; + const result = await this.accountConfirmationService.findByIdentifier( + data.identifier + ); + + if (result) { + account.confirmed = true; + account.accountType = result.accountType; + + this.accountConfirmationService.delete(result.identifier); + } + } + const result: Account = await this.accountService.save(account); if (result) { @@ -193,8 +216,63 @@ export class AccountController { }); } - //TODO - Implement (gotInvites, invitedAccount) - // Invite functionality requires a special account confirmation token change where we verify if the token is valid - // without the account field, this was in the previous code (middleware files) - // to reimpl this functionality we should reference there. + @Post("/invite", [ + EnsureAuthenticated, + EnsureAuthorization([AuthorizationLevel.Staff]) + ]) + async createWithInvite( + @Response() response: ExpressResponse, + @Body("email") email: string, + @Body("accountType") accountType: string + ) { + const model = await this.accountConfirmationService.save({ + email: email, + accountType: accountType + }); + + await this.mailer.send( + { + to: model.email, + subject: "Account Confirmation Instructions", + html: join( + __dirname, + "../assets/email/AccountConfirmation.mjml" + ) + }, + { + link: this.accountConfirmationService.generateLink( + "confirm", + this.accountConfirmationService.generateToken( + model.identifier, + model.account!.identifier + ) + ) + }, + (error?: any) => { + if (error) + response.status(500).send({ + message: ErrorConstants.EMAIL_500_MESSAGE, + data: error + }); + } + ); + + return response.status(200).send({ + message: SuccessConstants.ACCOUNT_INVITE, + data: {} + }); + } + + @Get("/invites", [ + EnsureAuthenticated, + EnsureAuthorization([AuthorizationLevel.Staff]) + ]) + async getInvited(@Response() response: ExpressResponse) { + const result: Array = await this.accountConfirmationService.find(); + + response.status(200).json({ + message: SuccessConstants.ACCOUNT_READ, + data: result + }); + } } diff --git a/src/services/account-confirmation.service.ts b/src/services/account-confirmation.service.ts index 857a46f7..ef4a1193 100644 --- a/src/services/account-confirmation.service.ts +++ b/src/services/account-confirmation.service.ts @@ -14,6 +14,10 @@ export class AccountConfirmationService { this.accountConfirmationRepository = getRepository(AccountConfirmation); } + public async find(): Promise> { + return await this.accountConfirmationRepository.find(); + } + public async findByIdentifier( identifier: number ): Promise { From b8794056b6610548bfad3f90ba3d928fe6c440fa Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Sun, 20 Mar 2022 15:56:03 -0400 Subject: [PATCH 64/72] fix(account.controller.ts): make invite token optional --- src/controllers/account.controller.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/controllers/account.controller.ts b/src/controllers/account.controller.ts index 6309ced0..be8086f3 100644 --- a/src/controllers/account.controller.ts +++ b/src/controllers/account.controller.ts @@ -120,7 +120,7 @@ export class AccountController { async create( @Response() response: ExpressResponse, @Body() account: Account, - @Headers("X-Invite-Token") token: string + @Headers("X-Invite-Token") token?: string ) { if (token) { const data = jwt.verify( @@ -129,6 +129,7 @@ export class AccountController { ) as { identifier: number; }; + const result = await this.accountConfirmationService.findByIdentifier( data.identifier ); From 72674e598d7f6e11c3c14ac9b2be1b41aa834c3a Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Sun, 20 Mar 2022 22:54:16 -0400 Subject: [PATCH 65/72] feat: add settings seed, and placeholders in templating files - add placeholders for setting values in the e-mail template files - add default seed values for settings --- src/assets/email/Footer.mjml | 6 +++--- src/assets/email/HackingPolicy.mjml | 2 +- src/assets/email/SocialMedia.mjml | 8 ++++---- src/assets/email/Ticket.mjml | 10 +++++----- src/assets/email/Welcome.mjml | 10 +++++----- src/assets/email/statusEmail/Accepted.mjml | 1 + src/assets/email/statusEmail/Applied.mjml | 1 + src/assets/email/statusEmail/Checked-In.mjml | 2 +- src/assets/email/statusEmail/None.mjml | 2 +- src/migrations/1643998687434-SeedSettings.ts | 16 ++++++++++++++++ src/services/setting.service.ts | 2 +- 11 files changed, 39 insertions(+), 21 deletions(-) diff --git a/src/assets/email/Footer.mjml b/src/assets/email/Footer.mjml index 533a9d2d..fbc234d1 100644 --- a/src/assets/email/Footer.mjml +++ b/src/assets/email/Footer.mjml @@ -2,9 +2,9 @@ - - - + + + diff --git a/src/assets/email/HackingPolicy.mjml b/src/assets/email/HackingPolicy.mjml index 09d87f5d..5a7b282c 100644 --- a/src/assets/email/HackingPolicy.mjml +++ b/src/assets/email/HackingPolicy.mjml @@ -22,7 +22,7 @@ That being said, you're more than welcome to familiarize yourself with all the tech and tools you intend to build with beforehand! You can - check our Devpost + check our Devpost which will be updated soon with our available prizes to inspire ideas for your project! 🎁 diff --git a/src/assets/email/SocialMedia.mjml b/src/assets/email/SocialMedia.mjml index f28d163c..5e11513d 100644 --- a/src/assets/email/SocialMedia.mjml +++ b/src/assets/email/SocialMedia.mjml @@ -7,13 +7,13 @@ Follow us on - Facebook, - Twitter, + Facebook, + Twitter, and - Instagram + Instagram for important updates and news about McHacks! If you have any questions, feel free to reach out at - contact@mchacks.ca. + contact@mchacks.ca. diff --git a/src/assets/email/Ticket.mjml b/src/assets/email/Ticket.mjml index db5c9e78..898895e3 100644 --- a/src/assets/email/Ticket.mjml +++ b/src/assets/email/Ticket.mjml @@ -1,6 +1,6 @@ - McHacks 9: Important Information + McHacks {{HACKATHON_YEAR}}: Important Information @@ -10,7 +10,7 @@ - 4 Days Until McHacks 9! + 4 Days Until McHacks {{HACKATHON_YEAR}}! @@ -18,7 +18,7 @@ - McHacks 9 is this coming weekend and we're excited to spend an epic + McHacks {{HACKATHON_YEAR}} is this coming weekend and we're excited to spend an epic weekend with you hacking away! 🎉 @@ -43,7 +43,7 @@ During the hackathon, we'll be using both the FB group and the official - McHacks 9 Discord + McHacks {{HACKATHON_YEAR}} Discord Be sure to join the Discord so you're updated on everything going on as they happen! @@ -123,7 +123,7 @@ - McHacks 9 will be hosted at + McHacks {{HACKATHON_YEAR}} will be hosted at Theatre St James in the Old Port of Montreal. diff --git a/src/assets/email/Welcome.mjml b/src/assets/email/Welcome.mjml index 314f52fd..976efaaa 100644 --- a/src/assets/email/Welcome.mjml +++ b/src/assets/email/Welcome.mjml @@ -1,6 +1,6 @@ - McHacks 9: Important Information + McHacks {{HACKATHON_YEAR}}: Important Information @@ -10,7 +10,7 @@ - Welcome To McHacks 9! + Welcome To McHacks {{HACKATHON_YEAR}}! @@ -18,7 +18,7 @@ - McHacks 6 is finally here, and we're excited to spend an epic + McHacks {{HACKATHON_YEAR}} is finally here, and we're excited to spend an epic weekend with you hacking away! 🎉 @@ -37,13 +37,13 @@ Join our - Facebook group + Facebook group for announcements, to RSVP for workshops/activities, chat with other hackers, and form teams! During the hackathon, we'll be using both the FB group and the official - McHacks 9 Discord + McHacks {{HACKATHON_YEAR}} Discord Be sure to join the Discord so you're updated on everything going on as they happen! diff --git a/src/assets/email/statusEmail/Accepted.mjml b/src/assets/email/statusEmail/Accepted.mjml index a9a7d154..70bb7dff 100644 --- a/src/assets/email/statusEmail/Accepted.mjml +++ b/src/assets/email/statusEmail/Accepted.mjml @@ -23,6 +23,7 @@ Confirm your attendance on our hacker dashboard no later than January 25th at 11:59PM EST. + diff --git a/src/assets/email/statusEmail/Applied.mjml b/src/assets/email/statusEmail/Applied.mjml index 39ab11f6..cb9c7617 100644 --- a/src/assets/email/statusEmail/Applied.mjml +++ b/src/assets/email/statusEmail/Applied.mjml @@ -23,6 +23,7 @@ hacker dashboard until the deadline on December 26th at 12:00pm ET. + diff --git a/src/assets/email/statusEmail/Checked-In.mjml b/src/assets/email/statusEmail/Checked-In.mjml index d43ed5fa..a2c68840 100644 --- a/src/assets/email/statusEmail/Checked-In.mjml +++ b/src/assets/email/statusEmail/Checked-In.mjml @@ -20,7 +20,7 @@ Don't forget to join the McHacks participants - Facebook group + Facebook group and Discord for announcements, to chat with other hackers, ask questions, and form teams! diff --git a/src/assets/email/statusEmail/None.mjml b/src/assets/email/statusEmail/None.mjml index f1ba26eb..0ffb496d 100644 --- a/src/assets/email/statusEmail/None.mjml +++ b/src/assets/email/statusEmail/None.mjml @@ -23,7 +23,7 @@ Applications close on - December 26th at 12:00pm ET + December 26th at 12:00pm ET so be sure to click submit before then to be considered. diff --git a/src/migrations/1643998687434-SeedSettings.ts b/src/migrations/1643998687434-SeedSettings.ts index 346b2814..021498a9 100644 --- a/src/migrations/1643998687434-SeedSettings.ts +++ b/src/migrations/1643998687434-SeedSettings.ts @@ -1,6 +1,10 @@ import { getRepository, MigrationInterface, QueryRunner } from "typeorm"; export const SettingsSeed = [ + { + key: "HACKATHON_YEAR", + value: "10" + }, { key: "APPLICATION_OPEN", value: `${Date.now() - 100}` @@ -25,9 +29,21 @@ export const SettingsSeed = [ key: "SOCIAL_MEDIA_TWITTER", value: "https://twitter.com/mcgillhacks" }, + { + key: "SOCIAL_MEDIA_INSTAGRAM", + value: "https://instagram.com/mcgillhacks" + }, { key: "SOCIAL_MEDIA_DISCORD", value: "" + }, + { + key: "SOCIAL_MEDIA_EMAIL", + value: "contact@mchacks.ca" + }, + { + key: "SOCIAL_MEDIA_DEVPOST", + value: "mchacks.devpost.com" } ]; diff --git a/src/services/setting.service.ts b/src/services/setting.service.ts index ff75da99..e011aaba 100644 --- a/src/services/setting.service.ts +++ b/src/services/setting.service.ts @@ -1,4 +1,4 @@ -import { Setting } from "@app/models/setting.model"; +import { Setting } from "@models/setting.model"; import { getRepository, Repository, UpdateResult } from "typeorm"; export class SettingService { From 523ec9dc5ea6298922bc4c97311963ad6a4b3cd9 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Thu, 12 May 2022 19:50:28 -0400 Subject: [PATCH 66/72] refactor(search.service.ts): add interfaces to model filtering - Add Filter interface to model the basic search filter. - Add Operation enum to only allow a finite set of SQL operators to be used. - Remove older way of putting filter's in the query string. - Now we require them to be in the request body as an JSON array modeled after the Filter interface. --- src/controllers/search.controller.ts | 11 ++---- src/services/search.service.ts | 57 ++++++++++++++++++++-------- 2 files changed, 46 insertions(+), 22 deletions(-) diff --git a/src/controllers/search.controller.ts b/src/controllers/search.controller.ts index e2194980..1ae95300 100644 --- a/src/controllers/search.controller.ts +++ b/src/controllers/search.controller.ts @@ -1,9 +1,9 @@ -import { Controller, Get, Query, Response } from "@decorators/express"; +import { Body, Controller, Get, Query, Response } from "@decorators/express"; import { autoInjectable } from "tsyringe"; import { AuthorizationLevel } from "@constants/authorization-level.constant"; import { EnsureAuthenticated } from "@middlewares/authenticated.middleware"; import { EnsureAuthorization } from "@middlewares/authorization.middleware"; -import { SearchService } from "@services/search.service"; +import { Filter, SearchService } from "@services/search.service"; import { Response as ExpressResponse } from "express"; import * as SuccessConstants from "@constants/success.constant"; @@ -23,12 +23,9 @@ export class SearchController { async execute( @Response() response: ExpressResponse, @Query("model") model: string, - @Query("q") q: string + @Body("filters") filters: Array ) { - const result = await this.searchService.executeQuery( - model, - JSON.parse(q) - ); + const result = await this.searchService.executeQuery(model, filters); response.status(200).send({ message: diff --git a/src/services/search.service.ts b/src/services/search.service.ts index 1931e098..9fc5d432 100644 --- a/src/services/search.service.ts +++ b/src/services/search.service.ts @@ -1,6 +1,21 @@ import { singleton } from "tsyringe"; import { Connection, getConnection } from "typeorm"; +export interface Filter { + parameter: string; + operation: Operation; + value: string; +} + +enum Operation { + Equal = "=", + Like = "LIKE", + In = "IN", + Limit = "LIMIT", + Skip = "SKIP", + OrderBy = "ORDER BY" +} + @singleton() export class SearchService { private readonly connection: Connection; @@ -10,28 +25,40 @@ export class SearchService { public async executeQuery( model: string, - query: any + query: Array ): Promise> { const metadata = this.connection.getMetadata(model).target; - let builder = this.connection + const builder = this.connection .getRepository(metadata) .createQueryBuilder(model) .loadAllRelationIds(); - for (const element in query) { - const { - param, - value, - operation - }: { param: any; value: any; operation: string } = query[element]; - - //TODO: Ensure santitized input for operation and value? - builder = builder.andWhere(`${param} ${operation} :value`, { - value: value - }); - } + query.forEach(({ parameter, operation, value }: Filter) => { + switch (operation) { + case Operation.Equal: + case Operation.In: + builder.andWhere(`:parameter :operation :value`, { + parameter: parameter, + operation: operation, + value: value + }); + break; + case Operation.Like: + builder.andWhere(`:parameter :operation %:value%`, { + parameter: parameter, + operation: operation, + value: value + }); + break; + case Operation.Limit: + builder.skip(Number.parseInt(value)); + break; + case Operation.Skip: + builder.skip(Number.parseInt(value)); + break; + } + }); - //TODO: Implement limits (limit()), skipping (skip()), and sorting by ascending, descending (orderBy()). return builder.getMany(); } } From fde223df3199deb841f7dc48f1deb6a074d2765d Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Fri, 13 May 2022 10:32:10 -0400 Subject: [PATCH 67/72] build(Dockerfile): add containerization to improve onboarding --- .dockerignore | 4 ++++ .gitignore | 2 +- Dockerfile | 11 +++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..077cf2d9 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +node_modules/ +build/ +Dockerfile +docker-compose.yaml diff --git a/.gitignore b/.gitignore index 7adf4096..0039b493 100755 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,4 @@ certbot/ secret.yaml # compile output folder. -dist/ +build/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..02b14482 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM node:latest + +WORKDIR /application/ + +ADD . /application/ + +RUN npm ci + +EXPOSE ${PORT} + +CMD [ "npm", "run", "start" ] From 62edd8f9062c683f0d91675d042a38e4379380f0 Mon Sep 17 00:00:00 2001 From: Anmol Brar Date: Fri, 13 May 2022 13:22:35 -0400 Subject: [PATCH 68/72] refactor: remove old documentation and apidocs - Remove old Jekyll documentation. - Will be replaced in the hackmcgill/documentation repository. - Remove old api-docs. - Find a new library or just re-do them for the new API inside the controllers? --- docs/.DS_Store | Bin 6148 -> 0 bytes docs/CNAME | 1 - docs/_config.yml | 3 - docs/api/api_data.js | 4150 ----------------- docs/api/api_data.json | 4150 ----------------- docs/api/api_project.js | 1 - docs/api/api_project.json | 1 - docs/api/css/style.css | 569 --- .../fonts/glyphicons-halflings-regular.eot | Bin 20127 -> 0 bytes .../fonts/glyphicons-halflings-regular.svg | 288 -- .../fonts/glyphicons-halflings-regular.ttf | Bin 45404 -> 0 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 23424 -> 0 bytes .../fonts/glyphicons-halflings-regular.woff2 | Bin 18028 -> 0 bytes docs/api/img/favicon.ico | Bin 894 -> 0 bytes docs/api/index.html | 669 --- docs/api/locales/ca.js | 25 - docs/api/locales/cs.js | 25 - docs/api/locales/de.js | 25 - docs/api/locales/es.js | 25 - docs/api/locales/fr.js | 25 - docs/api/locales/it.js | 25 - docs/api/locales/locale.js | 51 - docs/api/locales/nl.js | 25 - docs/api/locales/pl.js | 25 - docs/api/locales/pt_br.js | 25 - docs/api/locales/ro.js | 25 - docs/api/locales/ru.js | 25 - docs/api/locales/tr.js | 25 - docs/api/locales/vi.js | 25 - docs/api/locales/zh.js | 25 - docs/api/locales/zh_cn.js | 25 - docs/api/main.js | 827 ---- docs/api/utils/handlebars_helper.js | 357 -- docs/api/utils/send_sample_request.js | 184 - docs/api/vendor/bootstrap.min.css | 6 - docs/api/vendor/bootstrap.min.js | 7 - docs/api/vendor/diff_match_patch.min.js | 49 - docs/api/vendor/handlebars.min.js | 29 - docs/api/vendor/jquery.min.js | 4 - docs/api/vendor/list.min.js | 2 - docs/api/vendor/lodash.custom.min.js | 41 - docs/api/vendor/path-to-regexp/LICENSE | 21 - docs/api/vendor/path-to-regexp/index.js | 204 - docs/api/vendor/polyfill.js | 96 - docs/api/vendor/prettify.css | 51 - docs/api/vendor/prettify/lang-Splus.js | 18 - docs/api/vendor/prettify/lang-aea.js | 18 - docs/api/vendor/prettify/lang-agc.js | 18 - docs/api/vendor/prettify/lang-apollo.js | 18 - docs/api/vendor/prettify/lang-basic.js | 18 - docs/api/vendor/prettify/lang-cbm.js | 18 - docs/api/vendor/prettify/lang-cl.js | 18 - docs/api/vendor/prettify/lang-clj.js | 17 - docs/api/vendor/prettify/lang-css.js | 18 - docs/api/vendor/prettify/lang-dart.js | 19 - docs/api/vendor/prettify/lang-el.js | 18 - docs/api/vendor/prettify/lang-erl.js | 18 - docs/api/vendor/prettify/lang-erlang.js | 18 - docs/api/vendor/prettify/lang-fs.js | 18 - docs/api/vendor/prettify/lang-go.js | 17 - docs/api/vendor/prettify/lang-hs.js | 18 - docs/api/vendor/prettify/lang-lasso.js | 19 - docs/api/vendor/prettify/lang-lassoscript.js | 19 - docs/api/vendor/prettify/lang-latex.js | 17 - docs/api/vendor/prettify/lang-lgt.js | 18 - docs/api/vendor/prettify/lang-lisp.js | 18 - docs/api/vendor/prettify/lang-ll.js | 17 - docs/api/vendor/prettify/lang-llvm.js | 17 - docs/api/vendor/prettify/lang-logtalk.js | 18 - docs/api/vendor/prettify/lang-ls.js | 19 - docs/api/vendor/prettify/lang-lsp.js | 18 - docs/api/vendor/prettify/lang-lua.js | 18 - docs/api/vendor/prettify/lang-matlab.js | 29 - docs/api/vendor/prettify/lang-ml.js | 18 - docs/api/vendor/prettify/lang-mumps.js | 18 - docs/api/vendor/prettify/lang-n.js | 19 - docs/api/vendor/prettify/lang-nemerle.js | 19 - docs/api/vendor/prettify/lang-pascal.js | 18 - docs/api/vendor/prettify/lang-proto.js | 17 - docs/api/vendor/prettify/lang-r.js | 18 - docs/api/vendor/prettify/lang-rd.js | 17 - docs/api/vendor/prettify/lang-rkt.js | 18 - docs/api/vendor/prettify/lang-rust.js | 20 - docs/api/vendor/prettify/lang-s.js | 18 - docs/api/vendor/prettify/lang-scala.js | 18 - docs/api/vendor/prettify/lang-scm.js | 18 - docs/api/vendor/prettify/lang-sql.js | 18 - docs/api/vendor/prettify/lang-ss.js | 18 - docs/api/vendor/prettify/lang-swift.js | 16 - docs/api/vendor/prettify/lang-tcl.js | 18 - docs/api/vendor/prettify/lang-tex.js | 17 - docs/api/vendor/prettify/lang-vb.js | 19 - docs/api/vendor/prettify/lang-vbs.js | 19 - docs/api/vendor/prettify/lang-vhd.js | 19 - docs/api/vendor/prettify/lang-vhdl.js | 19 - docs/api/vendor/prettify/lang-wiki.js | 18 - docs/api/vendor/prettify/lang-xq.js | 19 - docs/api/vendor/prettify/lang-xquery.js | 19 - docs/api/vendor/prettify/lang-yaml.js | 18 - docs/api/vendor/prettify/lang-yml.js | 18 - docs/api/vendor/prettify/prettify.css | 1 - docs/api/vendor/prettify/prettify.js | 46 - docs/api/vendor/prettify/run_prettify.js | 63 - docs/api/vendor/require.min.js | 37 - docs/api/vendor/semver.min.js | 1 - docs/api/vendor/webfontloader.js | 17 - docs/architecture.md | 236 - docs/deploy.md | 42 - docs/getting-started.md | 34 - docs/index.md | 100 - docs/standards.md | 432 -- 111 files changed, 14150 deletions(-) delete mode 100644 docs/.DS_Store delete mode 100644 docs/CNAME delete mode 100644 docs/_config.yml delete mode 100644 docs/api/api_data.js delete mode 100644 docs/api/api_data.json delete mode 100644 docs/api/api_project.js delete mode 100644 docs/api/api_project.json delete mode 100644 docs/api/css/style.css delete mode 100644 docs/api/fonts/glyphicons-halflings-regular.eot delete mode 100644 docs/api/fonts/glyphicons-halflings-regular.svg delete mode 100644 docs/api/fonts/glyphicons-halflings-regular.ttf delete mode 100644 docs/api/fonts/glyphicons-halflings-regular.woff delete mode 100644 docs/api/fonts/glyphicons-halflings-regular.woff2 delete mode 100644 docs/api/img/favicon.ico delete mode 100644 docs/api/index.html delete mode 100644 docs/api/locales/ca.js delete mode 100644 docs/api/locales/cs.js delete mode 100644 docs/api/locales/de.js delete mode 100644 docs/api/locales/es.js delete mode 100644 docs/api/locales/fr.js delete mode 100644 docs/api/locales/it.js delete mode 100644 docs/api/locales/locale.js delete mode 100644 docs/api/locales/nl.js delete mode 100644 docs/api/locales/pl.js delete mode 100644 docs/api/locales/pt_br.js delete mode 100644 docs/api/locales/ro.js delete mode 100644 docs/api/locales/ru.js delete mode 100644 docs/api/locales/tr.js delete mode 100644 docs/api/locales/vi.js delete mode 100644 docs/api/locales/zh.js delete mode 100644 docs/api/locales/zh_cn.js delete mode 100644 docs/api/main.js delete mode 100644 docs/api/utils/handlebars_helper.js delete mode 100755 docs/api/utils/send_sample_request.js delete mode 100644 docs/api/vendor/bootstrap.min.css delete mode 100644 docs/api/vendor/bootstrap.min.js delete mode 100644 docs/api/vendor/diff_match_patch.min.js delete mode 100644 docs/api/vendor/handlebars.min.js delete mode 100644 docs/api/vendor/jquery.min.js delete mode 100644 docs/api/vendor/list.min.js delete mode 100644 docs/api/vendor/lodash.custom.min.js delete mode 100644 docs/api/vendor/path-to-regexp/LICENSE delete mode 100644 docs/api/vendor/path-to-regexp/index.js delete mode 100644 docs/api/vendor/polyfill.js delete mode 100644 docs/api/vendor/prettify.css delete mode 100644 docs/api/vendor/prettify/lang-Splus.js delete mode 100644 docs/api/vendor/prettify/lang-aea.js delete mode 100644 docs/api/vendor/prettify/lang-agc.js delete mode 100644 docs/api/vendor/prettify/lang-apollo.js delete mode 100644 docs/api/vendor/prettify/lang-basic.js delete mode 100644 docs/api/vendor/prettify/lang-cbm.js delete mode 100644 docs/api/vendor/prettify/lang-cl.js delete mode 100644 docs/api/vendor/prettify/lang-clj.js delete mode 100644 docs/api/vendor/prettify/lang-css.js delete mode 100644 docs/api/vendor/prettify/lang-dart.js delete mode 100644 docs/api/vendor/prettify/lang-el.js delete mode 100644 docs/api/vendor/prettify/lang-erl.js delete mode 100644 docs/api/vendor/prettify/lang-erlang.js delete mode 100644 docs/api/vendor/prettify/lang-fs.js delete mode 100644 docs/api/vendor/prettify/lang-go.js delete mode 100644 docs/api/vendor/prettify/lang-hs.js delete mode 100644 docs/api/vendor/prettify/lang-lasso.js delete mode 100644 docs/api/vendor/prettify/lang-lassoscript.js delete mode 100644 docs/api/vendor/prettify/lang-latex.js delete mode 100644 docs/api/vendor/prettify/lang-lgt.js delete mode 100644 docs/api/vendor/prettify/lang-lisp.js delete mode 100644 docs/api/vendor/prettify/lang-ll.js delete mode 100644 docs/api/vendor/prettify/lang-llvm.js delete mode 100644 docs/api/vendor/prettify/lang-logtalk.js delete mode 100644 docs/api/vendor/prettify/lang-ls.js delete mode 100644 docs/api/vendor/prettify/lang-lsp.js delete mode 100644 docs/api/vendor/prettify/lang-lua.js delete mode 100644 docs/api/vendor/prettify/lang-matlab.js delete mode 100644 docs/api/vendor/prettify/lang-ml.js delete mode 100644 docs/api/vendor/prettify/lang-mumps.js delete mode 100644 docs/api/vendor/prettify/lang-n.js delete mode 100644 docs/api/vendor/prettify/lang-nemerle.js delete mode 100644 docs/api/vendor/prettify/lang-pascal.js delete mode 100644 docs/api/vendor/prettify/lang-proto.js delete mode 100644 docs/api/vendor/prettify/lang-r.js delete mode 100644 docs/api/vendor/prettify/lang-rd.js delete mode 100644 docs/api/vendor/prettify/lang-rkt.js delete mode 100644 docs/api/vendor/prettify/lang-rust.js delete mode 100644 docs/api/vendor/prettify/lang-s.js delete mode 100644 docs/api/vendor/prettify/lang-scala.js delete mode 100644 docs/api/vendor/prettify/lang-scm.js delete mode 100644 docs/api/vendor/prettify/lang-sql.js delete mode 100644 docs/api/vendor/prettify/lang-ss.js delete mode 100644 docs/api/vendor/prettify/lang-swift.js delete mode 100644 docs/api/vendor/prettify/lang-tcl.js delete mode 100644 docs/api/vendor/prettify/lang-tex.js delete mode 100644 docs/api/vendor/prettify/lang-vb.js delete mode 100644 docs/api/vendor/prettify/lang-vbs.js delete mode 100644 docs/api/vendor/prettify/lang-vhd.js delete mode 100644 docs/api/vendor/prettify/lang-vhdl.js delete mode 100644 docs/api/vendor/prettify/lang-wiki.js delete mode 100644 docs/api/vendor/prettify/lang-xq.js delete mode 100644 docs/api/vendor/prettify/lang-xquery.js delete mode 100644 docs/api/vendor/prettify/lang-yaml.js delete mode 100644 docs/api/vendor/prettify/lang-yml.js delete mode 100644 docs/api/vendor/prettify/prettify.css delete mode 100644 docs/api/vendor/prettify/prettify.js delete mode 100644 docs/api/vendor/prettify/run_prettify.js delete mode 100644 docs/api/vendor/require.min.js delete mode 100644 docs/api/vendor/semver.min.js delete mode 100644 docs/api/vendor/webfontloader.js delete mode 100644 docs/architecture.md delete mode 100755 docs/deploy.md delete mode 100644 docs/getting-started.md delete mode 100644 docs/index.md delete mode 100644 docs/standards.md diff --git a/docs/.DS_Store b/docs/.DS_Store deleted file mode 100644 index b719d60af08f4b4921cd7882a6993fb697de956c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKJxc>Y5Pf4(L@Z2cxxYa09~>bT*7*Z^IT2yailSh5oj+UOd?*QrU}YimVD|0K z&g`0dV7RJn+t=1}SKn}|_F>>GkqV>&sX!`_3Zw!P1+=6R zixcM@Q-M?<75G*_zYm3`+y#%$_UYhYEdY5=w}Er(CCEh`3>-vy7(mQKH=lk-PFbxEWG Hf1$u9sPrRT diff --git a/docs/CNAME b/docs/CNAME deleted file mode 100644 index a6b7a152..00000000 --- a/docs/CNAME +++ /dev/null @@ -1 +0,0 @@ -docs.mchacks.ca \ No newline at end of file diff --git a/docs/_config.yml b/docs/_config.yml deleted file mode 100644 index 63fabab9..00000000 --- a/docs/_config.yml +++ /dev/null @@ -1,3 +0,0 @@ -theme: jekyll-theme-cayman -url: https://hackerapi.mchacks.ca -repository: https://github.com/hackmcgill/hackerAPI diff --git a/docs/api/api_data.js b/docs/api/api_data.js deleted file mode 100644 index af1aa91e..00000000 --- a/docs/api/api_data.js +++ /dev/null @@ -1,4150 +0,0 @@ -define({ "api": [ - { - "type": "post", - "url": "/account/", - "title": "create a new account", - "name": "create", - "group": "Account", - "version": "0.0.8", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "String", - "optional": false, - "field": "firstName", - "description": "

First name of the account creator.

" - }, - { - "group": "body", - "type": "String", - "optional": false, - "field": "lastName", - "description": "

Last name of the account creator.

" - }, - { - "group": "body", - "type": "String", - "optional": false, - "field": "pronoun", - "description": "

the pronoun of the account creator.

" - }, - { - "group": "body", - "type": "String", - "optional": false, - "field": "email", - "description": "

Email of the account.

" - }, - { - "group": "body", - "type": "String", - "optional": false, - "field": "gender", - "description": "

Gender of the account creator.

" - }, - { - "group": "body", - "type": "String[]", - "optional": false, - "field": "dietaryRestrictions", - "description": "

Any dietary restrictions for the user. 'None' if there are no restrictions

" - }, - { - "group": "body", - "type": "String", - "optional": false, - "field": "password", - "description": "

The password of the account.

" - }, - { - "group": "body", - "type": "String", - "optional": false, - "field": "birthDate", - "description": "

a Date parsable string.

" - }, - { - "group": "body", - "type": "Number", - "optional": true, - "field": "phoneNumber", - "description": "

the user's phone number, represented as a string.

" - } - ], - "header": [ - { - "group": "header", - "type": "JWT", - "optional": true, - "field": "token", - "description": "

the user's invite token.

" - } - ] - }, - "examples": [ - { - "title": "Request-Example:", - "content": "{ \n \"firstName\": \"Theo\",\n \"lastName\":\"Klein\",\n \"pronoun\":\"he/him\",\n \"email\":\"theo@klein.com\",\n \"password\":\"hunter2\",\n \"phoneNumber\":1234567890,\n \"gender\":\"Male\",\n \"birthDate\":\"10/30/1997\"\n}", - "type": "json" - } - ] - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Account object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Account creation successful\", \n \"data\": {\n \"id\": ObjectId(\"5bff8b9f3274cf001bc71048\"),\n \t\"firstName\": \"Theo\",\n \"lastName\":\"Klein\",\n \"pronoun\":\"he/him\",\n \"email\":\"theo@klein.com\",\n \"phoneNumber\":1234567890,\n \t\"gender\":\"Male\",\n \"birthDate\":Date(\"10/30/1997\")\n }\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\n \"message\": \"Account already exists\", \n \"data\": {\n \"route\": \"/\"\n }\n}", - "type": "object" - } - ] - }, - "filename": "routes/api/account.js", - "groupTitle": "Account", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/account/" - } - ] - }, - { - "type": "get", - "url": "/account/:id", - "title": "gets information from an account with mongoid ':id'", - "name": "getAccount", - "group": "Account", - "version": "0.0.8", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "ObjectId", - "optional": false, - "field": "id", - "description": "

MongoId of an account

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Account object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Account found by user id\", \n \"data\": {\n \"id\": ObjectId(\"5bff8b9f3274cf001bc71048\"),\n \"firstName\": \"Theo\",\n \"lastName\":\"Klein\",\n \"pronoun\":\"he/him\",\n \"email\":\"theo@klein.com\",\n \"phoneNumber\":1234567890,\n \"gender\":\"Male\",\n \"birthDate\":Date(\"10/30/1997\")\n }\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Account not found\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/account.js", - "groupTitle": "Account", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/account/:id" - } - ] - }, - { - "type": "get", - "url": "/account/invite", - "title": "Get all of the invites.", - "name": "getAllInvites", - "group": "Account", - "version": "0.0.8", - "description": "

Get all of the invites that currently exist in the database.

", - "success": { - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Invite retrieval successful.\", \n \"data\": [{\n \"email\":\"abc@def.com\",\n \"accountType\":\"Hacker\"\n }]\n }", - "type": "object" - } - ] - }, - "filename": "routes/api/account.js", - "groupTitle": "Account", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/account/invite" - } - ] - }, - { - "type": "post", - "url": "/account/invite", - "title": "invites a user to create an account with the specified accountType", - "name": "inviteAccount", - "group": "Account", - "version": "0.0.8", - "description": "

sends link with token to be used with the account/create route

", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "String", - "optional": true, - "field": "email", - "description": "

email of the account to be created and where to send the link

" - }, - { - "group": "body", - "type": "String", - "optional": true, - "field": "accountType", - "description": "

the type of the account which the user can create, for sponsor this should specify tier as well

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Account object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Successfully invited user\", \n \"data\": {}\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

Error object

" - } - ] - }, - "examples": [ - { - "title": "Error-Response:", - "content": "{\n \"message\": \"Invalid Authentication\",\n \"data\": {\n \"route\": \"/invite\"\n }\n }", - "type": "object" - } - ] - }, - "filename": "routes/api/account.js", - "groupTitle": "Account", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/account/invite" - } - ] - }, - { - "type": "get", - "url": "/account/self", - "title": "get information about own account", - "name": "self", - "group": "Account", - "version": "0.0.8", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Account object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Account found by user email\", \n \"data\": {\n \t\"id\": ObjectId(\"5bff8b9f3274cf001bc71048\"),\n \t\"firstName\": \"Theo\",\n \"lastName\":\"Klein\",\n \"pronoun\":\"he/him\",\n \"email\":\"theo@klein.com\",\n \"phoneNumber\":1234567890,\n \t\"gender\":\"Male\",\n \"birthDate\":Date(\"10/30/1997\")\n }\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty object

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Account not found\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/account.js", - "groupTitle": "Account", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/account/self" - } - ] - }, - { - "type": "patch", - "url": "/account/:id", - "title": "update an account's information", - "name": "updateOneUser", - "group": "Account", - "version": "0.0.8", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "String", - "optional": true, - "field": "firstName", - "description": "

First name of the account creator.

" - }, - { - "group": "body", - "type": "String", - "optional": true, - "field": "lastName", - "description": "

Last name of the account creator.

" - }, - { - "group": "body", - "type": "String", - "optional": true, - "field": "pronoun", - "description": "

The pronoun of the account creator.

" - }, - { - "group": "body", - "type": "String", - "optional": true, - "field": "email", - "description": "

Email of the account.

" - }, - { - "group": "body", - "type": "String", - "optional": true, - "field": "gender", - "description": "

Gender of the account creator.

" - }, - { - "group": "body", - "type": "String", - "optional": true, - "field": "birthDate", - "description": "

A Date parsable string.

" - }, - { - "group": "body", - "type": "Number", - "optional": true, - "field": "phoneNumber", - "description": "

The user's phone number, represented as a string.

" - }, - { - "group": "body", - "type": "String[]", - "optional": true, - "field": "dietaryRestrictions", - "description": "

Any dietary restrictions for the user. 'None' if there are no restrictions

" - } - ] - }, - "examples": [ - { - "title": "Request-Example:", - "content": "{ \"gender\": \"Male\" }", - "type": "json" - } - ] - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Account object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Account update successful.\", \n \"data\": {\n \"id\": ObjectId(\"5bff8b9f3274cf001bc71048\"),\n \t\"firstName\": \"Theo\",\n \"lastName\":\"Klein\",\n \"pronoun\":\"he/him\",\n \"email\":\"theo@klein.com\",\n \"phoneNumber\":1234567890,\n \t\"gender\": \"Male\",\n \"birthDate\":Date(\"10/30/1997\")\n }\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Error while updating account\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/account.js", - "groupTitle": "Account", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/account/:id" - } - ] - }, - { - "type": "patch", - "url": "/auth/password/change", - "title": "change password for logged in user", - "name": "changePassword", - "group": "Authentication", - "version": "0.0.8", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "oldPassword", - "description": "

The current password of the user

" - }, - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "newPassword", - "description": "

The new password of the user

" - } - ] - }, - "examples": [ - { - "title": "Request-Example:", - "content": "{\n \"oldPassword\": \"password12345\",\n \"newPassword\": \"password123456\"\n}", - "type": "json" - } - ] - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\"message\": \"Successfully reset password\", \"data\": {}}", - "type": "json" - } - ] - }, - "permission": [ - { - "name": ": Must be logged in" - } - ], - "filename": "routes/api/auth.js", - "groupTitle": "Authentication", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/auth/password/change" - } - ] - }, - { - "type": "post", - "url": "/auth/confirm/:token", - "title": "confirm account using the JWT in :token", - "name": "confirmAccount", - "group": "Authentication", - "version": "0.0.8", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "JWT", - "description": "

for confirming the account

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\"message\": \"Successfully confirmed account\", \"data\": {}}", - "type": "json" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response:", - "content": "{\"message\": \"Invalid token for confirming account, \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/auth.js", - "groupTitle": "Authentication", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/auth/confirm/:token" - } - ] - }, - { - "type": "post", - "url": "/auth/password/forgot", - "title": "forgot password route", - "name": "forgotPassword", - "group": "Authentication", - "version": "0.0.8", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "email", - "description": "

the email address of the account

" - } - ] - }, - "examples": [ - { - "title": "Request-Example:", - "content": "{ \"email\": \"myemail@mchacks.ca\" }", - "type": "json" - } - ] - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\"message\": \"Sent reset email\", \"data\": {}}", - "type": "json" - } - ] - }, - "permission": [ - { - "name": ": public" - } - ], - "filename": "routes/api/auth.js", - "groupTitle": "Authentication", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/auth/password/forgot" - } - ] - }, - { - "type": "get", - "url": "/auth/rolebindings/:id", - "title": "retrieve rolebindings for a user given by their user id :id", - "name": "getRoleBindings", - "group": "Authentication", - "version": "0.0.8", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "ObjectId", - "optional": false, - "field": "id", - "description": "

MongoId of an account

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Rolebindings object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Successfully retrieved role bindings\",\n \"data\": {\n accountId:\"5beca4ab2e069a34f91697b2\"\n id:\"5beca4ae2e069a34f91698b1\"\n roles: [\n {\n _id:\"5beca4ab2e069a34f91697d9\",\n name:\"hacker\",\n routes: [\n {_id: \"5beca4ae2e069a34f9169852\", requestType: \"POST\", uri: \"/api/auth/login\"},\n {_id: \"5beca4ae2e069a34f9169851\", requestType: \"POST\", uri: \"/api/auth/logout\"},\n {_id: \"5beca4ae2e069a34f9169850\", requestType: \"GET\", uri: \"/api/auth/rolebindings/:self\"},\n {_id: \"5beca4ae2e069a34f916984f\", requestType: \"GET\", uri: \"/api/account/self\"},\n {_id: \"5beca4ae2e069a34f916984e\", requestType: \"GET\", uri: \"/api/account/:self\"},\n {_id: \"5beca4ae2e069a34f916984d\", requestType: \"PATCH\", uri: \"/api/account/:self\"},\n {_id: \"5beca4ae2e069a34f916984c\", requestType: \"POST\", uri: \"/api/hacker/\"},\n {_id: \"5beca4ae2e069a34f916984b\", requestType: \"GET\", uri: \"/api/hacker/:self\"},\n {_id: \"5beca4ae2e069a34f916984a\", requestType: \"GET\", uri: \"/api/hacker/:self/resume\"},\n {_id: \"5beca4ae2e069a34f9169849\", requestType: \"PATCH\", uri: \"/api/hacker/:self\"}\n ]\n }\n ]\n }\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Role Bindings not found\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/auth.js", - "groupTitle": "Authentication", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/auth/rolebindings/:id" - } - ] - }, - { - "type": "get", - "url": "/auth/roles", - "title": "get roles", - "name": "getRoles", - "description": "

get all roles that exist in the database

", - "group": "Authentication", - "version": "0.0.8", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\"message\": \"Sucessfully retrieved all roles\", \"data\":\n[{name: \"GodStaff\", routes: Array(27), id: \"5bee20ef3ca9dd4754382880\"},\n {name: \"Hacker\", routes: Array(10), id: \"5bee20ef3ca9dd4754382881\"},\n {name: \"Volunteer\", routes: Array(4), id: \"5bee20ef3ca9dd4754382882\"}]", - "type": "json" - } - ] - }, - "filename": "routes/api/auth.js", - "groupTitle": "Authentication", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/auth/roles" - } - ] - }, - { - "type": "post", - "url": "/auth/login", - "title": "login to the service", - "name": "login", - "group": "Authentication", - "version": "0.0.8", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "string", - "optional": false, - "field": "email", - "description": "

Account email

" - }, - { - "group": "Parameter", - "type": "string", - "optional": false, - "field": "password", - "description": "

Account password

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\"message\": \"Successfully logged in\", \"data\": {}}", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Invalid Authentication\", \"data\": {}}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": ": public" - } - ], - "filename": "routes/api/auth.js", - "groupTitle": "Authentication", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/auth/login" - } - ] - }, - { - "type": "get", - "url": "/auth/logout", - "title": "logout of service", - "name": "logout", - "group": "Authentication", - "version": "0.0.8", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\"message\": \"Successfully logged out\", \"data\": {}}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": ": public" - } - ], - "filename": "routes/api/auth.js", - "groupTitle": "Authentication", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/auth/logout" - } - ] - }, - { - "type": "get", - "url": "/auth/confirm/resend", - "title": "resend confirmation token", - "name": "resendConfirmAccount", - "group": "Authentication", - "version": "0.0.8", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\"message\": \"Successfully resent confirmation email\", \"data\": {}}", - "type": "json" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response:", - "content": " HTTP/1.1 422\n{\"message\": \"Account already confirmed\", \"data\": {}}", - "type": "json" - }, - { - "title": "Error-Response:", - "content": " HTTP/1.1 428\n{\"message\": \"Account confirmation token does not exist\", \"data\": {}}", - "type": "json" - } - ] - }, - "filename": "routes/api/auth.js", - "groupTitle": "Authentication", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/auth/confirm/resend" - } - ] - }, - { - "type": "post", - "url": "/auth/password/reset", - "title": "reset password", - "name": "resetPassword", - "group": "Authentication", - "version": "0.0.8", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "password", - "description": "

the password of the account

" - } - ] - }, - "examples": [ - { - "title": "Request-Example:", - "content": "{ \"password\": \"hunter2\" }", - "type": "json" - } - ] - }, - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Authentication", - "description": "

the token that was provided in the reset password email

" - } - ] - }, - "examples": [ - { - "title": "Header-Example:", - "content": "{\n \"X-Reset-Token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c\"\n}", - "type": "json" - } - ] - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\"message\": \"Successfully reset password\", \"data\": {}}", - "type": "json" - } - ] - }, - "permission": [ - { - "name": ": must have authentication token" - } - ], - "filename": "routes/api/auth.js", - "groupTitle": "Authentication", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/auth/password/reset" - } - ] - }, - { - "type": "patch", - "url": "/hacker/batchAccept/", - "title": "accept array of Hackers", - "name": "acceptHacker", - "group": "Hacker", - "version": "3.0.0", - "parameter": { - "fields": { - "body) {{ids: ObjectId[]}} Array of id(s": [ - { - "group": "body) {{ids: ObjectId[]}} Array of id(s", - "optional": false, - "field": "that", - "description": "

needed to be accepted

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

success_ids array and errors array. Errors array will contain a detailed error for why the batch update for a given ID did not work

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Hacker batch update successful.\",\n \"data\": {\n \"success_ids\": [\"id1\", \"id2\"]\n \"errors\": [{status: 404, message: \"ACCOUNT_NOT_FOUND\", account: null, hacker_id: \"id3\"}]\n }\n}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": "Administrator" - } - ], - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/batchAccept/" - } - ] - }, - { - "type": "patch", - "url": "/hacker/acceptEmail/:email", - "title": "accept a Hacker by email", - "name": "acceptHacker", - "group": "Hacker", - "version": "2.0.0", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Hacker object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Accepted\"\n }\n}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": "Administrator" - } - ], - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/acceptEmail/:email" - } - ] - }, - { - "type": "patch", - "url": "/hacker/accept/:id", - "title": "accept a Hacker", - "name": "acceptHacker", - "group": "Hacker", - "version": "2.0.0", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Hacker object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Accepted\"\n }\n}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": "Administrator" - } - ], - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/accept/:id" - } - ] - }, - { - "type": "patch", - "url": "/hacker/checkin/:id", - "title": "update a hacker's status to be 'Checked-in'. Note that the Hacker must eitehr be Accepted or Confirmed.", - "name": "checkinHacker", - "group": "Hacker", - "version": "0.0.9", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "string", - "optional": true, - "field": "status", - "description": "

Check-in status. "Checked-in"

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Hacker object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Checked-in\"\n }\n}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": "Administrator" - }, - { - "name": "Volunteer" - } - ], - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/checkin/:id" - } - ] - }, - { - "type": "post", - "url": "/hacker/", - "title": "create a new hacker", - "name": "createHacker", - "group": "Hacker", - "version": "0.0.8", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "MongoID", - "optional": false, - "field": "accountId", - "description": "

ObjectID of the respective account

" - }, - { - "group": "body", - "type": "String", - "optional": false, - "field": "school", - "description": "

Name of the school the hacker goes to

" - }, - { - "group": "body", - "type": "String", - "optional": false, - "field": "gender", - "description": "

Gender of the hacker

" - }, - { - "group": "body", - "type": "Number", - "optional": false, - "field": "travel", - "description": "

Whether the hacker requires a bus for transportation

" - }, - { - "group": "body", - "type": "String[]", - "optional": false, - "field": "ethnicity", - "description": "

the ethnicities of the hacker

" - }, - { - "group": "body", - "type": "String[]", - "optional": false, - "field": "major", - "description": "

the major of the hacker

" - }, - { - "group": "body", - "type": "Number", - "optional": false, - "field": "graduationYear", - "description": "

the graduation year of the hacker

" - }, - { - "group": "body", - "type": "Boolean", - "optional": false, - "field": "codeOfConduct", - "description": "

acceptance of the code of conduct

" - }, - { - "group": "body", - "type": "Json", - "optional": false, - "field": "application", - "description": "

The hacker's application. Resume and jobInterest fields are required.

" - } - ] - }, - "examples": [ - { - "title": "application: ", - "content": "{\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accommodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n}", - "type": "Json" - } - ] - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Hacker object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Hacker creation successful\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accommodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n}", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Error while creating hacker\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/" - } - ] - }, - { - "type": "get", - "url": "/hacker/:id", - "title": "get a hacker's information", - "name": "getHacker", - "group": "Hacker", - "version": "0.0.8", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "String", - "optional": false, - "field": "id", - "description": "

a hacker's unique mongoID

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Hacker object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Successfully retrieved hacker information\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"Applied\",\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accommodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n }\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "String", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "Object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Hacker not found\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/:id" - } - ] - }, - { - "type": "get", - "url": "/hacker/email/:email", - "title": "get a hacker's information", - "name": "getHacker", - "group": "Hacker", - "version": "0.0.8", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "String", - "optional": false, - "field": "email", - "description": "

a hacker's unique email

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Hacker object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Successfully retrieved hacker information\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"Applied\",\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accommodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n }\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "String", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "Object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Hacker not found\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/email/:email" - } - ] - }, - { - "type": "get", - "url": "/hacker/resume:id", - "title": "get the resume for a hacker.", - "name": "getHackerResume", - "group": "Hacker", - "version": "0.0.8", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "ObjectId", - "optional": false, - "field": "id", - "description": "

Hacker id

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "HTTP/1.1 200 OK\n{\n message: \"Downloaded resume\",\n data: {\n id: \"507f191e810c19729de860ea\",\n resume: [Buffer]\n }\n}", - "type": "json" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "String", - "optional": false, - "field": "message", - "description": "

"Resume does not exist"

" - } - ] - }, - "examples": [ - { - "title": "Error-Response:", - "content": "HTTP/1.1 404\n{\n message: \"Resume not found\",\n data: {}\n}", - "type": "json" - } - ] - }, - "permission": [ - { - "name": "Must be logged in, and the account id must be linked to the hacker." - } - ], - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker" - }, - { - "type": "get", - "url": "/hacker/stats", - "title": "Gets the stats of all of the hackers who have applied.", - "name": "getHackerStats", - "group": "Hacker", - "version": "0.0.9", - "parameter": { - "fields": { - "query": [ - { - "group": "query", - "type": "String", - "optional": false, - "field": "model", - "description": "

the model to be searched (Only hacker supported)

" - }, - { - "group": "query", - "type": "Array", - "optional": false, - "field": "q", - "description": "

the query to be executed. For more information on how to format this, please see https://docs.mchacks.ca/architecture/

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Hacker object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Retrieved stats\",\n \"data\": {\n \"stats\" : {\n \"total\": 10,\n \"status\": { \"Applied\": 10 },\n \"school\": { \"McGill University\": 3, \"Harvard University\": 7 },\n degree: { \"Undergraduate\": 10 },\n gender: { \"Male\": 1, \"Female\": 9 },\n travel: { \"true\": 7, \"false\": 3 },\n ethnicity: { \"White\": 10, },\n jobInterest: { \"Internship\": 10 },\n major: { \"Computer Science\": 10 },\n graduationYear: { \"2019\": 10 },\n dietaryRestrictions: { \"None\": 10 },\n shirtSize: { \"M\": 3, \"XL\": 7 },\n age: { \"22\": 10 }\n }\n }\n}", - "type": "object" - } - ] - }, - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/stats" - } - ] - }, - { - "type": "patch", - "url": "/hacker/:id", - "title": "update a hacker's information.", - "description": "

This route only contains the ability to update a subset of a hacker's information. If you want to update a status, you must have Admin priviledges and use PATCH /hacker/status/:id.

", - "name": "patchHacker", - "group": "Hacker", - "version": "0.0.8", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "String", - "optional": true, - "field": "school", - "description": "

Name of the school the hacker goes to

" - }, - { - "group": "body", - "type": "String", - "optional": true, - "field": "gender", - "description": "

Gender of the hacker

" - }, - { - "group": "body", - "type": "Number", - "optional": true, - "field": "travel", - "description": "

How much the hacker requires a bus for transportation

" - }, - { - "group": "body", - "type": "String[]", - "optional": true, - "field": "ethnicity", - "description": "

the ethnicities of the hacker

" - }, - { - "group": "body", - "type": "String[]", - "optional": true, - "field": "major", - "description": "

the major of the hacker

" - }, - { - "group": "body", - "type": "Number", - "optional": true, - "field": "graduationYear", - "description": "

the graduation year of the hacker

" - }, - { - "group": "body", - "type": "Json", - "optional": true, - "field": "application", - "description": "

The hacker's application

" - } - ] - }, - "examples": [ - { - "title": "application: ", - "content": "{\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accommodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n }", - "type": "Json" - } - ] - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Hacker object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Changed hacker information\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"Applied\",\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accommodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n }\n}", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Error while updating hacker\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/:id" - } - ] - }, - { - "type": "patch", - "url": "/hacker/confirmation/:id", - "title": "Allows confirmation of hacker attendence if they are accepted. Also allows change from 'confirmed' to 'withdrawn'.", - "name": "patchHackerConfirmed", - "group": "Hacker", - "version": "0.0.9", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "string", - "optional": true, - "field": "status", - "description": "

The new status of the hacker. "Accepted", "Confirmed", or "Withdrawn"

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Hacker object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Confirmed\"\n }\n}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": "Administrator" - }, - { - "name": "Hacker" - } - ], - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/confirmation/:id" - } - ] - }, - { - "type": "patch", - "url": "/hacker/status/:id", - "title": "update a hacker's status", - "name": "patchHackerStatus", - "group": "Hacker", - "version": "0.0.9", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "string", - "optional": true, - "field": "status", - "description": "

Status of the hacker's application ("None"|"Applied"|"Accepted"|"Declined"|"Waitlisted"|"Confirmed"|"Withdrawn"|"Checked-in")

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Hacker object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Accepted\"\n }\n}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": "Administrator" - } - ], - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/status/:id" - } - ] - }, - { - "type": "post", - "url": "/hacker/resume/:id", - "title": "upload or update resume for a hacker.", - "name": "postHackerResume", - "group": "Hacker", - "version": "0.0.8", - "description": "

NOTE: This must be sent via multipart/form-data POST request

", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "ObjectId", - "optional": false, - "field": "id", - "description": "

Hacker id

" - } - ], - "body": [ - { - "group": "body", - "type": "File", - "optional": false, - "field": "resume", - "description": "

The uploaded file.

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Location in the bucket that the file was stored.

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "HTTP/1.1 200 OK\n{\n message: \"Uploaded resume\",\n data: {\n filename: \"resumes/1535032624768-507f191e810c19729de860ea\"\n }\n}", - "type": "json" - } - ] - }, - "permission": [ - { - "name": "Must be logged in, and the account id must be linked to the hacker." - } - ], - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/resume/:id" - } - ] - }, - { - "type": "post", - "url": "/hacker/email/dayOf/:id", - "title": "", - "description": "

Sends a hacker the day-of email, along with the HackPass QR code to view their hacker profile (for checkin purposes). Hackers must be either confirmed, or checked in.

", - "name": "postHackerSendDayOfEmail", - "group": "Hacker", - "version": "0.0.9", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "string", - "optional": true, - "field": "status", - "description": "

The hacker ID

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Hacker day-of email sent.\",\n \"data\": {}\n}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": "Administrator" - } - ], - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/email/dayOf/:id" - } - ] - }, - { - "type": "post", - "url": "/hacker/email/weekOf/:id", - "title": "", - "description": "

Sends a hacker the week-of email, along with the HackPass QR code to view their hacker profile (for checkin purposes). Hackers must be either confirmed, or checked in.

", - "name": "postHackerSendWeekOfEmail", - "group": "Hacker", - "version": "0.0.9", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "string", - "optional": true, - "field": "status", - "description": "

The hacker ID

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Hacker week-of email sent.\",\n \"data\": {}\n}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": "Administrator" - } - ], - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/email/weekOf/:id" - } - ] - }, - { - "type": "post", - "url": "/hacker/email/weekOf/:id", - "title": "", - "description": "

Sends a hacker the week-of email, along with the HackPass QR code to view their hacker profile (for checkin purposes). Hackers must be eitherconfirmed, or checked in.

", - "name": "postHackerSendWeekOfEmail", - "group": "Hacker", - "version": "0.0.9", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "string", - "optional": true, - "field": "status", - "description": "

The hacker ID

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Hacker week-of email sent.\",\n \"data\": {}\n}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": "Administrator" - } - ], - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/email/weekOf/:id" - } - ] - }, - { - "type": "get", - "url": "/sponsor/self", - "title": "get information about logged in sponsor", - "name": "self", - "group": "Hacker", - "version": "1.4.1", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Sponsor object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Successfully retrieved sponsor information\", \n \"data\": {\n \"id\": \"5bff4d736f86be0a41badb91\",\n \"accountId\": \"5bff4d736f86be0a41badb99\",\n \"tier\": 3,\n \"company\": \"companyName\",\n \"contractURL\": \"https://www.contractHere.com\",\n \"nominees\": [\"5bff4d736f86be0a41badb93\",\"5bff4d736f86be0a41badb94\"]\n }\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "String", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "Object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Sponsor not found\", \"data\": {}}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": ": Sponsor" - } - ], - "filename": "routes/api/sponsor.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/sponsor/self" - } - ] - }, - { - "type": "get", - "url": "/hacker/self", - "title": "get information about own hacker", - "name": "self", - "group": "Hacker", - "version": "0.0.8", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Hacker object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Hacker found by logged in account id\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"application\":{\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n \"jobInterest\":\"Internship\",\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"comments\":\"hi!\",\n \"essay\":\"Pls accept me\"\n },\n \"status\":\"Applied\",\n \"ethnicity\":[\"White or Caucasian\",\" Asian or Pacific Islander\"],\n \"accountId\":\"5bff2a35e533b0f6562b4998\",\n \"school\":\"McPherson College\",\n \"gender\":\"Female\",\n \"travel\":0,\n \"major\":[\"Accounting\"],\n \"graduationYear\":2019,\n \"codeOfConduct\":true,\n } \n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Hacker not found\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/self" - } - ] - }, - { - "type": "get", - "url": "/", - "title": "version", - "version": "0.0.8", - "name": "index", - "group": "Index", - "permission": [ - { - "name": "public" - } - ], - "filename": "routes/index.js", - "groupTitle": "Index", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/" - } - ] - }, - { - "type": "post", - "url": "/api/role/", - "title": "create a new role", - "name": "createRole", - "group": "Role", - "version": "1.1.1", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "String", - "optional": false, - "field": "name", - "description": "

Name of the route

" - }, - { - "group": "body", - "type": "Route[]", - "optional": false, - "field": "routes", - "description": "

The routes that this role gives access to

" - } - ] - }, - "examples": [ - { - "title": "application: ", - "content": "{\n \"name\": \"routename\",\n \"routes\": [\n {\n uri: \"/api/hacker/\"\n requestType: \"POST\"\n }\n ]\n}", - "type": "Json" - } - ] - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Role object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Role creation successful\", \n \"data\": {\n \"name\": \"routename\",\n \"routes\": [\n {\n uri: \"/api/hacker/\"\n requestType: \"POST\"\n }\n ]\n }\n}", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Error while creating role\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/role.js", - "groupTitle": "Role", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/api/role/" - } - ] - }, - { - "type": "get", - "url": "/search/", - "title": "provide a specific query for any defined model", - "name": "search", - "group": "Search", - "version": "0.0.8", - "parameter": { - "fields": { - "query": [ - { - "group": "query", - "type": "String", - "optional": false, - "field": "model", - "description": "

the model to be searched

" - }, - { - "group": "query", - "type": "Array", - "optional": false, - "field": "q", - "description": "

the query to be executed. For more information on how to format this, please see https://docs.mchacks.ca/architecture/

" - }, - { - "group": "query", - "type": "String", - "optional": false, - "field": "sort", - "description": "

either "asc" or "desc"

" - }, - { - "group": "query", - "type": "number", - "optional": false, - "field": "page", - "description": "

the page number that you would like

" - }, - { - "group": "query", - "type": "number", - "optional": false, - "field": "limit", - "description": "

the maximum number of results that you would like returned

" - }, - { - "group": "query", - "type": "any", - "optional": false, - "field": "sort_by", - "description": "

any parameter you want to sort the results by

" - }, - { - "group": "query", - "type": "boolean", - "optional": false, - "field": "expand", - "description": "

whether you want to expand sub documents within the results

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Results

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Successfully executed query, returning all results\",\n \"data\": [\n {...}\n ]\n }", - "type": "object" - }, - { - "title": "Success-Response:", - "content": "{\n \"message\": \"No results found.\",\n \"data\": {}\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "String", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "Object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response:", - "content": "{\"message\": \"Validation failed\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/search.js", - "groupTitle": "Search", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/search/" - } - ] - }, - { - "type": "get", - "url": "/settings/", - "title": "Get the settings for the current hackathon", - "name": "getSettings", - "group": "Settings", - "version": "1.1.1", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Settings Object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Settings creation successful.\",\n \"data\": {\n \"settings\": {\n openTime: \"Wed Feb 06 2019 00:00:00 GMT-0500 (GMT-05:00)\",\n closeTime: \"Sat Feb 01 2020 00:00:00 GMT-0500 (GMT-05:00)\",\n confirmTime: \"Sat Feb 20 2020 00:00:00 GMT-0500 (GMT-05:00)\",\n isRemote: false\n }\n }\n}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": "public" - } - ], - "filename": "routes/api/settings.js", - "groupTitle": "Settings", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/settings/" - } - ] - }, - { - "type": "patch", - "url": "/settings/", - "title": "Patch the settings for the current hackathon", - "name": "patchSettings", - "group": "Settings", - "version": "1.1.1", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "Date", - "optional": true, - "field": "openTime", - "description": "

The opening time for the hackathon.

" - }, - { - "group": "body", - "type": "Date", - "optional": true, - "field": "closeTime", - "description": "

The closing time for the hackathon.

" - }, - { - "group": "body", - "type": "Date", - "optional": true, - "field": "confirmTime", - "description": "

The deadline for confirmation for the hackathon.

" - }, - { - "group": "body", - "type": "Boolean", - "optional": true, - "field": "isRemote", - "description": "

Whether this hackathon is remote or not.

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Settings Object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Settings patch successful.\",\n \"data\": {\n \"settings\": {\n openTime: \"Wed Feb 06 2019 00:00:00 GMT-0500 (GMT-05:00)\",\n closeTime: \"Sat Feb 01 2020 00:00:00 GMT-0500 (GMT-05:00)\",\n confirmTime: \"Sat Feb 20 2020 00:00:00 GMT-0500 (GMT-05:00)\",\n isRemote: true\n }\n }\n}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": "Administrators" - } - ], - "filename": "routes/api/settings.js", - "groupTitle": "Settings", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/settings/" - } - ] - }, - { - "type": "post", - "url": "/sponsor/", - "title": "create a new sponsor", - "name": "createSponsor", - "group": "Sponsor", - "version": "0.0.8", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "MongoID", - "optional": false, - "field": "accountId", - "description": "

ObjectID of the respective account.

" - }, - { - "group": "body", - "type": "Number", - "optional": false, - "field": "tier", - "description": "

Tier of the sponsor, from 0 to 5. 0 is lowest tier, and 5 is the custom tier.

" - }, - { - "group": "body", - "type": "String", - "optional": false, - "field": "company", - "description": "

Name of the company.

" - }, - { - "group": "body", - "type": "String", - "optional": false, - "field": "contractURL", - "description": "

URL link to the contract with the company.

" - }, - { - "group": "body", - "type": "MongoID[]", - "optional": false, - "field": "nominees", - "description": "

Array of accounts that the company wish to nominate as hackers.

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Sponsor object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Sponsor creation successful\", \n \"data\": {...}\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "String", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "Object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Error while creating sponsor\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/sponsor.js", - "groupTitle": "Sponsor", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/sponsor/" - } - ] - }, - { - "type": "get", - "url": "/sponsor/:id", - "title": "get a sponsor's information", - "name": "getSponsor", - "group": "Sponsor", - "version": "0.0.8", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "string", - "optional": false, - "field": "id", - "description": "

a sponsor's unique mongoID

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Sponsor object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Successfully retrieved sponsor information\", \n \"data\": {\n \"id\": \"5bff4d736f86be0a41badb91\",\n \"accountId\": \"5bff4d736f86be0a41badb99\",\n \"tier\": 3,\n \"company\": \"companyName\",\n \"contractURL\": \"https://www.contractHere.com\",\n \"nominees\": [\"5bff4d736f86be0a41badb93\",\"5bff4d736f86be0a41badb94\"]\n }\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "String", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "Object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Sponsor not found\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/sponsor.js", - "groupTitle": "Sponsor", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/sponsor/:id" - } - ] - }, - { - "type": "patch", - "url": "/sponsor/", - "title": "update a sponsor", - "name": "patchSponsor", - "group": "Sponsor", - "version": "1.3.0", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "ObjectId", - "optional": false, - "field": "id", - "description": "

ObjectID of the sponsor

" - } - ], - "body": [ - { - "group": "body", - "type": "String", - "optional": false, - "field": "company", - "description": "

Name of the company.

" - }, - { - "group": "body", - "type": "String", - "optional": false, - "field": "contractURL", - "description": "

URL link to the contract with the company.

" - }, - { - "group": "body", - "type": "ObjectId[]", - "optional": false, - "field": "nominees", - "description": "

Array of accounts that the company wish to nominate as hackers.

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Sponsor object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Sponsor update successful\", \n \"data\": {...}\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "String", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "Object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Error while updating sponsor\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/sponsor.js", - "groupTitle": "Sponsor", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/sponsor/" - } - ] - }, - { - "type": "post", - "url": "/team/", - "title": "create a new team consisting of only the logged in user", - "name": "createTeam", - "group": "Team", - "version": "0.0.8", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "String", - "optional": false, - "field": "name", - "description": "

Name of the team.

" - }, - { - "group": "body", - "type": "String", - "optional": true, - "field": "devpostURL", - "description": "

Devpost link to hack. Once the link is sent, the hack will be considered to be submitted.

" - }, - { - "group": "body", - "type": "String", - "optional": true, - "field": "projectName", - "description": "

Name of the team.

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Team object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Team creation successful\", \n \"data\": {...}\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Error while creating team\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/team.js", - "groupTitle": "Team", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/team/" - } - ] - }, - { - "type": "patch", - "url": "/team/leave/", - "title": "Allows a logged in hacker to leave current team", - "name": "deleteSelfFromTeam", - "group": "Team", - "version": "1.1.1", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

{}

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Removal from team successful.\",\n \"data\": {}\n}", - "type": "object" - } - ] - }, - "filename": "routes/api/team.js", - "groupTitle": "Team", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/team/leave/" - } - ] - }, - { - "type": "get", - "url": "/team/:id", - "title": "get a team's information", - "name": "getTeam", - "group": "Team", - "version": "0.0.8", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "ObjectId", - "optional": false, - "field": "id", - "description": "

MongoId of the team

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Team object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Team retrieval successful\", \n \"data\": { \n \"team\": {\n \"name\":\"foo\",\n \"members\": [\n ObjectId('...')\n ],\n \"devpostURL\": \"www.devpost.com/foo\",\n \"projectName\": \"fooey\"\n },\n \"members\": [\n {\n \"firstName\": \"John\",\n \"lastName\": \"Doe\"\n }\n ],\n }\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "String", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "Object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Team not found\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/team.js", - "groupTitle": "Team", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/team/:id" - } - ] - }, - { - "type": "patch", - "url": "/team/join/", - "title": "Allows a logged in hacker to join a team by name", - "name": "patchJoinTeam", - "group": "Team", - "version": "1.1.1", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "string", - "optional": true, - "field": "name", - "description": "

Name of the team to join

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

{}

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Team join successful.\",\n \"data\": {}\n}", - "type": "object" - } - ] - }, - "filename": "routes/api/team.js", - "groupTitle": "Team", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/team/join/" - } - ] - }, - { - "type": "patch", - "url": "/team/:hackerId", - "title": "Update a team's information. The team is specified by the hacker belonging to it.", - "name": "patchTeam", - "group": "Team", - "version": "0.0.8", - "description": "

We use hackerId instead of teamId because authorization requires a one-to-one mapping from param id to accountId, but we are not able to have that from teamId to accountId due to multiple members in a team. Instead, we use hackerId, as there is a 1 to 1 link between hackerId to teamId, and a 1 to 1 link between hackerId and accountId

", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "ObjectId", - "optional": false, - "field": "hackerId", - "description": "

a hacker's unique Id

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Team object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Team update successful.\", \n \"data\": {...}\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "String", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Query input that caused the error.

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Team not found\", \"data\": {teamId}}", - "type": "object" - } - ] - }, - "filename": "routes/api/team.js", - "groupTitle": "Team", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/team/:hackerId" - } - ] - }, - { - "type": "post", - "url": "/travel/", - "title": "create a new travel", - "name": "createTravel", - "group": "Travel", - "version": "2.0.1", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "MongoID", - "optional": false, - "field": "accountId", - "description": "

ObjectID of the respective account

" - }, - { - "group": "body", - "type": "MongoID", - "optional": false, - "field": "hackerId", - "description": "

ObjectID of the respective hacker

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Travel object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Travel creation successful\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"None\",\n \"request\": 50,\n \"offer\": 0\n }\n}", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Error while creating travel\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/travel.js", - "groupTitle": "Travel", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/travel/" - } - ] - }, - { - "type": "get", - "url": "/travel/email/:email", - "title": "get a travel's information", - "name": "getTravel", - "group": "Travel", - "version": "2.0.1", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "String", - "optional": false, - "field": "email", - "description": "

a travel's unique email

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Travel object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Successfully retrieved travel information\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"Valid\",\n \"request\": 100,\n \"offer\": 50\n }\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "String", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "Object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Travel not found\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/travel.js", - "groupTitle": "Travel", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/travel/email/:email" - } - ] - }, - { - "type": "get", - "url": "/travel/:id", - "title": "get a traveler's information", - "name": "getTravel", - "group": "Travel", - "version": "2.0.1", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "String", - "optional": false, - "field": "id", - "description": "

a travel's unique mongoID

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Travel object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Successfully retrieved travel information\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"Valid\",\n \"request\": 100,\n \"offer\": 50\n }\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "String", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "Object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Travel not found\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/travel.js", - "groupTitle": "Travel", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/travel/:id" - } - ] - }, - { - "type": "patch", - "url": "/travel/offer/:id", - "title": "update a traveler's offer", - "name": "patchTravelOffer", - "group": "Travel", - "version": "2.0.1", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "number", - "optional": true, - "field": "offer", - "description": "

Amount of money offered for travel

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Travel object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Changed travel information\",\n \"data\": {\n \"offer\": 75\n }\n}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": "Administrator" - } - ], - "filename": "routes/api/travel.js", - "groupTitle": "Travel", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/travel/offer/:id" - } - ] - }, - { - "type": "patch", - "url": "/travel/status/:id", - "title": "update a traveler's status", - "name": "patchTravelStatus", - "group": "Travel", - "version": "2.0.1", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "string", - "optional": true, - "field": "status", - "description": "

Status of the travel's reimbursement ("None"|"Bus"|"Offered"|"Valid"|"Invalid"|"Claimed")

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Travel object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Changed travel information\",\n \"data\": {\n \"status\": \"Accepted\"\n }\n}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": "Administrator" - } - ], - "filename": "routes/api/travel.js", - "groupTitle": "Travel", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/travel/status/:id" - } - ] - }, - { - "type": "get", - "url": "/travel/self", - "title": "get information about own hacker's travel", - "name": "self", - "group": "Travel", - "version": "2.0.1", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Travel object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Travel found by logged in account id\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"Claimed\"\n \"request\": 90,\n \"offer\": 80\n } \n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Travel not found\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/travel.js", - "groupTitle": "Travel", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/travel/self" - } - ] - }, - { - "type": "post", - "url": "/volunteer/", - "title": "create a new volunteer", - "name": "createVolunteer", - "group": "Volunteer", - "version": "0.0.8", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "MongoID", - "optional": false, - "field": "accountId", - "description": "

MongoID of the account of the volunteer

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Volunteer object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Volunteer creation successful\", \n \"data\": {...}\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Error while creating volunteer\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/volunteer.js", - "groupTitle": "Volunteer", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/volunteer/" - } - ] - }, - { - "type": "get", - "url": "/volunteer/:id", - "title": "get a volunteer's information", - "name": "getVolunteer", - "group": "Volunteer", - "version": "1.3.0", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "ObjectId", - "optional": false, - "field": "id", - "description": "

a volunteer's unique mongoID

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Volunteer object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Successfully retrieved volunteer information\", \n \"data\": {...}\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "String", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "Object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Volunteer not found\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/volunteer.js", - "groupTitle": "Volunteer", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/volunteer/:id" - } - ] - } -] }); diff --git a/docs/api/api_data.json b/docs/api/api_data.json deleted file mode 100644 index cfc8a3ab..00000000 --- a/docs/api/api_data.json +++ /dev/null @@ -1,4150 +0,0 @@ -[ - { - "type": "post", - "url": "/account/", - "title": "create a new account", - "name": "create", - "group": "Account", - "version": "0.0.8", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "String", - "optional": false, - "field": "firstName", - "description": "

First name of the account creator.

" - }, - { - "group": "body", - "type": "String", - "optional": false, - "field": "lastName", - "description": "

Last name of the account creator.

" - }, - { - "group": "body", - "type": "String", - "optional": false, - "field": "pronoun", - "description": "

the pronoun of the account creator.

" - }, - { - "group": "body", - "type": "String", - "optional": false, - "field": "email", - "description": "

Email of the account.

" - }, - { - "group": "body", - "type": "String", - "optional": false, - "field": "gender", - "description": "

Gender of the account creator.

" - }, - { - "group": "body", - "type": "String[]", - "optional": false, - "field": "dietaryRestrictions", - "description": "

Any dietary restrictions for the user. 'None' if there are no restrictions

" - }, - { - "group": "body", - "type": "String", - "optional": false, - "field": "password", - "description": "

The password of the account.

" - }, - { - "group": "body", - "type": "String", - "optional": false, - "field": "birthDate", - "description": "

a Date parsable string.

" - }, - { - "group": "body", - "type": "Number", - "optional": true, - "field": "phoneNumber", - "description": "

the user's phone number, represented as a string.

" - } - ], - "header": [ - { - "group": "header", - "type": "JWT", - "optional": true, - "field": "token", - "description": "

the user's invite token.

" - } - ] - }, - "examples": [ - { - "title": "Request-Example:", - "content": "{ \n \"firstName\": \"Theo\",\n \"lastName\":\"Klein\",\n \"pronoun\":\"he/him\",\n \"email\":\"theo@klein.com\",\n \"password\":\"hunter2\",\n \"phoneNumber\":1234567890,\n \"gender\":\"Male\",\n \"birthDate\":\"10/30/1997\"\n}", - "type": "json" - } - ] - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Account object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Account creation successful\", \n \"data\": {\n \"id\": ObjectId(\"5bff8b9f3274cf001bc71048\"),\n \t\"firstName\": \"Theo\",\n \"lastName\":\"Klein\",\n \"pronoun\":\"he/him\",\n \"email\":\"theo@klein.com\",\n \"phoneNumber\":1234567890,\n \t\"gender\":\"Male\",\n \"birthDate\":Date(\"10/30/1997\")\n }\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\n \"message\": \"Account already exists\", \n \"data\": {\n \"route\": \"/\"\n }\n}", - "type": "object" - } - ] - }, - "filename": "routes/api/account.js", - "groupTitle": "Account", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/account/" - } - ] - }, - { - "type": "get", - "url": "/account/:id", - "title": "gets information from an account with mongoid ':id'", - "name": "getAccount", - "group": "Account", - "version": "0.0.8", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "ObjectId", - "optional": false, - "field": "id", - "description": "

MongoId of an account

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Account object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Account found by user id\", \n \"data\": {\n \"id\": ObjectId(\"5bff8b9f3274cf001bc71048\"),\n \"firstName\": \"Theo\",\n \"lastName\":\"Klein\",\n \"pronoun\":\"he/him\",\n \"email\":\"theo@klein.com\",\n \"phoneNumber\":1234567890,\n \"gender\":\"Male\",\n \"birthDate\":Date(\"10/30/1997\")\n }\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Account not found\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/account.js", - "groupTitle": "Account", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/account/:id" - } - ] - }, - { - "type": "get", - "url": "/account/invite", - "title": "Get all of the invites.", - "name": "getAllInvites", - "group": "Account", - "version": "0.0.8", - "description": "

Get all of the invites that currently exist in the database.

", - "success": { - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Invite retrieval successful.\", \n \"data\": [{\n \"email\":\"abc@def.com\",\n \"accountType\":\"Hacker\"\n }]\n }", - "type": "object" - } - ] - }, - "filename": "routes/api/account.js", - "groupTitle": "Account", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/account/invite" - } - ] - }, - { - "type": "post", - "url": "/account/invite", - "title": "invites a user to create an account with the specified accountType", - "name": "inviteAccount", - "group": "Account", - "version": "0.0.8", - "description": "

sends link with token to be used with the account/create route

", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "String", - "optional": true, - "field": "email", - "description": "

email of the account to be created and where to send the link

" - }, - { - "group": "body", - "type": "String", - "optional": true, - "field": "accountType", - "description": "

the type of the account which the user can create, for sponsor this should specify tier as well

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Account object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Successfully invited user\", \n \"data\": {}\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

Error object

" - } - ] - }, - "examples": [ - { - "title": "Error-Response:", - "content": "{\n \"message\": \"Invalid Authentication\",\n \"data\": {\n \"route\": \"/invite\"\n }\n }", - "type": "object" - } - ] - }, - "filename": "routes/api/account.js", - "groupTitle": "Account", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/account/invite" - } - ] - }, - { - "type": "get", - "url": "/account/self", - "title": "get information about own account", - "name": "self", - "group": "Account", - "version": "0.0.8", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Account object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Account found by user email\", \n \"data\": {\n \t\"id\": ObjectId(\"5bff8b9f3274cf001bc71048\"),\n \t\"firstName\": \"Theo\",\n \"lastName\":\"Klein\",\n \"pronoun\":\"he/him\",\n \"email\":\"theo@klein.com\",\n \"phoneNumber\":1234567890,\n \t\"gender\":\"Male\",\n \"birthDate\":Date(\"10/30/1997\")\n }\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty object

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Account not found\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/account.js", - "groupTitle": "Account", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/account/self" - } - ] - }, - { - "type": "patch", - "url": "/account/:id", - "title": "update an account's information", - "name": "updateOneUser", - "group": "Account", - "version": "0.0.8", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "String", - "optional": true, - "field": "firstName", - "description": "

First name of the account creator.

" - }, - { - "group": "body", - "type": "String", - "optional": true, - "field": "lastName", - "description": "

Last name of the account creator.

" - }, - { - "group": "body", - "type": "String", - "optional": true, - "field": "pronoun", - "description": "

The pronoun of the account creator.

" - }, - { - "group": "body", - "type": "String", - "optional": true, - "field": "email", - "description": "

Email of the account.

" - }, - { - "group": "body", - "type": "String", - "optional": true, - "field": "gender", - "description": "

Gender of the account creator.

" - }, - { - "group": "body", - "type": "String", - "optional": true, - "field": "birthDate", - "description": "

A Date parsable string.

" - }, - { - "group": "body", - "type": "Number", - "optional": true, - "field": "phoneNumber", - "description": "

The user's phone number, represented as a string.

" - }, - { - "group": "body", - "type": "String[]", - "optional": true, - "field": "dietaryRestrictions", - "description": "

Any dietary restrictions for the user. 'None' if there are no restrictions

" - } - ] - }, - "examples": [ - { - "title": "Request-Example:", - "content": "{ \"gender\": \"Male\" }", - "type": "json" - } - ] - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Account object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Account update successful.\", \n \"data\": {\n \"id\": ObjectId(\"5bff8b9f3274cf001bc71048\"),\n \t\"firstName\": \"Theo\",\n \"lastName\":\"Klein\",\n \"pronoun\":\"he/him\",\n \"email\":\"theo@klein.com\",\n \"phoneNumber\":1234567890,\n \t\"gender\": \"Male\",\n \"birthDate\":Date(\"10/30/1997\")\n }\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Error while updating account\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/account.js", - "groupTitle": "Account", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/account/:id" - } - ] - }, - { - "type": "patch", - "url": "/auth/password/change", - "title": "change password for logged in user", - "name": "changePassword", - "group": "Authentication", - "version": "0.0.8", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "oldPassword", - "description": "

The current password of the user

" - }, - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "newPassword", - "description": "

The new password of the user

" - } - ] - }, - "examples": [ - { - "title": "Request-Example:", - "content": "{\n \"oldPassword\": \"password12345\",\n \"newPassword\": \"password123456\"\n}", - "type": "json" - } - ] - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\"message\": \"Successfully reset password\", \"data\": {}}", - "type": "json" - } - ] - }, - "permission": [ - { - "name": ": Must be logged in" - } - ], - "filename": "routes/api/auth.js", - "groupTitle": "Authentication", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/auth/password/change" - } - ] - }, - { - "type": "post", - "url": "/auth/confirm/:token", - "title": "confirm account using the JWT in :token", - "name": "confirmAccount", - "group": "Authentication", - "version": "0.0.8", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "JWT", - "description": "

for confirming the account

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\"message\": \"Successfully confirmed account\", \"data\": {}}", - "type": "json" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response:", - "content": "{\"message\": \"Invalid token for confirming account, \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/auth.js", - "groupTitle": "Authentication", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/auth/confirm/:token" - } - ] - }, - { - "type": "post", - "url": "/auth/password/forgot", - "title": "forgot password route", - "name": "forgotPassword", - "group": "Authentication", - "version": "0.0.8", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "email", - "description": "

the email address of the account

" - } - ] - }, - "examples": [ - { - "title": "Request-Example:", - "content": "{ \"email\": \"myemail@mchacks.ca\" }", - "type": "json" - } - ] - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\"message\": \"Sent reset email\", \"data\": {}}", - "type": "json" - } - ] - }, - "permission": [ - { - "name": ": public" - } - ], - "filename": "routes/api/auth.js", - "groupTitle": "Authentication", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/auth/password/forgot" - } - ] - }, - { - "type": "get", - "url": "/auth/rolebindings/:id", - "title": "retrieve rolebindings for a user given by their user id :id", - "name": "getRoleBindings", - "group": "Authentication", - "version": "0.0.8", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "ObjectId", - "optional": false, - "field": "id", - "description": "

MongoId of an account

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Rolebindings object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Successfully retrieved role bindings\",\n \"data\": {\n accountId:\"5beca4ab2e069a34f91697b2\"\n id:\"5beca4ae2e069a34f91698b1\"\n roles: [\n {\n _id:\"5beca4ab2e069a34f91697d9\",\n name:\"hacker\",\n routes: [\n {_id: \"5beca4ae2e069a34f9169852\", requestType: \"POST\", uri: \"/api/auth/login\"},\n {_id: \"5beca4ae2e069a34f9169851\", requestType: \"POST\", uri: \"/api/auth/logout\"},\n {_id: \"5beca4ae2e069a34f9169850\", requestType: \"GET\", uri: \"/api/auth/rolebindings/:self\"},\n {_id: \"5beca4ae2e069a34f916984f\", requestType: \"GET\", uri: \"/api/account/self\"},\n {_id: \"5beca4ae2e069a34f916984e\", requestType: \"GET\", uri: \"/api/account/:self\"},\n {_id: \"5beca4ae2e069a34f916984d\", requestType: \"PATCH\", uri: \"/api/account/:self\"},\n {_id: \"5beca4ae2e069a34f916984c\", requestType: \"POST\", uri: \"/api/hacker/\"},\n {_id: \"5beca4ae2e069a34f916984b\", requestType: \"GET\", uri: \"/api/hacker/:self\"},\n {_id: \"5beca4ae2e069a34f916984a\", requestType: \"GET\", uri: \"/api/hacker/:self/resume\"},\n {_id: \"5beca4ae2e069a34f9169849\", requestType: \"PATCH\", uri: \"/api/hacker/:self\"}\n ]\n }\n ]\n }\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Role Bindings not found\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/auth.js", - "groupTitle": "Authentication", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/auth/rolebindings/:id" - } - ] - }, - { - "type": "get", - "url": "/auth/roles", - "title": "get roles", - "name": "getRoles", - "description": "

get all roles that exist in the database

", - "group": "Authentication", - "version": "0.0.8", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\"message\": \"Sucessfully retrieved all roles\", \"data\":\n[{name: \"GodStaff\", routes: Array(27), id: \"5bee20ef3ca9dd4754382880\"},\n {name: \"Hacker\", routes: Array(10), id: \"5bee20ef3ca9dd4754382881\"},\n {name: \"Volunteer\", routes: Array(4), id: \"5bee20ef3ca9dd4754382882\"}]", - "type": "json" - } - ] - }, - "filename": "routes/api/auth.js", - "groupTitle": "Authentication", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/auth/roles" - } - ] - }, - { - "type": "post", - "url": "/auth/login", - "title": "login to the service", - "name": "login", - "group": "Authentication", - "version": "0.0.8", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "string", - "optional": false, - "field": "email", - "description": "

Account email

" - }, - { - "group": "Parameter", - "type": "string", - "optional": false, - "field": "password", - "description": "

Account password

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\"message\": \"Successfully logged in\", \"data\": {}}", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Invalid Authentication\", \"data\": {}}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": ": public" - } - ], - "filename": "routes/api/auth.js", - "groupTitle": "Authentication", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/auth/login" - } - ] - }, - { - "type": "get", - "url": "/auth/logout", - "title": "logout of service", - "name": "logout", - "group": "Authentication", - "version": "0.0.8", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\"message\": \"Successfully logged out\", \"data\": {}}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": ": public" - } - ], - "filename": "routes/api/auth.js", - "groupTitle": "Authentication", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/auth/logout" - } - ] - }, - { - "type": "get", - "url": "/auth/confirm/resend", - "title": "resend confirmation token", - "name": "resendConfirmAccount", - "group": "Authentication", - "version": "0.0.8", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\"message\": \"Successfully resent confirmation email\", \"data\": {}}", - "type": "json" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response:", - "content": " HTTP/1.1 422\n{\"message\": \"Account already confirmed\", \"data\": {}}", - "type": "json" - }, - { - "title": "Error-Response:", - "content": " HTTP/1.1 428\n{\"message\": \"Account confirmation token does not exist\", \"data\": {}}", - "type": "json" - } - ] - }, - "filename": "routes/api/auth.js", - "groupTitle": "Authentication", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/auth/confirm/resend" - } - ] - }, - { - "type": "post", - "url": "/auth/password/reset", - "title": "reset password", - "name": "resetPassword", - "group": "Authentication", - "version": "0.0.8", - "parameter": { - "fields": { - "Parameter": [ - { - "group": "Parameter", - "type": "String", - "optional": false, - "field": "password", - "description": "

the password of the account

" - } - ] - }, - "examples": [ - { - "title": "Request-Example:", - "content": "{ \"password\": \"hunter2\" }", - "type": "json" - } - ] - }, - "header": { - "fields": { - "Header": [ - { - "group": "Header", - "type": "String", - "optional": false, - "field": "Authentication", - "description": "

the token that was provided in the reset password email

" - } - ] - }, - "examples": [ - { - "title": "Header-Example:", - "content": "{\n \"X-Reset-Token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c\"\n}", - "type": "json" - } - ] - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\"message\": \"Successfully reset password\", \"data\": {}}", - "type": "json" - } - ] - }, - "permission": [ - { - "name": ": must have authentication token" - } - ], - "filename": "routes/api/auth.js", - "groupTitle": "Authentication", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/auth/password/reset" - } - ] - }, - { - "type": "patch", - "url": "/hacker/batchAccept/", - "title": "accept array of Hackers", - "name": "acceptHacker", - "group": "Hacker", - "version": "3.0.0", - "parameter": { - "fields": { - "body) {{ids: ObjectId[]}} Array of id(s": [ - { - "group": "body) {{ids: ObjectId[]}} Array of id(s", - "optional": false, - "field": "that", - "description": "

needed to be accepted

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

success_ids array and errors array. Errors array will contain a detailed error for why the batch update for a given ID did not work

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Hacker batch update successful.\",\n \"data\": {\n \"success_ids\": [\"id1\", \"id2\"]\n \"errors\": [{status: 404, message: \"ACCOUNT_NOT_FOUND\", account: null, hacker_id: \"id3\"}]\n }\n}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": "Administrator" - } - ], - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/batchAccept/" - } - ] - }, - { - "type": "patch", - "url": "/hacker/acceptEmail/:email", - "title": "accept a Hacker by email", - "name": "acceptHacker", - "group": "Hacker", - "version": "2.0.0", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Hacker object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Accepted\"\n }\n}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": "Administrator" - } - ], - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/acceptEmail/:email" - } - ] - }, - { - "type": "patch", - "url": "/hacker/accept/:id", - "title": "accept a Hacker", - "name": "acceptHacker", - "group": "Hacker", - "version": "2.0.0", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Hacker object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Accepted\"\n }\n}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": "Administrator" - } - ], - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/accept/:id" - } - ] - }, - { - "type": "patch", - "url": "/hacker/checkin/:id", - "title": "update a hacker's status to be 'Checked-in'. Note that the Hacker must eitehr be Accepted or Confirmed.", - "name": "checkinHacker", - "group": "Hacker", - "version": "0.0.9", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "string", - "optional": true, - "field": "status", - "description": "

Check-in status. "Checked-in"

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Hacker object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Checked-in\"\n }\n}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": "Administrator" - }, - { - "name": "Volunteer" - } - ], - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/checkin/:id" - } - ] - }, - { - "type": "post", - "url": "/hacker/", - "title": "create a new hacker", - "name": "createHacker", - "group": "Hacker", - "version": "0.0.8", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "MongoID", - "optional": false, - "field": "accountId", - "description": "

ObjectID of the respective account

" - }, - { - "group": "body", - "type": "String", - "optional": false, - "field": "school", - "description": "

Name of the school the hacker goes to

" - }, - { - "group": "body", - "type": "String", - "optional": false, - "field": "gender", - "description": "

Gender of the hacker

" - }, - { - "group": "body", - "type": "Number", - "optional": false, - "field": "travel", - "description": "

Whether the hacker requires a bus for transportation

" - }, - { - "group": "body", - "type": "String[]", - "optional": false, - "field": "ethnicity", - "description": "

the ethnicities of the hacker

" - }, - { - "group": "body", - "type": "String[]", - "optional": false, - "field": "major", - "description": "

the major of the hacker

" - }, - { - "group": "body", - "type": "Number", - "optional": false, - "field": "graduationYear", - "description": "

the graduation year of the hacker

" - }, - { - "group": "body", - "type": "Boolean", - "optional": false, - "field": "codeOfConduct", - "description": "

acceptance of the code of conduct

" - }, - { - "group": "body", - "type": "Json", - "optional": false, - "field": "application", - "description": "

The hacker's application. Resume and jobInterest fields are required.

" - } - ] - }, - "examples": [ - { - "title": "application: ", - "content": "{\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accommodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n}", - "type": "Json" - } - ] - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Hacker object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Hacker creation successful\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accommodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n}", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Error while creating hacker\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/" - } - ] - }, - { - "type": "get", - "url": "/hacker/:id", - "title": "get a hacker's information", - "name": "getHacker", - "group": "Hacker", - "version": "0.0.8", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "String", - "optional": false, - "field": "id", - "description": "

a hacker's unique mongoID

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Hacker object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Successfully retrieved hacker information\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"Applied\",\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accommodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n }\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "String", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "Object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Hacker not found\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/:id" - } - ] - }, - { - "type": "get", - "url": "/hacker/email/:email", - "title": "get a hacker's information", - "name": "getHacker", - "group": "Hacker", - "version": "0.0.8", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "String", - "optional": false, - "field": "email", - "description": "

a hacker's unique email

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Hacker object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Successfully retrieved hacker information\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"Applied\",\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accommodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n }\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "String", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "Object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Hacker not found\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/email/:email" - } - ] - }, - { - "type": "get", - "url": "/hacker/resume:id", - "title": "get the resume for a hacker.", - "name": "getHackerResume", - "group": "Hacker", - "version": "0.0.8", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "ObjectId", - "optional": false, - "field": "id", - "description": "

Hacker id

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "HTTP/1.1 200 OK\n{\n message: \"Downloaded resume\",\n data: {\n id: \"507f191e810c19729de860ea\",\n resume: [Buffer]\n }\n}", - "type": "json" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "String", - "optional": false, - "field": "message", - "description": "

"Resume does not exist"

" - } - ] - }, - "examples": [ - { - "title": "Error-Response:", - "content": "HTTP/1.1 404\n{\n message: \"Resume not found\",\n data: {}\n}", - "type": "json" - } - ] - }, - "permission": [ - { - "name": "Must be logged in, and the account id must be linked to the hacker." - } - ], - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker" - }, - { - "type": "get", - "url": "/hacker/stats", - "title": "Gets the stats of all of the hackers who have applied.", - "name": "getHackerStats", - "group": "Hacker", - "version": "0.0.9", - "parameter": { - "fields": { - "query": [ - { - "group": "query", - "type": "String", - "optional": false, - "field": "model", - "description": "

the model to be searched (Only hacker supported)

" - }, - { - "group": "query", - "type": "Array", - "optional": false, - "field": "q", - "description": "

the query to be executed. For more information on how to format this, please see https://docs.mchacks.ca/architecture/

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Hacker object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Retrieved stats\",\n \"data\": {\n \"stats\" : {\n \"total\": 10,\n \"status\": { \"Applied\": 10 },\n \"school\": { \"McGill University\": 3, \"Harvard University\": 7 },\n degree: { \"Undergraduate\": 10 },\n gender: { \"Male\": 1, \"Female\": 9 },\n travel: { \"true\": 7, \"false\": 3 },\n ethnicity: { \"White\": 10, },\n jobInterest: { \"Internship\": 10 },\n major: { \"Computer Science\": 10 },\n graduationYear: { \"2019\": 10 },\n dietaryRestrictions: { \"None\": 10 },\n shirtSize: { \"M\": 3, \"XL\": 7 },\n age: { \"22\": 10 }\n }\n }\n}", - "type": "object" - } - ] - }, - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/stats" - } - ] - }, - { - "type": "patch", - "url": "/hacker/:id", - "title": "update a hacker's information.", - "description": "

This route only contains the ability to update a subset of a hacker's information. If you want to update a status, you must have Admin priviledges and use PATCH /hacker/status/:id.

", - "name": "patchHacker", - "group": "Hacker", - "version": "0.0.8", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "String", - "optional": true, - "field": "school", - "description": "

Name of the school the hacker goes to

" - }, - { - "group": "body", - "type": "String", - "optional": true, - "field": "gender", - "description": "

Gender of the hacker

" - }, - { - "group": "body", - "type": "Number", - "optional": true, - "field": "travel", - "description": "

How much the hacker requires a bus for transportation

" - }, - { - "group": "body", - "type": "String[]", - "optional": true, - "field": "ethnicity", - "description": "

the ethnicities of the hacker

" - }, - { - "group": "body", - "type": "String[]", - "optional": true, - "field": "major", - "description": "

the major of the hacker

" - }, - { - "group": "body", - "type": "Number", - "optional": true, - "field": "graduationYear", - "description": "

the graduation year of the hacker

" - }, - { - "group": "body", - "type": "Json", - "optional": true, - "field": "application", - "description": "

The hacker's application

" - } - ] - }, - "examples": [ - { - "title": "application: ", - "content": "{\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accommodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n }", - "type": "Json" - } - ] - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Hacker object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Changed hacker information\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"Applied\",\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accommodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n }\n}", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Error while updating hacker\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/:id" - } - ] - }, - { - "type": "patch", - "url": "/hacker/confirmation/:id", - "title": "Allows confirmation of hacker attendence if they are accepted. Also allows change from 'confirmed' to 'withdrawn'.", - "name": "patchHackerConfirmed", - "group": "Hacker", - "version": "0.0.9", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "string", - "optional": true, - "field": "status", - "description": "

The new status of the hacker. "Accepted", "Confirmed", or "Withdrawn"

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Hacker object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Confirmed\"\n }\n}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": "Administrator" - }, - { - "name": "Hacker" - } - ], - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/confirmation/:id" - } - ] - }, - { - "type": "patch", - "url": "/hacker/status/:id", - "title": "update a hacker's status", - "name": "patchHackerStatus", - "group": "Hacker", - "version": "0.0.9", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "string", - "optional": true, - "field": "status", - "description": "

Status of the hacker's application ("None"|"Applied"|"Accepted"|"Declined"|"Waitlisted"|"Confirmed"|"Withdrawn"|"Checked-in")

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Hacker object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Accepted\"\n }\n}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": "Administrator" - } - ], - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/status/:id" - } - ] - }, - { - "type": "post", - "url": "/hacker/resume/:id", - "title": "upload or update resume for a hacker.", - "name": "postHackerResume", - "group": "Hacker", - "version": "0.0.8", - "description": "

NOTE: This must be sent via multipart/form-data POST request

", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "ObjectId", - "optional": false, - "field": "id", - "description": "

Hacker id

" - } - ], - "body": [ - { - "group": "body", - "type": "File", - "optional": false, - "field": "resume", - "description": "

The uploaded file.

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Location in the bucket that the file was stored.

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "HTTP/1.1 200 OK\n{\n message: \"Uploaded resume\",\n data: {\n filename: \"resumes/1535032624768-507f191e810c19729de860ea\"\n }\n}", - "type": "json" - } - ] - }, - "permission": [ - { - "name": "Must be logged in, and the account id must be linked to the hacker." - } - ], - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/resume/:id" - } - ] - }, - { - "type": "post", - "url": "/hacker/email/dayOf/:id", - "title": "", - "description": "

Sends a hacker the day-of email, along with the HackPass QR code to view their hacker profile (for checkin purposes). Hackers must be either confirmed, or checked in.

", - "name": "postHackerSendDayOfEmail", - "group": "Hacker", - "version": "0.0.9", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "string", - "optional": true, - "field": "status", - "description": "

The hacker ID

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Hacker day-of email sent.\",\n \"data\": {}\n}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": "Administrator" - } - ], - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/email/dayOf/:id" - } - ] - }, - { - "type": "post", - "url": "/hacker/email/weekOf/:id", - "title": "", - "description": "

Sends a hacker the week-of email, along with the HackPass QR code to view their hacker profile (for checkin purposes). Hackers must be either confirmed, or checked in.

", - "name": "postHackerSendWeekOfEmail", - "group": "Hacker", - "version": "0.0.9", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "string", - "optional": true, - "field": "status", - "description": "

The hacker ID

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Hacker week-of email sent.\",\n \"data\": {}\n}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": "Administrator" - } - ], - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/email/weekOf/:id" - } - ] - }, - { - "type": "post", - "url": "/hacker/email/weekOf/:id", - "title": "", - "description": "

Sends a hacker the week-of email, along with the HackPass QR code to view their hacker profile (for checkin purposes). Hackers must be eitherconfirmed, or checked in.

", - "name": "postHackerSendWeekOfEmail", - "group": "Hacker", - "version": "0.0.9", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "string", - "optional": true, - "field": "status", - "description": "

The hacker ID

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Hacker week-of email sent.\",\n \"data\": {}\n}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": "Administrator" - } - ], - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/email/weekOf/:id" - } - ] - }, - { - "type": "get", - "url": "/sponsor/self", - "title": "get information about logged in sponsor", - "name": "self", - "group": "Hacker", - "version": "1.4.1", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Sponsor object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Successfully retrieved sponsor information\", \n \"data\": {\n \"id\": \"5bff4d736f86be0a41badb91\",\n \"accountId\": \"5bff4d736f86be0a41badb99\",\n \"tier\": 3,\n \"company\": \"companyName\",\n \"contractURL\": \"https://www.contractHere.com\",\n \"nominees\": [\"5bff4d736f86be0a41badb93\",\"5bff4d736f86be0a41badb94\"]\n }\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "String", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "Object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Sponsor not found\", \"data\": {}}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": ": Sponsor" - } - ], - "filename": "routes/api/sponsor.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/sponsor/self" - } - ] - }, - { - "type": "get", - "url": "/hacker/self", - "title": "get information about own hacker", - "name": "self", - "group": "Hacker", - "version": "0.0.8", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Hacker object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Hacker found by logged in account id\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"application\":{\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n \"jobInterest\":\"Internship\",\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"comments\":\"hi!\",\n \"essay\":\"Pls accept me\"\n },\n \"status\":\"Applied\",\n \"ethnicity\":[\"White or Caucasian\",\" Asian or Pacific Islander\"],\n \"accountId\":\"5bff2a35e533b0f6562b4998\",\n \"school\":\"McPherson College\",\n \"gender\":\"Female\",\n \"travel\":0,\n \"major\":[\"Accounting\"],\n \"graduationYear\":2019,\n \"codeOfConduct\":true,\n } \n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Hacker not found\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/hacker.js", - "groupTitle": "Hacker", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/hacker/self" - } - ] - }, - { - "type": "get", - "url": "/", - "title": "version", - "version": "0.0.8", - "name": "index", - "group": "Index", - "permission": [ - { - "name": "public" - } - ], - "filename": "routes/index.js", - "groupTitle": "Index", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/" - } - ] - }, - { - "type": "post", - "url": "/api/role/", - "title": "create a new role", - "name": "createRole", - "group": "Role", - "version": "1.1.1", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "String", - "optional": false, - "field": "name", - "description": "

Name of the route

" - }, - { - "group": "body", - "type": "Route[]", - "optional": false, - "field": "routes", - "description": "

The routes that this role gives access to

" - } - ] - }, - "examples": [ - { - "title": "application: ", - "content": "{\n \"name\": \"routename\",\n \"routes\": [\n {\n uri: \"/api/hacker/\"\n requestType: \"POST\"\n }\n ]\n}", - "type": "Json" - } - ] - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Role object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Role creation successful\", \n \"data\": {\n \"name\": \"routename\",\n \"routes\": [\n {\n uri: \"/api/hacker/\"\n requestType: \"POST\"\n }\n ]\n }\n}", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Error while creating role\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/role.js", - "groupTitle": "Role", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/api/role/" - } - ] - }, - { - "type": "get", - "url": "/search/", - "title": "provide a specific query for any defined model", - "name": "search", - "group": "Search", - "version": "0.0.8", - "parameter": { - "fields": { - "query": [ - { - "group": "query", - "type": "String", - "optional": false, - "field": "model", - "description": "

the model to be searched

" - }, - { - "group": "query", - "type": "Array", - "optional": false, - "field": "q", - "description": "

the query to be executed. For more information on how to format this, please see https://docs.mchacks.ca/architecture/

" - }, - { - "group": "query", - "type": "String", - "optional": false, - "field": "sort", - "description": "

either "asc" or "desc"

" - }, - { - "group": "query", - "type": "number", - "optional": false, - "field": "page", - "description": "

the page number that you would like

" - }, - { - "group": "query", - "type": "number", - "optional": false, - "field": "limit", - "description": "

the maximum number of results that you would like returned

" - }, - { - "group": "query", - "type": "any", - "optional": false, - "field": "sort_by", - "description": "

any parameter you want to sort the results by

" - }, - { - "group": "query", - "type": "boolean", - "optional": false, - "field": "expand", - "description": "

whether you want to expand sub documents within the results

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Results

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Successfully executed query, returning all results\",\n \"data\": [\n {...}\n ]\n }", - "type": "object" - }, - { - "title": "Success-Response:", - "content": "{\n \"message\": \"No results found.\",\n \"data\": {}\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "String", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "Object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response:", - "content": "{\"message\": \"Validation failed\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/search.js", - "groupTitle": "Search", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/search/" - } - ] - }, - { - "type": "get", - "url": "/settings/", - "title": "Get the settings for the current hackathon", - "name": "getSettings", - "group": "Settings", - "version": "1.1.1", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Settings Object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Settings creation successful.\",\n \"data\": {\n \"settings\": {\n openTime: \"Wed Feb 06 2019 00:00:00 GMT-0500 (GMT-05:00)\",\n closeTime: \"Sat Feb 01 2020 00:00:00 GMT-0500 (GMT-05:00)\",\n confirmTime: \"Sat Feb 20 2020 00:00:00 GMT-0500 (GMT-05:00)\",\n isRemote: false\n }\n }\n}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": "public" - } - ], - "filename": "routes/api/settings.js", - "groupTitle": "Settings", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/settings/" - } - ] - }, - { - "type": "patch", - "url": "/settings/", - "title": "Patch the settings for the current hackathon", - "name": "patchSettings", - "group": "Settings", - "version": "1.1.1", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "Date", - "optional": true, - "field": "openTime", - "description": "

The opening time for the hackathon.

" - }, - { - "group": "body", - "type": "Date", - "optional": true, - "field": "closeTime", - "description": "

The closing time for the hackathon.

" - }, - { - "group": "body", - "type": "Date", - "optional": true, - "field": "confirmTime", - "description": "

The deadline for confirmation for the hackathon.

" - }, - { - "group": "body", - "type": "Boolean", - "optional": true, - "field": "isRemote", - "description": "

Whether this hackathon is remote or not.

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Settings Object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Settings patch successful.\",\n \"data\": {\n \"settings\": {\n openTime: \"Wed Feb 06 2019 00:00:00 GMT-0500 (GMT-05:00)\",\n closeTime: \"Sat Feb 01 2020 00:00:00 GMT-0500 (GMT-05:00)\",\n confirmTime: \"Sat Feb 20 2020 00:00:00 GMT-0500 (GMT-05:00)\",\n isRemote: true\n }\n }\n}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": "Administrators" - } - ], - "filename": "routes/api/settings.js", - "groupTitle": "Settings", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/settings/" - } - ] - }, - { - "type": "post", - "url": "/sponsor/", - "title": "create a new sponsor", - "name": "createSponsor", - "group": "Sponsor", - "version": "0.0.8", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "MongoID", - "optional": false, - "field": "accountId", - "description": "

ObjectID of the respective account.

" - }, - { - "group": "body", - "type": "Number", - "optional": false, - "field": "tier", - "description": "

Tier of the sponsor, from 0 to 5. 0 is lowest tier, and 5 is the custom tier.

" - }, - { - "group": "body", - "type": "String", - "optional": false, - "field": "company", - "description": "

Name of the company.

" - }, - { - "group": "body", - "type": "String", - "optional": false, - "field": "contractURL", - "description": "

URL link to the contract with the company.

" - }, - { - "group": "body", - "type": "MongoID[]", - "optional": false, - "field": "nominees", - "description": "

Array of accounts that the company wish to nominate as hackers.

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Sponsor object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Sponsor creation successful\", \n \"data\": {...}\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "String", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "Object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Error while creating sponsor\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/sponsor.js", - "groupTitle": "Sponsor", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/sponsor/" - } - ] - }, - { - "type": "get", - "url": "/sponsor/:id", - "title": "get a sponsor's information", - "name": "getSponsor", - "group": "Sponsor", - "version": "0.0.8", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "string", - "optional": false, - "field": "id", - "description": "

a sponsor's unique mongoID

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Sponsor object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Successfully retrieved sponsor information\", \n \"data\": {\n \"id\": \"5bff4d736f86be0a41badb91\",\n \"accountId\": \"5bff4d736f86be0a41badb99\",\n \"tier\": 3,\n \"company\": \"companyName\",\n \"contractURL\": \"https://www.contractHere.com\",\n \"nominees\": [\"5bff4d736f86be0a41badb93\",\"5bff4d736f86be0a41badb94\"]\n }\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "String", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "Object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Sponsor not found\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/sponsor.js", - "groupTitle": "Sponsor", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/sponsor/:id" - } - ] - }, - { - "type": "patch", - "url": "/sponsor/", - "title": "update a sponsor", - "name": "patchSponsor", - "group": "Sponsor", - "version": "1.3.0", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "ObjectId", - "optional": false, - "field": "id", - "description": "

ObjectID of the sponsor

" - } - ], - "body": [ - { - "group": "body", - "type": "String", - "optional": false, - "field": "company", - "description": "

Name of the company.

" - }, - { - "group": "body", - "type": "String", - "optional": false, - "field": "contractURL", - "description": "

URL link to the contract with the company.

" - }, - { - "group": "body", - "type": "ObjectId[]", - "optional": false, - "field": "nominees", - "description": "

Array of accounts that the company wish to nominate as hackers.

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Sponsor object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Sponsor update successful\", \n \"data\": {...}\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "String", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "Object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Error while updating sponsor\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/sponsor.js", - "groupTitle": "Sponsor", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/sponsor/" - } - ] - }, - { - "type": "post", - "url": "/team/", - "title": "create a new team consisting of only the logged in user", - "name": "createTeam", - "group": "Team", - "version": "0.0.8", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "String", - "optional": false, - "field": "name", - "description": "

Name of the team.

" - }, - { - "group": "body", - "type": "String", - "optional": true, - "field": "devpostURL", - "description": "

Devpost link to hack. Once the link is sent, the hack will be considered to be submitted.

" - }, - { - "group": "body", - "type": "String", - "optional": true, - "field": "projectName", - "description": "

Name of the team.

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Team object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Team creation successful\", \n \"data\": {...}\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Error while creating team\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/team.js", - "groupTitle": "Team", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/team/" - } - ] - }, - { - "type": "patch", - "url": "/team/leave/", - "title": "Allows a logged in hacker to leave current team", - "name": "deleteSelfFromTeam", - "group": "Team", - "version": "1.1.1", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

{}

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Removal from team successful.\",\n \"data\": {}\n}", - "type": "object" - } - ] - }, - "filename": "routes/api/team.js", - "groupTitle": "Team", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/team/leave/" - } - ] - }, - { - "type": "get", - "url": "/team/:id", - "title": "get a team's information", - "name": "getTeam", - "group": "Team", - "version": "0.0.8", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "ObjectId", - "optional": false, - "field": "id", - "description": "

MongoId of the team

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Team object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Team retrieval successful\", \n \"data\": { \n \"team\": {\n \"name\":\"foo\",\n \"members\": [\n ObjectId('...')\n ],\n \"devpostURL\": \"www.devpost.com/foo\",\n \"projectName\": \"fooey\"\n },\n \"members\": [\n {\n \"firstName\": \"John\",\n \"lastName\": \"Doe\"\n }\n ],\n }\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "String", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "Object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Team not found\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/team.js", - "groupTitle": "Team", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/team/:id" - } - ] - }, - { - "type": "patch", - "url": "/team/join/", - "title": "Allows a logged in hacker to join a team by name", - "name": "patchJoinTeam", - "group": "Team", - "version": "1.1.1", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "string", - "optional": true, - "field": "name", - "description": "

Name of the team to join

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

{}

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Team join successful.\",\n \"data\": {}\n}", - "type": "object" - } - ] - }, - "filename": "routes/api/team.js", - "groupTitle": "Team", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/team/join/" - } - ] - }, - { - "type": "patch", - "url": "/team/:hackerId", - "title": "Update a team's information. The team is specified by the hacker belonging to it.", - "name": "patchTeam", - "group": "Team", - "version": "0.0.8", - "description": "

We use hackerId instead of teamId because authorization requires a one-to-one mapping from param id to accountId, but we are not able to have that from teamId to accountId due to multiple members in a team. Instead, we use hackerId, as there is a 1 to 1 link between hackerId to teamId, and a 1 to 1 link between hackerId and accountId

", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "ObjectId", - "optional": false, - "field": "hackerId", - "description": "

a hacker's unique Id

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Team object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Team update successful.\", \n \"data\": {...}\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "String", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Query input that caused the error.

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Team not found\", \"data\": {teamId}}", - "type": "object" - } - ] - }, - "filename": "routes/api/team.js", - "groupTitle": "Team", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/team/:hackerId" - } - ] - }, - { - "type": "post", - "url": "/travel/", - "title": "create a new travel", - "name": "createTravel", - "group": "Travel", - "version": "2.0.1", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "MongoID", - "optional": false, - "field": "accountId", - "description": "

ObjectID of the respective account

" - }, - { - "group": "body", - "type": "MongoID", - "optional": false, - "field": "hackerId", - "description": "

ObjectID of the respective hacker

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Travel object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Travel creation successful\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"None\",\n \"request\": 50,\n \"offer\": 0\n }\n}", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Error while creating travel\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/travel.js", - "groupTitle": "Travel", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/travel/" - } - ] - }, - { - "type": "get", - "url": "/travel/email/:email", - "title": "get a travel's information", - "name": "getTravel", - "group": "Travel", - "version": "2.0.1", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "String", - "optional": false, - "field": "email", - "description": "

a travel's unique email

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Travel object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Successfully retrieved travel information\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"Valid\",\n \"request\": 100,\n \"offer\": 50\n }\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "String", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "Object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Travel not found\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/travel.js", - "groupTitle": "Travel", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/travel/email/:email" - } - ] - }, - { - "type": "get", - "url": "/travel/:id", - "title": "get a traveler's information", - "name": "getTravel", - "group": "Travel", - "version": "2.0.1", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "String", - "optional": false, - "field": "id", - "description": "

a travel's unique mongoID

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Travel object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Successfully retrieved travel information\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"Valid\",\n \"request\": 100,\n \"offer\": 50\n }\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "String", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "Object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Travel not found\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/travel.js", - "groupTitle": "Travel", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/travel/:id" - } - ] - }, - { - "type": "patch", - "url": "/travel/offer/:id", - "title": "update a traveler's offer", - "name": "patchTravelOffer", - "group": "Travel", - "version": "2.0.1", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "number", - "optional": true, - "field": "offer", - "description": "

Amount of money offered for travel

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Travel object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Changed travel information\",\n \"data\": {\n \"offer\": 75\n }\n}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": "Administrator" - } - ], - "filename": "routes/api/travel.js", - "groupTitle": "Travel", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/travel/offer/:id" - } - ] - }, - { - "type": "patch", - "url": "/travel/status/:id", - "title": "update a traveler's status", - "name": "patchTravelStatus", - "group": "Travel", - "version": "2.0.1", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "string", - "optional": true, - "field": "status", - "description": "

Status of the travel's reimbursement ("None"|"Bus"|"Offered"|"Valid"|"Invalid"|"Claimed")

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Travel object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response:", - "content": "{\n \"message\": \"Changed travel information\",\n \"data\": {\n \"status\": \"Accepted\"\n }\n}", - "type": "object" - } - ] - }, - "permission": [ - { - "name": "Administrator" - } - ], - "filename": "routes/api/travel.js", - "groupTitle": "Travel", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/travel/status/:id" - } - ] - }, - { - "type": "get", - "url": "/travel/self", - "title": "get information about own hacker's travel", - "name": "self", - "group": "Travel", - "version": "2.0.1", - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Travel object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Travel found by logged in account id\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"Claimed\"\n \"request\": 90,\n \"offer\": 80\n } \n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Travel not found\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/travel.js", - "groupTitle": "Travel", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/travel/self" - } - ] - }, - { - "type": "post", - "url": "/volunteer/", - "title": "create a new volunteer", - "name": "createVolunteer", - "group": "Volunteer", - "version": "0.0.8", - "parameter": { - "fields": { - "body": [ - { - "group": "body", - "type": "MongoID", - "optional": false, - "field": "accountId", - "description": "

MongoID of the account of the volunteer

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "string", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "object", - "optional": false, - "field": "data", - "description": "

Volunteer object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Volunteer creation successful\", \n \"data\": {...}\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "string", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Error while creating volunteer\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/volunteer.js", - "groupTitle": "Volunteer", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/volunteer/" - } - ] - }, - { - "type": "get", - "url": "/volunteer/:id", - "title": "get a volunteer's information", - "name": "getVolunteer", - "group": "Volunteer", - "version": "1.3.0", - "parameter": { - "fields": { - "param": [ - { - "group": "param", - "type": "ObjectId", - "optional": false, - "field": "id", - "description": "

a volunteer's unique mongoID

" - } - ] - } - }, - "success": { - "fields": { - "Success 200": [ - { - "group": "Success 200", - "type": "String", - "optional": false, - "field": "message", - "description": "

Success message

" - }, - { - "group": "Success 200", - "type": "Object", - "optional": false, - "field": "data", - "description": "

Volunteer object

" - } - ] - }, - "examples": [ - { - "title": "Success-Response: ", - "content": "{\n \"message\": \"Successfully retrieved volunteer information\", \n \"data\": {...}\n }", - "type": "object" - } - ] - }, - "error": { - "fields": { - "Error 4xx": [ - { - "group": "Error 4xx", - "type": "String", - "optional": false, - "field": "message", - "description": "

Error message

" - }, - { - "group": "Error 4xx", - "type": "Object", - "optional": false, - "field": "data", - "description": "

empty

" - } - ] - }, - "examples": [ - { - "title": "Error-Response: ", - "content": "{\"message\": \"Volunteer not found\", \"data\": {}}", - "type": "object" - } - ] - }, - "filename": "routes/api/volunteer.js", - "groupTitle": "Volunteer", - "sampleRequest": [ - { - "url": "https://api.mchacks.ca/api/volunteer/:id" - } - ] - } -] diff --git a/docs/api/api_project.js b/docs/api/api_project.js deleted file mode 100644 index 3e967754..00000000 --- a/docs/api/api_project.js +++ /dev/null @@ -1 +0,0 @@ -define({ "name": "hackerAPI", "version": "0.0.8", "description": "Documentation for the API used for mchacks", "defaultVersion": "0.0.8", "title": "hackerAPI documentation", "url": "https://api.mchacks.ca/api", "sampleUrl": "https://api.mchacks.ca/api", "apidoc": "0.3.0", "generator": { "name": "apidoc", "time": "2020-11-01T22:01:33.009Z", "url": "http://apidocjs.com", "version": "0.17.7" } }); diff --git a/docs/api/api_project.json b/docs/api/api_project.json deleted file mode 100644 index 586dbd12..00000000 --- a/docs/api/api_project.json +++ /dev/null @@ -1 +0,0 @@ -{ "name": "hackerAPI", "version": "0.0.8", "description": "Documentation for the API used for mchacks", "defaultVersion": "0.0.8", "title": "hackerAPI documentation", "url": "https://api.mchacks.ca/api", "sampleUrl": "https://api.mchacks.ca/api", "apidoc": "0.3.0", "generator": { "name": "apidoc", "time": "2020-11-01T22:01:33.009Z", "url": "http://apidocjs.com", "version": "0.17.7" } } diff --git a/docs/api/css/style.css b/docs/api/css/style.css deleted file mode 100644 index 6468b2b2..00000000 --- a/docs/api/css/style.css +++ /dev/null @@ -1,569 +0,0 @@ -/* ------------------------------------------------------------------------------------------ - * Content - * ------------------------------------------------------------------------------------------ */ -body { - min-width: 980px; - max-width: 1280px; -} - -body, p, a, div, th, td { - font-family: "Source Sans Pro", sans-serif; - font-weight: 400; - font-size: 16px; -} - -td.code { - font-size: 14px; - font-family: "Source Code Pro", monospace; - font-style: normal; - font-weight: 400; -} - -#content { - padding-top: 16px; - z-Index: -1; - margin-left: 270px; -} - -p { - color: #808080; -} - -h1 { - font-family: "Source Sans Pro Semibold", sans-serif; - font-weight: normal; - font-size: 44px; - line-height: 50px; - margin: 0 0 10px 0; - padding: 0; -} - -h2 { - font-family: "Source Sans Pro", sans-serif; - font-weight: normal; - font-size: 24px; - line-height: 40px; - margin: 0 0 20px 0; - padding: 0; -} - -section { - border-top: 1px solid #ebebeb; - padding: 30px 0; -} - -section h1 { - font-family: "Source Sans Pro", sans-serif; - font-weight: 700; - font-size: 32px; - line-height: 40px; - padding-bottom: 14px; - margin: 0 0 20px 0; - padding: 0; -} - -article { - padding: 14px 0 30px 0; -} - -article h1 { - font-family: "Source Sans Pro Bold", sans-serif; - font-weight: 600; - font-size: 24px; - line-height: 26px; -} - -article h2 { - font-family: "Source Sans Pro", sans-serif; - font-weight: 600; - font-size: 18px; - line-height: 24px; - margin: 0 0 10px 0; -} - -article h3 { - font-family: "Source Sans Pro", sans-serif; - font-weight: 600; - font-size: 16px; - line-height: 18px; - margin: 0 0 10px 0; -} - -article h4 { - font-family: "Source Sans Pro", sans-serif; - font-weight: 600; - font-size: 14px; - line-height: 16px; - margin: 0 0 8px 0; -} - -table { - border-collapse: collapse; - width: 100%; - margin: 0 0 20px 0; -} - -th { - background-color: #f5f5f5; - text-align: left; - font-family: "Source Sans Pro", sans-serif; - font-weight: 700; - padding: 4px 8px; - border: #e0e0e0 1px solid; -} - -td { - vertical-align: top; - padding: 10px 8px 0 8px; - border: #e0e0e0 1px solid; -} - -#generator .content { - color: #b0b0b0; - border-top: 1px solid #ebebeb; - padding: 10px 0; -} - -.label-optional { - float: right; - background-color: grey; - margin-top: 4px; -} - -.open-left { - right: 0; - left: auto; -} - -/* ------------------------------------------------------------------------------------------ - * apidoc - intro - * ------------------------------------------------------------------------------------------ */ - -#apidoc .apidoc { - border-top: 1px solid #ebebeb; - padding: 30px 0; -} - -#apidoc h1 { - font-family: "Source Sans Pro", sans-serif; - font-weight: 700; - font-size: 32px; - line-height: 40px; - padding-bottom: 14px; - margin: 0 0 20px 0; - padding: 0; -} - -#apidoc h2 { - font-family: "Source Sans Pro Bold", sans-serif; - font-weight: 600; - font-size: 22px; - line-height: 26px; - padding-top: 14px; -} - -/* ------------------------------------------------------------------------------------------ - * pre / code - * ------------------------------------------------------------------------------------------ */ -pre { - background-color: #292b36; - color: #ffffff; - padding: 10px; - border-radius: 6px; - position: relative; - margin: 10px 0 20px 0; - overflow-x: auto; -} - -pre.prettyprint { - width: 100%; -} - -code.language-text { - word-wrap: break-word; -} - -pre.language-json { - overflow: auto; -} - -pre.language-html { - margin: 0 0 20px 0; -} - -.type { - font-family: "Source Sans Pro", sans-serif; - font-weight: 600; - font-size: 15px; - display: inline-block; - margin: 0 0 5px 0; - padding: 4px 5px; - border-radius: 6px; - text-transform: uppercase; - background-color: #3387CC; - color: #ffffff; -} - -.type__get { - background-color: green; -} - -.type__put { - background-color: #e5c500; -} - -.type__post { - background-color: #4070ec; -} - -.type__delete { - background-color: #ed0039; -} - -pre.language-api .str { - color: #ffffff; -} - -pre.language-api .pln, -pre.language-api .pun { - color: #65B042; -} - -pre code { - display: block; - font-size: 14px; - font-family: "Source Code Pro", monospace; - font-style: normal; - font-weight: 400; - word-wrap: normal; - white-space: pre; -} - -pre code.sample-request-response-json { - white-space: pre-wrap; - max-height: 500px; - overflow: auto; -} - -/* ------------------------------------------------------------------------------------------ - * Sidenav - * ------------------------------------------------------------------------------------------ */ -.sidenav { - width: 228px; - margin: 0; - padding: 0 20px 20px 20px; - position: fixed; - top: 50px; - left: 0; - bottom: 0; - overflow-x: hidden; - overflow-y: auto; - background-color: #f5f5f5; - z-index: 10; -} - -.sidenav > li > a { - display: block; - width: 192px; - margin: 0; - padding: 2px 11px; - border: 0; - border-left: transparent 4px solid; - border-right: transparent 4px solid; - font-family: "Source Sans Pro", sans-serif; - font-weight: 400; - font-size: 14px; -} - -.sidenav > li.nav-header { - margin-top: 8px; - margin-bottom: 8px; -} - -.sidenav > li.nav-header > a { - padding: 5px 15px; - border: 1px solid #e5e5e5; - width: 190px; - font-family: "Source Sans Pro", sans-serif; - font-weight: 700; - font-size: 16px; - background-color: #ffffff; -} - -.sidenav > li.active > a { - position: relative; - z-index: 2; - background-color: #0088cc; - color: #ffffff; -} - -.sidenav > li.has-modifications a { - border-right: #60d060 4px solid; -} - -.sidenav > li.is-new a { - border-left: #e5e5e5 4px solid; -} - -/* ------------------------------------------------------------------------------------------ - * Side nav search - * ------------------------------------------------------------------------------------------ */ -.sidenav-search { - width: 228px; - left: 0px; - position: fixed; - padding: 16px 20px 10px 20px; - background-color: #F5F5F5; - z-index: 11; -} - -.sidenav-search .search { - height: 26px; -} - -.search-reset { - position: absolute; - display: block; - cursor: pointer; - width: 20px; - height: 20px; - text-align: center; - right: 28px; - top: 17px; - background-color: #fff; -} - -/* ------------------------------------------------------------------------------------------ - * Compare - * ------------------------------------------------------------------------------------------ */ - -ins { - background: #60d060; - text-decoration: none; - color: #000000; -} - -del { - background: #f05050; - color: #000000; -} - -.label-ins { - background-color: #60d060; -} - -.label-del { - background-color: #f05050; - text-decoration: line-through; -} - -pre.ins { - background-color: #60d060; -} - -pre.del { - background-color: #f05050; - text-decoration: line-through; -} - -table.ins th, -table.ins td { - background-color: #60d060; -} - -table.del th, -table.del td { - background-color: #f05050; - text-decoration: line-through; -} - -tr.ins td { - background-color: #60d060; -} - -tr.del td { - background-color: #f05050; - text-decoration: line-through; -} - -/* ------------------------------------------------------------------------------------------ - * Spinner - * ------------------------------------------------------------------------------------------ */ - -#loader { - position: absolute; - width: 100%; -} - -#loader p { - padding-top: 80px; - margin-left: -4px; -} - -.spinner { - margin: 200px auto; - width: 60px; - height: 60px; - position: relative; -} - -.container1 > div, .container2 > div, .container3 > div { - width: 14px; - height: 14px; - background-color: #0088cc; - - border-radius: 100%; - position: absolute; - -webkit-animation: bouncedelay 1.2s infinite ease-in-out; - animation: bouncedelay 1.2s infinite ease-in-out; - /* Prevent first frame from flickering when animation starts */ - -webkit-animation-fill-mode: both; - animation-fill-mode: both; -} - -.spinner .spinner-container { - position: absolute; - width: 100%; - height: 100%; -} - -.container2 { - -webkit-transform: rotateZ(45deg); - transform: rotateZ(45deg); -} - -.container3 { - -webkit-transform: rotateZ(90deg); - transform: rotateZ(90deg); -} - -.circle1 { top: 0; left: 0; } -.circle2 { top: 0; right: 0; } -.circle3 { right: 0; bottom: 0; } -.circle4 { left: 0; bottom: 0; } - -.container2 .circle1 { - -webkit-animation-delay: -1.1s; - animation-delay: -1.1s; -} - -.container3 .circle1 { - -webkit-animation-delay: -1.0s; - animation-delay: -1.0s; -} - -.container1 .circle2 { - -webkit-animation-delay: -0.9s; - animation-delay: -0.9s; -} - -.container2 .circle2 { - -webkit-animation-delay: -0.8s; - animation-delay: -0.8s; -} - -.container3 .circle2 { - -webkit-animation-delay: -0.7s; - animation-delay: -0.7s; -} - -.container1 .circle3 { - -webkit-animation-delay: -0.6s; - animation-delay: -0.6s; -} - -.container2 .circle3 { - -webkit-animation-delay: -0.5s; - animation-delay: -0.5s; -} - -.container3 .circle3 { - -webkit-animation-delay: -0.4s; - animation-delay: -0.4s; -} - -.container1 .circle4 { - -webkit-animation-delay: -0.3s; - animation-delay: -0.3s; -} - -.container2 .circle4 { - -webkit-animation-delay: -0.2s; - animation-delay: -0.2s; -} - -.container3 .circle4 { - -webkit-animation-delay: -0.1s; - animation-delay: -0.1s; -} - -@-webkit-keyframes bouncedelay { - 0%, 80%, 100% { -webkit-transform: scale(0.0) } - 40% { -webkit-transform: scale(1.0) } -} - -@keyframes bouncedelay { - 0%, 80%, 100% { - transform: scale(0.0); - -webkit-transform: scale(0.0); - } 40% { - transform: scale(1.0); - -webkit-transform: scale(1.0); - } -} - -/* ------------------------------------------------------------------------------------------ - * Tabs - * ------------------------------------------------------------------------------------------ */ -ul.nav-tabs { - margin: 0; -} - -p.deprecated span{ - color: #ff0000; - font-weight: bold; - text-decoration: underline; -} - -/* ------------------------------------------------------------------------------------------ - * Print - * ------------------------------------------------------------------------------------------ */ - -@media print { - - #sidenav, - #version, - #versions, - section .version, - section .versions { - display: none; - } - - #content { - margin-left: 0; - } - - a { - text-decoration: none; - color: inherit; - } - - a:after { - content: " [" attr(href) "] "; - } - - p { - color: #000000 - } - - pre { - background-color: #ffffff; - color: #000000; - padding: 10px; - border: #808080 1px solid; - border-radius: 6px; - position: relative; - margin: 10px 0 20px 0; - } - -} /* /@media print */ diff --git a/docs/api/fonts/glyphicons-halflings-regular.eot b/docs/api/fonts/glyphicons-halflings-regular.eot deleted file mode 100644 index b93a4953fff68df523aa7656497ee339d6026d64..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20127 zcma%hV{j!vx9y2-`@~L8?1^pLwlPU2wr$&<*tR|KBoo`2;LUg6eW-eW-tKDb)vH%` z^`A!Vd<6hNSRMcX|Cb;E|1qflDggj6Kmr)xA10^t-vIc3*Z+F{r%|K(GyE^?|I{=9 zNq`(c8=wS`0!RZy0g3{M(8^tv41d}oRU?8#IBFtJy*9zAN5dcxqGlMZGL>GG%R#)4J zDJ2;)4*E1pyHia%>lMv3X7Q`UoFyoB@|xvh^)kOE3)IL&0(G&i;g08s>c%~pHkN&6 z($7!kyv|A2DsV2mq-5Ku)D#$Kn$CzqD-wm5Q*OtEOEZe^&T$xIb0NUL}$)W)Ck`6oter6KcQG9Zcy>lXip)%e&!lQgtQ*N`#abOlytt!&i3fo)cKV zP0BWmLxS1gQv(r_r|?9>rR0ZeEJPx;Vi|h1!Eo*dohr&^lJgqJZns>&vexP@fs zkPv93Nyw$-kM5Mw^{@wPU47Y1dSkiHyl3dtHLwV&6Tm1iv{ve;sYA}Z&kmH802s9Z zyJEn+cfl7yFu#1^#DbtP7k&aR06|n{LnYFYEphKd@dJEq@)s#S)UA&8VJY@S2+{~> z(4?M();zvayyd^j`@4>xCqH|Au>Sfzb$mEOcD7e4z8pPVRTiMUWiw;|gXHw7LS#U< zsT(}Z5SJ)CRMXloh$qPnK77w_)ctHmgh}QAe<2S{DU^`!uwptCoq!Owz$u6bF)vnb zL`bM$%>baN7l#)vtS3y6h*2?xCk z>w+s)@`O4(4_I{L-!+b%)NZcQ&ND=2lyP+xI#9OzsiY8$c)ys-MI?TG6 zEP6f=vuLo!G>J7F4v|s#lJ+7A`^nEQScH3e?B_jC&{sj>m zYD?!1z4nDG_Afi$!J(<{>z{~Q)$SaXWjj~%ZvF152Hd^VoG14rFykR=_TO)mCn&K$ z-TfZ!vMBvnToyBoKRkD{3=&=qD|L!vb#jf1f}2338z)e)g>7#NPe!FoaY*jY{f)Bf>ohk-K z4{>fVS}ZCicCqgLuYR_fYx2;*-4k>kffuywghn?15s1dIOOYfl+XLf5w?wtU2Og*f z%X5x`H55F6g1>m~%F`655-W1wFJtY>>qNSdVT`M`1Mlh!5Q6#3j={n5#za;!X&^OJ zgq;d4UJV-F>gg?c3Y?d=kvn3eV)Jb^ zO5vg0G0yN0%}xy#(6oTDSVw8l=_*2k;zTP?+N=*18H5wp`s90K-C67q{W3d8vQGmr zhpW^>1HEQV2TG#8_P_0q91h8QgHT~8=-Ij5snJ3cj?Jn5_66uV=*pq(j}yHnf$Ft;5VVC?bz%9X31asJeQF2jEa47H#j` zk&uxf3t?g!tltVP|B#G_UfDD}`<#B#iY^i>oDd-LGF}A@Fno~dR72c&hs6bR z2F}9(i8+PR%R|~FV$;Ke^Q_E_Bc;$)xN4Ti>Lgg4vaip!%M z06oxAF_*)LH57w|gCW3SwoEHwjO{}}U=pKhjKSZ{u!K?1zm1q? zXyA6y@)}_sONiJopF}_}(~}d4FDyp|(@w}Vb;Fl5bZL%{1`}gdw#i{KMjp2@Fb9pg ziO|u7qP{$kxH$qh8%L+)AvwZNgUT6^zsZq-MRyZid{D?t`f|KzSAD~C?WT3d0rO`0 z=qQ6{)&UXXuHY{9g|P7l_nd-%eh}4%VVaK#Nik*tOu9lBM$<%FS@`NwGEbP0&;Xbo zObCq=y%a`jSJmx_uTLa{@2@}^&F4c%z6oe-TN&idjv+8E|$FHOvBqg5hT zMB=7SHq`_-E?5g=()*!V>rIa&LcX(RU}aLm*38U_V$C_g4)7GrW5$GnvTwJZdBmy6 z*X)wi3=R8L=esOhY0a&eH`^fSpUHV8h$J1|o^3fKO|9QzaiKu>yZ9wmRkW?HTkc<*v7i*ylJ#u#j zD1-n&{B`04oG>0Jn{5PKP*4Qsz{~`VVA3578gA+JUkiPc$Iq!^K|}*p_z3(-c&5z@ zKxmdNpp2&wg&%xL3xZNzG-5Xt7jnI@{?c z25=M>-VF|;an2Os$Nn%HgQz7m(ujC}Ii0Oesa(y#8>D+P*_m^X##E|h$M6tJr%#=P zWP*)Px>7z`E~U^2LNCNiy%Z7!!6RI%6fF@#ZY3z`CK91}^J$F!EB0YF1je9hJKU7!S5MnXV{+#K;y zF~s*H%p@vj&-ru7#(F2L+_;IH46X(z{~HTfcThqD%b{>~u@lSc<+f5#xgt9L7$gSK ziDJ6D*R%4&YeUB@yu@4+&70MBNTnjRyqMRd+@&lU#rV%0t3OmouhC`mkN}pL>tXin zY*p)mt=}$EGT2E<4Q>E2`6)gZ`QJhGDNpI}bZL9}m+R>q?l`OzFjW?)Y)P`fUH(_4 zCb?sm1=DD0+Q5v}BW#0n5;Nm(@RTEa3(Y17H2H67La+>ptQHJ@WMy2xRQT$|7l`8c zYHCxYw2o-rI?(fR2-%}pbs$I%w_&LPYE{4bo}vRoAW>3!SY_zH3`ofx3F1PsQ?&iq z*BRG>?<6%z=x#`NhlEq{K~&rU7Kc7Y-90aRnoj~rVoKae)L$3^z*Utppk?I`)CX&& zZ^@Go9fm&fN`b`XY zt0xE5aw4t@qTg_k=!-5LXU+_~DlW?53!afv6W(k@FPPX-`nA!FBMp7b!ODbL1zh58 z*69I}P_-?qSLKj}JW7gP!la}K@M}L>v?rDD!DY-tu+onu9kLoJz20M4urX_xf2dfZ zORd9Zp&28_ff=wdMpXi%IiTTNegC}~RLkdYjA39kWqlA?jO~o1`*B&85Hd%VPkYZT z48MPe62;TOq#c%H(`wX5(Bu>nlh4Fbd*Npasdhh?oRy8a;NB2(eb}6DgwXtx=n}fE zx67rYw=(s0r?EsPjaya}^Qc-_UT5|*@|$Q}*|>V3O~USkIe6a0_>vd~6kHuP8=m}_ zo2IGKbv;yA+TBtlCpnw)8hDn&eq?26gN$Bh;SdxaS04Fsaih_Cfb98s39xbv)=mS0 z6M<@pM2#pe32w*lYSWG>DYqB95XhgAA)*9dOxHr{t)er0Xugoy)!Vz#2C3FaUMzYl zCxy{igFB901*R2*F4>grPF}+G`;Yh zGi@nRjWyG3mR(BVOeBPOF=_&}2IWT%)pqdNAcL{eP`L*^FDv#Rzql5U&Suq_X%JfR_lC!S|y|xd5mQ0{0!G#9hV46S~A` z0B!{yI-4FZEtol5)mNWXcX(`x&Pc*&gh4k{w%0S#EI>rqqlH2xv7mR=9XNCI$V#NG z4wb-@u{PfQP;tTbzK>(DF(~bKp3;L1-A*HS!VB)Ae>Acnvde15Anb`h;I&0)aZBS6 z55ZS7mL5Wp!LCt45^{2_70YiI_Py=X{I3>$Px5Ez0ahLQ+ z9EWUWSyzA|+g-Axp*Lx-M{!ReQO07EG7r4^)K(xbj@%ZU=0tBC5shl)1a!ifM5OkF z0w2xQ-<+r-h1fi7B6waX15|*GGqfva)S)dVcgea`lQ~SQ$KXPR+(3Tn2I2R<0 z9tK`L*pa^+*n%>tZPiqt{_`%v?Bb7CR-!GhMON_Fbs0$#|H}G?rW|{q5fQhvw!FxI zs-5ZK>hAbnCS#ZQVi5K0X3PjL1JRdQO+&)*!oRCqB{wen60P6!7bGiWn@vD|+E@Xq zb!!_WiU^I|@1M}Hz6fN-m04x=>Exm{b@>UCW|c8vC`aNbtA@KCHujh^2RWZC}iYhL^<*Z93chIBJYU&w>$CGZDRcHuIgF&oyesDZ#&mA;?wxx4Cm#c0V$xYG?9OL(Smh}#fFuX(K;otJmvRP{h ze^f-qv;)HKC7geB92_@3a9@MGijS(hNNVd%-rZ;%@F_f7?Fjinbe1( zn#jQ*jKZTqE+AUTEd3y6t>*=;AO##cmdwU4gc2&rT8l`rtKW2JF<`_M#p>cj+)yCG zgKF)y8jrfxTjGO&ccm8RU>qn|HxQ7Z#sUo$q)P5H%8iBF$({0Ya51-rA@!It#NHN8MxqK zrYyl_&=}WVfQ?+ykV4*@F6)=u_~3BebR2G2>>mKaEBPmSW3(qYGGXj??m3L zHec{@jWCsSD8`xUy0pqT?Sw0oD?AUK*WxZn#D>-$`eI+IT)6ki>ic}W)t$V32^ITD zR497@LO}S|re%A+#vdv-?fXsQGVnP?QB_d0cGE+U84Q=aM=XrOwGFN3`Lpl@P0fL$ zKN1PqOwojH*($uaQFh8_)H#>Acl&UBSZ>!2W1Dinei`R4dJGX$;~60X=|SG6#jci} z&t4*dVDR*;+6Y(G{KGj1B2!qjvDYOyPC}%hnPbJ@g(4yBJrViG1#$$X75y+Ul1{%x zBAuD}Q@w?MFNqF-m39FGpq7RGI?%Bvyyig&oGv)lR>d<`Bqh=p>urib5DE;u$c|$J zwim~nPb19t?LJZsm{<(Iyyt@~H!a4yywmHKW&=1r5+oj*Fx6c89heW@(2R`i!Uiy* zp)=`Vr8sR!)KChE-6SEIyi(dvG3<1KoVt>kGV=zZiG7LGonH1+~yOK-`g0)r#+O|Q>)a`I2FVW%wr3lhO(P{ksNQuR!G_d zeTx(M!%brW_vS9?IF>bzZ2A3mWX-MEaOk^V|4d38{1D|KOlZSjBKrj7Fgf^>JyL0k zLoI$adZJ0T+8i_Idsuj}C;6jgx9LY#Ukh;!8eJ^B1N}q=Gn4onF*a2vY7~`x$r@rJ z`*hi&Z2lazgu{&nz>gjd>#eq*IFlXed(%$s5!HRXKNm zDZld+DwDI`O6hyn2uJ)F^{^;ESf9sjJ)wMSKD~R=DqPBHyP!?cGAvL<1|7K-(=?VO zGcKcF1spUa+ki<`6K#@QxOTsd847N8WSWztG~?~ z!gUJn>z0O=_)VCE|56hkT~n5xXTp}Ucx$Ii%bQ{5;-a4~I2e|{l9ur#*ghd*hSqO= z)GD@ev^w&5%k}YYB~!A%3*XbPPU-N6&3Lp1LxyP@|C<{qcn&?l54+zyMk&I3YDT|E z{lXH-e?C{huu<@~li+73lMOk&k)3s7Asn$t6!PtXJV!RkA`qdo4|OC_a?vR!kE_}k zK5R9KB%V@R7gt@9=TGL{=#r2gl!@3G;k-6sXp&E4u20DgvbY$iE**Xqj3TyxK>3AU z!b9}NXuINqt>Htt6fXIy5mj7oZ{A&$XJ&thR5ySE{mkxq_YooME#VCHm2+3D!f`{) zvR^WSjy_h4v^|!RJV-RaIT2Ctv=)UMMn@fAgjQV$2G+4?&dGA8vK35c-8r)z9Qqa=%k(FU)?iec14<^olkOU3p zF-6`zHiDKPafKK^USUU+D01>C&Wh{{q?>5m zGQp|z*+#>IIo=|ae8CtrN@@t~uLFOeT{}vX(IY*;>wAU=u1Qo4c+a&R);$^VCr>;! zv4L{`lHgc9$BeM)pQ#XA_(Q#=_iSZL4>L~8Hx}NmOC$&*Q*bq|9Aq}rWgFnMDl~d*;7c44GipcpH9PWaBy-G$*MI^F0 z?Tdxir1D<2ui+Q#^c4?uKvq=p>)lq56=Eb|N^qz~w7rsZu)@E4$;~snz+wIxi+980O6M#RmtgLYh@|2}9BiHSpTs zacjGKvwkUwR3lwTSsCHlwb&*(onU;)$yvdhikonn|B44JMgs*&Lo!jn`6AE>XvBiO z*LKNX3FVz9yLcsnmL!cRVO_qv=yIM#X|u&}#f%_?Tj0>8)8P_0r0!AjWNw;S44tst zv+NXY1{zRLf9OYMr6H-z?4CF$Y%MdbpFIN@a-LEnmkcOF>h16cH_;A|e)pJTuCJ4O zY7!4FxT4>4aFT8a92}84>q0&?46h>&0Vv0p>u~k&qd5$C1A6Q$I4V(5X~6{15;PD@ ze6!s9xh#^QI`J+%8*=^(-!P!@9%~buBmN2VSAp@TOo6}C?az+ALP8~&a0FWZk*F5N z^8P8IREnN`N0i@>O0?{i-FoFShYbUB`D7O4HB`Im2{yzXmyrg$k>cY6A@>bf7i3n0 z5y&cf2#`zctT>dz+hNF&+d3g;2)U!#vsb-%LC+pqKRTiiSn#FH#e!bVwR1nAf*TG^ z!RKcCy$P>?Sfq6n<%M{T0I8?p@HlgwC!HoWO>~mT+X<{Ylm+$Vtj9};H3$EB}P2wR$3y!TO#$iY8eO-!}+F&jMu4%E6S>m zB(N4w9O@2=<`WNJay5PwP8javDp~o~xkSbd4t4t8)9jqu@bHmJHq=MV~Pt|(TghCA}fhMS?s-{klV>~=VrT$nsp7mf{?cze~KKOD4 z_1Y!F)*7^W+BBTt1R2h4f1X4Oy2%?=IMhZU8c{qk3xI1=!na*Sg<=A$?K=Y=GUR9@ zQ(ylIm4Lgm>pt#%p`zHxok%vx_=8Fap1|?OM02|N%X-g5_#S~sT@A!x&8k#wVI2lo z1Uyj{tDQRpb*>c}mjU^gYA9{7mNhFAlM=wZkXcA#MHXWMEs^3>p9X)Oa?dx7b%N*y zLz@K^%1JaArjgri;8ptNHwz1<0y8tcURSbHsm=26^@CYJ3hwMaEvC7 z3Wi-@AaXIQ)%F6#i@%M>?Mw7$6(kW@?et@wbk-APcvMCC{>iew#vkZej8%9h0JSc? zCb~K|!9cBU+))^q*co(E^9jRl7gR4Jihyqa(Z(P&ID#TPyysVNL7(^;?Gan!OU>au zN}miBc&XX-M$mSv%3xs)bh>Jq9#aD_l|zO?I+p4_5qI0Ms*OZyyxA`sXcyiy>-{YN zA70%HmibZYcHW&YOHk6S&PQ+$rJ3(utuUra3V0~@=_~QZy&nc~)AS>v&<6$gErZC3 zcbC=eVkV4Vu0#}E*r=&{X)Kgq|8MGCh(wsH4geLj@#8EGYa})K2;n z{1~=ghoz=9TSCxgzr5x3@sQZZ0FZ+t{?klSI_IZa16pSx6*;=O%n!uXVZ@1IL;JEV zfOS&yyfE9dtS*^jmgt6>jQDOIJM5Gx#Y2eAcC3l^lmoJ{o0T>IHpECTbfYgPI4#LZq0PKqnPCD}_ zyKxz;(`fE0z~nA1s?d{X2!#ZP8wUHzFSOoTWQrk%;wCnBV_3D%3@EC|u$Ao)tO|AO z$4&aa!wbf}rbNcP{6=ajgg(`p5kTeu$ji20`zw)X1SH*x zN?T36{d9TY*S896Ijc^!35LLUByY4QO=ARCQ#MMCjudFc7s!z%P$6DESz%zZ#>H|i zw3Mc@v4~{Eke;FWs`5i@ifeYPh-Sb#vCa#qJPL|&quSKF%sp8*n#t?vIE7kFWjNFh zJC@u^bRQ^?ra|%39Ux^Dn4I}QICyDKF0mpe+Bk}!lFlqS^WpYm&xwIYxUoS-rJ)N9 z1Tz*6Rl9;x`4lwS1cgW^H_M*)Dt*DX*W?ArBf?-t|1~ge&S}xM0K;U9Ibf{okZHf~ z#4v4qc6s6Zgm8iKch5VMbQc~_V-ZviirnKCi*ouN^c_2lo&-M;YSA>W>>^5tlXObg zacX$k0=9Tf$Eg+#9k6yV(R5-&F{=DHP8!yvSQ`Y~XRnUx@{O$-bGCksk~3&qH^dqX zkf+ZZ?Nv5u>LBM@2?k%k&_aUb5Xjqf#!&7%zN#VZwmv65ezo^Y4S#(ed0yUn4tFOB zh1f1SJ6_s?a{)u6VdwUC!Hv=8`%T9(^c`2hc9nt$(q{Dm2X)dK49ba+KEheQ;7^0) ziFKw$%EHy_B1)M>=yK^=Z$U-LT36yX>EKT zvD8IAom2&2?bTmX@_PBR4W|p?6?LQ+&UMzXxqHC5VHzf@Eb1u)kwyfy+NOM8Wa2y@ zNNDL0PE$F;yFyf^jy&RGwDXQwYw6yz>OMWvJt98X@;yr!*RQDBE- zE*l*u=($Zi1}0-Y4lGaK?J$yQjgb+*ljUvNQ!;QYAoCq@>70=sJ{o{^21^?zT@r~hhf&O;Qiq+ ziGQQLG*D@5;LZ%09mwMiE4Q{IPUx-emo*;a6#DrmWr(zY27d@ezre)Z1BGZdo&pXn z+);gOFelKDmnjq#8dL7CTiVH)dHOqWi~uE|NM^QI3EqxE6+_n>IW67~UB#J==QOGF zp_S)c8TJ}uiaEiaER}MyB(grNn=2m&0yztA=!%3xUREyuG_jmadN*D&1nxvjZ6^+2 zORi7iX1iPi$tKasppaR9$a3IUmrrX)m*)fg1>H+$KpqeB*G>AQV((-G{}h=qItj|d zz~{5@{?&Dab6;0c7!!%Se>w($RmlG7Jlv_zV3Ru8b2rugY0MVPOOYGlokI7%nhIy& z-B&wE=lh2dtD!F?noD{z^O1~Tq4MhxvchzuT_oF3-t4YyA*MJ*n&+1X3~6quEN z@m~aEp=b2~mP+}TUP^FmkRS_PDMA{B zaSy(P=$T~R!yc^Ye0*pl5xcpm_JWI;@-di+nruhqZ4gy7cq-)I&s&Bt3BkgT(Zdjf zTvvv0)8xzntEtp4iXm}~cT+pi5k{w{(Z@l2XU9lHr4Vy~3ycA_T?V(QS{qwt?v|}k z_ST!s;C4!jyV5)^6xC#v!o*uS%a-jQ6< z)>o?z7=+zNNtIz1*F_HJ(w@=`E+T|9TqhC(g7kKDc8z~?RbKQ)LRMn7A1p*PcX2YR zUAr{);~c7I#3Ssv<0i-Woj0&Z4a!u|@Xt2J1>N-|ED<3$o2V?OwL4oQ%$@!zLamVz zB)K&Ik^~GOmDAa143{I4?XUk1<3-k{<%?&OID&>Ud%z*Rkt*)mko0RwC2=qFf-^OV z=d@47?tY=A;=2VAh0mF(3x;!#X!%{|vn;U2XW{(nu5b&8kOr)Kop3-5_xnK5oO_3y z!EaIb{r%D{7zwtGgFVri4_!yUIGwR(xEV3YWSI_+E}Gdl>TINWsIrfj+7DE?xp+5^ zlr3pM-Cbse*WGKOd3+*Qen^*uHk)+EpH-{u@i%y}Z!YSid<}~kA*IRSk|nf+I1N=2 zIKi+&ej%Al-M5`cP^XU>9A(m7G>58>o|}j0ZWbMg&x`*$B9j#Rnyo0#=BMLdo%=ks zLa3(2EinQLXQ(3zDe7Bce%Oszu%?8PO648TNst4SMFvj=+{b%)ELyB!0`B?9R6aO{i-63|s@|raSQGL~s)9R#J#duFaTSZ2M{X z1?YuM*a!!|jP^QJ(hAisJuPOM`8Y-Hzl~%d@latwj}t&0{DNNC+zJARnuQfiN`HQ# z?boY_2?*q;Qk)LUB)s8(Lz5elaW56p&fDH*AWAq7Zrbeq1!?FBGYHCnFgRu5y1jwD zc|yBz+UW|X`zDsc{W~8m$sh@VVnZD$lLnKlq@Hg^;ky!}ZuPdKNi2BI70;hrpvaA4+Q_+K)I@|)q1N-H zrycZU`*YUW``Qi^`bDX-j7j^&bO+-Xg$cz2#i##($uyW{Nl&{DK{=lLWV3|=<&si||2)l=8^8_z+Vho-#5LB0EqQ3v5U#*DF7 zxT)1j^`m+lW}p$>WSIG1eZ>L|YR-@Feu!YNWiw*IZYh03mq+2QVtQ}1ezRJM?0PA< z;mK(J5@N8>u@<6Y$QAHWNE};rR|)U_&bv8dsnsza7{=zD1VBcxrALqnOf-qW(zzTn zTAp|pEo#FsQ$~*$j|~Q;$Zy&Liu9OM;VF@#_&*nL!N2hH!Q6l*OeTxq!l>dEc{;Hw zCQni{iN%jHU*C;?M-VUaXxf0FEJ_G=C8)C-wD!DvhY+qQ#FT3}Th8;GgV&AV94F`D ztT6=w_Xm8)*)dBnDkZd~UWL|W=Glu!$hc|1w7_7l!3MAt95oIp4Xp{M%clu&TXehO z+L-1#{mjkpTF@?|w1P98OCky~S%@OR&o75P&ZHvC}Y=(2_{ib(-Al_7aZ^U?s34#H}= zGfFi5%KnFVCKtdO^>Htpb07#BeCXMDO8U}crpe1Gm`>Q=6qB4i=nLoLZ%p$TY=OcP z)r}Et-Ed??u~f09d3Nx3bS@ja!fV(Dfa5lXxRs#;8?Y8G+Qvz+iv7fiRkL3liip}) z&G0u8RdEC9c$$rdU53=MH`p!Jn|DHjhOxHK$tW_pw9wCTf0Eo<){HoN=zG!!Gq4z4 z7PwGh)VNPXW-cE#MtofE`-$9~nmmj}m zlzZscQ2+Jq%gaB9rMgVJkbhup0Ggpb)&L01T=%>n7-?v@I8!Q(p&+!fd+Y^Pu9l+u zek(_$^HYFVRRIFt@0Fp52g5Q#I`tC3li`;UtDLP*rA{-#Yoa5qp{cD)QYhldihWe+ zG~zuaqLY~$-1sjh2lkbXCX;lq+p~!2Z=76cvuQe*Fl>IFwpUBP+d^&E4BGc{m#l%Kuo6#{XGoRyFc%Hqhf|%nYd<;yiC>tyEyk z4I+a`(%%Ie=-*n z-{mg=j&t12)LH3R?@-B1tEb7FLMePI1HK0`Ae@#)KcS%!Qt9p4_fmBl5zhO10n401 zBSfnfJ;?_r{%R)hh}BBNSl=$BiAKbuWrNGQUZ)+0=Mt&5!X*D@yGCSaMNY&@`;^a4 z;v=%D_!K!WXV1!3%4P-M*s%V2b#2jF2bk!)#2GLVuGKd#vNpRMyg`kstw0GQ8@^k^ zuqK5uR<>FeRZ#3{%!|4X!hh7hgirQ@Mwg%%ez8pF!N$xhMNQN((yS(F2-OfduxxKE zxY#7O(VGfNuLv-ImAw5+h@gwn%!ER;*Q+001;W7W^waWT%@(T+5k!c3A-j)a8y11t zx4~rSN0s$M8HEOzkcWW4YbKK9GQez2XJ|Nq?TFy;jmGbg;`m&%U4hIiarKmdTHt#l zL=H;ZHE?fYxKQQXKnC+K!TAU}r086{4m}r()-QaFmU(qWhJlc$eas&y?=H9EYQy8N$8^bni9TpDp zkA^WRs?KgYgjxX4T6?`SMs$`s3vlut(YU~f2F+id(Rf_)$BIMibk9lACI~LA+i7xn z%-+=DHV*0TCTJp~-|$VZ@g2vmd*|2QXV;HeTzt530KyK>v&253N1l}bP_J#UjLy4) zBJili9#-ey8Kj(dxmW^ctorxd;te|xo)%46l%5qE-YhAjP`Cc03vT)vV&GAV%#Cgb zX~2}uWNvh`2<*AuxuJpq>SyNtZwzuU)r@@dqC@v=Ocd(HnnzytN+M&|Qi#f4Q8D=h ziE<3ziFW%+!yy(q{il8H44g^5{_+pH60Mx5Z*FgC_3hKxmeJ+wVuX?T#ZfOOD3E4C zRJsj#wA@3uvwZwHKKGN{{Ag+8^cs?S4N@6(Wkd$CkoCst(Z&hp+l=ffZ?2m%%ffI3 zdV7coR`R+*dPbNx=*ivWeNJK=Iy_vKd`-_Hng{l?hmp=|T3U&epbmgXXWs9ySE|=G zeQ|^ioL}tveN{s72_&h+F+W;G}?;?_s@h5>DX(rp#eaZ!E=NivgLI zWykLKev+}sHH41NCRm7W>K+_qdoJ8x9o5Cf!)|qLtF7Izxk*p|fX8UqEY)_sI_45O zL2u>x=r5xLE%s|d%MO>zU%KV6QKFiEeo12g#bhei4!Hm+`~Fo~4h|BJ)%ENxy9)Up zOxupSf1QZWun=)gF{L0YWJ<(r0?$bPFANrmphJ>kG`&7E+RgrWQi}ZS#-CQJ*i#8j zM_A0?w@4Mq@xvk^>QSvEU|VYQoVI=TaOrsLTa`RZfe8{9F~mM{L+C`9YP9?OknLw| zmkvz>cS6`pF0FYeLdY%>u&XpPj5$*iYkj=m7wMzHqzZ5SG~$i_^f@QEPEC+<2nf-{ zE7W+n%)q$!5@2pBuXMxhUSi*%F>e_g!$T-_`ovjBh(3jK9Q^~OR{)}!0}vdTE^M+m z9QWsA?xG>EW;U~5gEuKR)Ubfi&YWnXV;3H6Zt^NE725*`;lpSK4HS1sN?{~9a4JkD z%}23oAovytUKfRN87XTH2c=kq1)O5(fH_M3M-o{{@&~KD`~TRot-gqg7Q2U2o-iiF}K>m?CokhmODaLB z1p6(6JYGntNOg(s!(>ZU&lzDf+Ur)^Lirm%*}Z>T)9)fAZ9>k(kvnM;ab$ptA=hoh zVgsVaveXbMpm{|4*d<0>?l_JUFOO8A3xNLQOh%nVXjYI6X8h?a@6kDe5-m&;M0xqx z+1U$s>(P9P)f0!{z%M@E7|9nn#IWgEx6A6JNJ(7dk`%6$3@!C!l;JK-p2?gg+W|d- ziEzgk$w7k48NMqg$CM*4O~Abj3+_yUKTyK1p6GDsGEs;}=E_q>^LI-~pym$qhXPJf z2`!PJDp4l(TTm#|n@bN!j;-FFOM__eLl!6{*}z=)UAcGYloj?bv!-XY1TA6Xz;82J zLRaF{8ayzGa|}c--}|^xh)xgX>6R(sZD|Z|qX50gu=d`gEwHqC@WYU7{%<5VOnf9+ zB@FX?|UL%`8EIAe!*UdYl|6wRz6Y>(#8x92$#y}wMeE|ZM2X*c}dKJ^4NIf;Fm zNwzq%QcO?$NR-7`su!*$dlIKo2y(N;qgH@1|8QNo$0wbyyJ2^}$iZ>M{BhBjTdMjK z>gPEzgX4;g3$rU?jvDeOq`X=>)zdt|jk1Lv3u~bjHI=EGLfIR&+K3ldcc4D&Um&04 z3^F*}WaxR(ZyaB>DlmF_UP@+Q*h$&nsOB#gwLt{1#F4i-{A5J@`>B9@{^i?g_Ce&O z<<}_We-RUFU&&MHa1#t56u_oM(Ljn7djja!T|gcxSoR=)@?owC*NkDarpBj=W4}=i1@)@L|C) zQKA+o<(pMVp*Su(`zBC0l1yTa$MRfQ#uby|$mlOMs=G`4J|?apMzKei%jZql#gP@IkOaOjB7MJM=@1j(&!jNnyVkn5;4lvro1!vq ztXiV8HYj5%)r1PPpIOj)f!>pc^3#LvfZ(hz}C@-3R(Cx7R427*Fwd!XO z4~j&IkPHcBm0h_|iG;ZNrYdJ4HI!$rSyo&sibmwIgm1|J#g6%>=ML1r!kcEhm(XY& zD@mIJt;!O%WP7CE&wwE3?1-dt;RTHdm~LvP7K`ccWXkZ0kfFa2S;wGtx_a}S2lslw z$<4^Jg-n#Ypc(3t2N67Juasu=h)j&UNTPNDil4MQMTlnI81kY46uMH5B^U{~nmc6+ z9>(lGhhvRK9ITfpAD!XQ&BPphL3p8B4PVBN0NF6U49;ZA0Tr75AgGw7(S=Yio+xg_ zepZ*?V#KD;sHH+15ix&yCs0eSB-Z%D%uujlXvT#V$Rz@$+w!u#3GIo*AwMI#Bm^oO zLr1e}k5W~G0xaO!C%Mb{sarxWZ4%Dn9vG`KHmPC9GWZwOOm11XJp#o0-P-${3m4g( z6~)X9FXw%Xm~&99tj>a-ri})ZcnsfJtc10F@t9xF5vq6E)X!iUXHq-ohlO`gQdS&k zZl})3k||u)!_=nNlvMbz%AuIr89l#I$;rG}qvDGiK?xTd5HzMQkw*p$YvFLGyQM!J zNC^gD!kP{A84nGosi~@MLKqWQNacfs7O$dkZtm4-BZ~iA8xWZPkTK!HpA5zr!9Z&+icfAJ1)NWkTd!-9`NWU>9uXXUr;`Js#NbKFgrNhTcY4GNv*71}}T zFJh?>=EcbUd2<|fiL+H=wMw8hbX6?+_cl4XnCB#ddwdG>bki* zt*&6Dy&EIPluL@A3_;R%)shA-tDQA1!Tw4ffBRyy;2n)vm_JV06(4Or&QAOKNZB5f(MVC}&_!B>098R{Simr!UG}?CW1Ah+X+0#~0`X)od zLYablwmFxN21L))!_zc`IfzWi`5>MxPe(DmjjO1}HHt7TJtAW+VXHt!aKZk>y6PoMsbDXRJnov;D~Ur~2R_7(Xr)aa%wJwZhS3gr7IGgt%@;`jpL@gyc6bGCVx!9CE7NgIbUNZ!Ur1RHror0~ zr(j$^yM4j`#c2KxSP61;(Tk^pe7b~}LWj~SZC=MEpdKf;B@on9=?_n|R|0q;Y*1_@ z>nGq>)&q!;u-8H)WCwtL&7F4vbnnfSAlK1mwnRq2&gZrEr!b1MA z(3%vAbh3aU-IX`d7b@q`-WiT6eitu}ZH9x#d&qx}?CtDuAXak%5<-P!{a`V=$|XmJ zUn@4lX6#ulB@a=&-9HG)a>KkH=jE7>&S&N~0X0zD=Q=t|7w;kuh#cU=NN7gBGbQTT z;?bdSt8V&IIi}sDTzA0dkU}Z-Qvg;RDe8v>468p3*&hbGT1I3hi9hh~Z(!H}{+>eUyF)H&gdrX=k$aB%J6I;6+^^kn1mL+E+?A!A}@xV(Qa@M%HD5C@+-4Mb4lI=Xp=@9+^x+jhtOc zYgF2aVa(uSR*n(O)e6tf3JEg2xs#dJfhEmi1iOmDYWk|wXNHU?g23^IGKB&yHnsm7 zm_+;p?YpA#N*7vXCkeN2LTNG`{QDa#U3fcFz7SB)83=<8rF)|udrEbrZL$o6W?oDR zQx!178Ih9B#D9Ko$H(jD{4MME&<|6%MPu|TfOc#E0B}!j^MMpV69D#h2`vsEQ{(?c zJ3Lh!3&=yS5fWL~;1wCZ?)%nmK`Eqgcu)O6rD^3%ijcxL50^z?OI(LaVDvfL0#zjZ z2?cPvC$QCzpxpt5jMFp05OxhK0F!Q`rPhDi5)y=-0C} zIM~ku&S@pl1&0=jl+rlS<4`riV~LC-#pqNde@44MB(j%)On$0Ko(@q?4`1?4149Z_ zZi!5aU@2vM$dHR6WSZpj+VboK+>u-CbNi7*lw4K^ZxxM#24_Yc`jvb9NPVi75L+MlM^U~`;a7`4H0L|TYK>%hfEfXLsu1JGM zbh|8{wuc7ucV+`Ys1kqxsj`dajwyM;^X^`)#<+a~$WFy8b2t_RS{8yNYKKlnv+>vB zX(QTf$kqrJ;%I@EwEs{cIcH@Z3|#^S@M+5jsP<^`@8^I4_8MlBb`~cE^n+{{;qW2q z=p1=&+fUo%T{GhVX@;56kH8K_%?X=;$OTYqW1L*)hzelm^$*?_K;9JyIWhsn4SK(| zSmXLTUE8VQX{se#8#Rj*lz`xHtT<61V~fb;WZUpu(M)f#;I+2_zR+)y5Jv?l`CxAinx|EY!`IJ*x9_gf_k&Gx2alL!hK zUWj1T_pk|?iv}4EP#PZvYD_-LpzU!NfcLL%fK&r$W8O1KH9c2&GV~N#T$kaXGvAOl)|T zuF9%6(i=Y3q?X%VK-D2YIYFPH3f|g$TrXW->&^Ab`WT z7>Oo!u1u40?jAJ8Hy`bv}qbgs8)cF0&qeVjD?e+3Ggn1Im>K77ZSpbU*08 zfZkIFcv?y)!*B{|>nx@cE{KoutP+seQU?bCGE`tS0GKUO3PN~t=2u7q_6$l;uw^4c zVu^f{uaqsZ{*a-N?2B8ngrLS8E&s6}Xtv9rR9C^b`@q8*iH)pFzf1|kCfiLw6u{Z%aC z!X^5CzF6qofFJgklJV3oc|Qc2XdFl+y5M9*P8}A>Kh{ zWRgRwMSZ(?Jw;m%0etU5BsWT-Dj-5F;Q$OQJrQd+lv`i6>MhVo^p*^w6{~=fhe|bN z*37oV0kji)4an^%3ABbg5RC;CS50@PV5_hKfXjYx+(DqQdKC^JIEMo6X66$qDdLRc z!YJPSKnbY`#Ht6`g@xGzJmKzzn|abYbP+_Q(v?~~ z96%cd{E0BCsH^0HaWt{y(Cuto4VE7jhB1Z??#UaU(*R&Eo+J`UN+8mcb51F|I|n*J zJCZ3R*OdyeS9hWkc_mA7-br>3Tw=CX2bl(=TpVt#WP8Bg^vE_9bP&6ccAf3lFMgr` z{3=h@?Ftb$RTe&@IQtiJfV;O&4fzh)e1>7seG; z=%mA4@c7{aXeJnhEg2J@Bm;=)j=O=cl#^NNkQ<{r;Bm|8Hg}bJ-S^g4`|itx)~!LN zXtL}?f1Hs6UQ+f0-X6&TBCW=A4>bU0{rv8C4T!(wD-h>VCK4YJk`6C9$by!fxOYw- zV#n+0{E(0ttq_#16B} ze8$E#X9o{B!0vbq#WUwmv5Xz6{(!^~+}sBW{xctdNHL4^vDk!0E}(g|W_q;jR|ZK< z8w>H-8G{%R#%f!E7cO_^B?yFRKLOH)RT9GJsb+kAKq~}WIF)NRLwKZ^Q;>!2MNa|} z-mh?=B;*&D{Nd-mQRcfVnHkChI=DRHU4ga%xJ%+QkBd|-d9uRI76@BT(bjsjwS+r) zvx=lGNLv1?SzZ;P)Gnn>04fO7Culg*?LmbEF0fATG8S@)oJ>NT3pYAXa*vX!eUTDF ziBrp(QyDqr0ZMTr?4uG_Nqs6f%S0g?h`1vO5fo=5S&u#wI2d4+3hWiolEU!=3_oFo zfie?+4W#`;1dd#X@g9Yj<53S<6OB!TM8w8})7k-$&q5(smc%;r z(BlXkTp`C47+%4JA{2X}MIaPbVF!35P#p;u7+fR*46{T+LR8+j25oduCfDzDv6R-hU{TVVo9fz?^N3ShMt!t0NsH)pB zRK8-S{Dn*y3b|k^*?_B70<2gHt==l7c&cT>r`C#{S}J2;s#d{M)ncW(#Y$C*lByLQ z&?+{dR7*gpdT~(1;M(FfF==3z`^eW)=5a9RqvF-)2?S-(G zhS;p(u~_qBum*q}On@$#08}ynd0+spzyVco0%G6;<-i5&016cV5UKzhQ~)fX03|>L z8ej+HzzgVr6_5ZUpa4HW0Ca!=r1%*}Oo;2no&Zz8DfR)L!@r<5 z2viSZpmvo5XqXyAz{Ms7`7kX>fnr1gi4X~7KpznRT0{Xc5Cfz@43PjBMBoH@z_{~( z(Wd}IPJ9hH+%)Fc)0!hrV+(A;76rhtI|YHbEDeERV~Ya>SQg^IvlazFkSK(KG9&{q zkPIR~EeQaaBmwA<20}mBO?)N$(z1@p)5?%}rM| zGF()~Z&Kx@OIDRI$d0T8;JX@vj3^2%pd_+@l9~a4lntZ;AvUIjqIZbuNTR6@hNJoV zk4F;ut)LN4ARuyn2M6F~eg-e#UH%2P;8uPGFW^vq1vj8mdIayFOZo(tphk8C7hpT~ z1Fv8?b_LNR3QD9J+!v=p%}# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/api/fonts/glyphicons-halflings-regular.ttf b/docs/api/fonts/glyphicons-halflings-regular.ttf deleted file mode 100644 index 1413fc609ab6f21774de0cb7e01360095584f65b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45404 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 G`u_lkUM?>H diff --git a/docs/api/fonts/glyphicons-halflings-regular.woff2 b/docs/api/fonts/glyphicons-halflings-regular.woff2 deleted file mode 100644 index 64539b54c3751a6d9adb44c8e3a45ba5a73b77f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18028 zcmV(~K+nH-Pew8T0RR9107h&84*&oF0I^&E07eM_0Rl|`00000000000000000000 z0000#Mn+Uk92y`7U;vDA2m}!b3WBL5f#qcZHUcCAhI9*rFaQJ~1&1OBl~F%;WnyLq z8)b|&?3j;$^FW}&KmNW53flIFARDZ7_Wz%hpoWaWlgHTHEHf()GI0&dMi#DFPaEt6 zCO)z0v0~C~q&0zBj^;=tv8q{$8JxX)>_`b}WQGgXi46R*CHJ}6r+;}OrvwA{_SY+o zK)H-vy{l!P`+NG*`*x6^PGgHH4!dsolgU4RKj@I8Xz~F6o?quCX&=VQ$Q{w01;M0? zKe|5r<_7CD z=eO3*x!r$aX2iFh3;}xNfx0v;SwBfGG+@Z;->HhvqfF4r__4$mU>Dl_1w;-9`~5rF~@!3;r~xP-hZvOfOx)A z#>8O3N{L{naf215f>m=bzbp7_(ssu&cx)Qo-{)!)Yz3A@Z0uZaM2yJ8#OGlzm?JO5gbrj~@)NB4@?>KE(K-$w}{};@dKY#K3+Vi64S<@!Z{(I{7l=!p9 z&kjG^P~0f46i13(w!hEDJga;*Eb z`!n|++@H8VaKG<9>VDh(y89J#=;Z$ei=GnD5TesW#|Wf)^D+9NKN4J3H5PF_t=V+Z zdeo8*h9+8&Zfc?>>1|E4B7MAx)^uy$L>szyXre7W|81fjy+RZ1>Gd}@@${~PCOXo) z$#HZd3)V3@lNGG%(3PyIbvyJTOJAWcN@Uh!FqUkx^&BuAvc)G}0~SKI`8ZZXw$*xP zum-ZdtPciTAUn$XWb6vrS=JX~f5?M%9S(=QsdYP?K%Odn0S0-Ad<-tBtS3W06I^FK z8}d2eR_n!(uK~APZ-#tl@SycxkRJ@5wmypdWV{MFtYBUY#g-Vv?5AEBj1 z`$T^tRKca*sn7gt%s@XUD-t>bij-4q-ilku9^;QJ3Mpc`HJ_EX4TGGQ-Og)`c~qm51<|gp7D@ zp#>Grssv^#A)&M8>ulnDM_5t#Al`#jaFpZ<#YJ@>!a$w@kEZ1<@PGs#L~kxOSz7jj zEhb?;W)eS}0IQQuk4~JT30>4rFJ3!b+77}>$_>v#2FFEnN^%(ls*o80pv0Q>#t#%H z@`Yy-FXQ9ULKh{Up&oA_A4B!(x^9&>i`+T|eD!&QOLVd(_avv-bFX~4^>o{%mzzrg_i~SBnr%DeE|i+^}|8?kaV(Z32{`vA^l!sp15>Z72z52FgXf z^8ZITvJ9eXBT1~iQjW|Q`Fac^ak$^N-vI^*geh5|*CdMz;n16gV_zk|Z7q8tFfCvU zJK^Pptnn0Rc~egGIAK}uv99VZm2WLPezQQ5K<`f zg{8Ll|GioPYfNheMj-7-S87=w4N0WxHP`1V6Y)0M&SkYzVrwp>yfsEF7wj&T0!}dB z)R~gGfP9pOR;GY_e0~K^^oJ-3AT+m~?Al!{>>5gNe17?OWz)$)sMH*xuQiB>FT2{i zQ>6U_8}Ay~r4li;jzG+$&?S12{)+<*k9 z<^SX#xY|jvlvTxt(m~C7{y{3g>7TX#o2q$xQO|fc<%8rE@A3=UW(o?gVg?gDV!0q6O!{MlX$6-Bu_m&0ms66 znWS&zr{O_4O&{2uCLQvA?xC5vGZ}KV1v6)#oTewgIMSnBur0PtM0&{R5t#UEy3I9) z`LVP?3f;o}sz*7g5qdTxJl^gk3>;8%SOPH@B)rmFOJ)m6?PlYa$y=RX%;}KId{m9R#2=LNwosF@OTivgMqxpRGe}5=LtAn?VVl6VWCFLD z7l#^^H8jY~42hR)OoVF#YDW(md!g(&pJ;yMj|UBAQa}UH?ED@%ci=*(q~Opn>kE2Q z_4Kgf|0kEA6ary41A;)^Ku(*nirvP!Y>{FZYBLXLP6QL~vRL+uMlZ?jWukMV*(dsn zL~~KA@jU)(UeoOz^4Gkw{fJsYQ%|UA7i79qO5=DOPBcWlv%pK!A+)*F`3WJ}t9FU3 zXhC4xMV7Z%5RjDs0=&vC4WdvD?Zi5tg4@xg8-GLUI>N$N&3aS4bHrp%3_1u9wqL)i z)XQLsI&{Hd&bQE!3m&D0vd!4D`l1$rt_{3NS?~lj#|$GN5RmvP(j3hzJOk=+0B*2v z)Bw133RMUM%wu_+$vbzOy?yk#kvR?xGsg-ipX4wKyXqd zROKp5))>tNy$HByaEHK%$mqd>-{Yoj`oSBK;w>+eZ&TVcj^DyXjo{DDbZ>vS2cCWB z(6&~GZ}kUdN(*2-nI!hvbnVy@z2E#F394OZD&Jb04}`Tgaj?MoY?1`{ejE2iud51% zQ~J0sijw(hqr_Ckbj@pm$FAVASKY(D4BS0GYPkSMqSDONRaFH+O2+jL{hIltJSJT~e)TNDr(}=Xt7|UhcU9eoXl&QZRR<9WomW%&m)FT~j zTgGd3-j}Uk%CRD;$@X)NNV9+RJbifYu>yr{FkO;p>_&njI> zyBHh_72bW;8}oGeY0gpHOxiV597j7mY<#?WMmkf5x~Kfk*re(&tG_mX<3&2cON*2u%V29tsXUv{#-ijs2>EuNH-x3) zPBpi+V6gI=wn}u164_j8xi-y(B?Au2o;UO=r6&)i5S3Mx*)*{_;u}~i4dh$`VgUS- zMG6t*?DXDYX0D2Oj31MI!HF>|aG8rjrOPnxHu4wZl;!=NGjjDoBpXf?ntrwt^dqxm zs(lE@*QB3NH)!`rH)5kks-D89g@UX&@DU9jvrsY)aI=9b4nPy3bfdX_U;#?zsan{G>DKob2LnhCJv8o}duQK)qP{7iaaf2=K`a-VNcfC582d4a z>sBJA*%S|NEazDxXcGPW_uZ&d7xG`~JB!U>U(}acUSn=FqOA~(pn^!aMXRnqiL0;? zebEZYouRv}-0r;Dq&z9>s#Rt1HL`0p4bB)A&sMyn|rE_9nh z?NO*RrjET8D4s(-`nS{MrdYtv*kyCnJKbsftG2D#ia@;42!8xd?a3P(&Y?vCf9na< zQ&Ni*1Qel&Xq{Z?=%f0SRqQt5m|Myg+8T=GDc)@^};=tM>9IDr7hdvE9-M@@<0pqv45xZTeNecbL- zWFQt4t`9>j8~X%lz}%We>Kzh_=`XO}!;4!OWH?=p*DOs#Nt({k^IvtBEL~Qafn)I^ zm*k{y7_bIs9YE}0B6%r`EIUH8US+MGY!KQA1fi-jCx9*}oz2k1nBsXp;4K<_&SN}}w<)!EylI_)v7}3&c)V;Cfuj*eJ2yc8LK=vugqTL><#65r6%#2e| zdYzZ)9Uq7)A$ol&ynM!|RDHc_7?FlWqjW>8TIHc`jExt)f5W|;D%GC#$u!%B*S%Z0 zsj&;bIU2jrt_7%$=!h4Q29n*A^^AI8R|stsW%O@?i+pN0YOU`z;TVuPy!N#~F8Z29 zzZh1`FU(q31wa>kmw{$q=MY>XBprL<1)Py~5TW4mgY%rg$S=4C^0qr+*A^T)Q)Q-U zGgRb9%MdE-&i#X3xW=I`%xDzAG95!RG9)s?v_5+qx`7NdkQ)If5}BoEp~h}XoeK>kweAMxJ8tehagx~;Nr_WP?jXa zJ&j7%Ef3w*XWf?V*nR)|IOMrX;$*$e23m?QN` zk>sC^GE=h6?*Cr~596s_QE@>Nnr?{EU+_^G=LZr#V&0fEXQ3IWtrM{=t^qJ62Sp=e zrrc>bzX^6yFV!^v7;>J9>j;`qHDQ4uc92eVe6nO@c>H=ouLQot``E~KLNqMqJ7(G+?GWO9Ol+q$w z!^kMv!n{vF?RqLnxVk{a_Ar;^sw0@=+~6!4&;SCh^utT=I zo&$CwvhNOjQpenw2`5*a6Gos6cs~*TD`8H9P4=#jOU_`%L!W;$57NjN%4 z39(61ZC#s7^tv`_4j}wMRT9rgDo*XtZwN-L;Qc$6v8kKkhmRrxSDkUAzGPgJ?}~_t zkwoGS4=6lsD`=RL|8L3O9L()N)lmEn-M15fRC{dhZ}7eYV%O-R^gsAp{q4 z!C1}_T8gy^v@SZ5R&Li5JMJy+K8iZw3LOGA0pN1~y@w7RRl#F()ii6Y5mr~Mdy@Kz z@FT4cm^I&#Fu_9IX(HAFP{XLbRALqm&)>m_we>a`hfv?eE|t z?YdDp2yAhj-~vuw^wzVDuj%w?exOcOT(ls(F*ceCe(C5HlN{lcQ;}|mRPqFDqLEzw zR7ldY+M6xe$$qLwekmk{Z&5cME$gpC?-8)f0m$rqaS|mj9ATNJvvyCgs(f2{r;2E!oy$k5{jik#(;S>do<#m0wVcU<}>)VtYmF9O0%(C>GDzPgh6X z9OkQLMR~y7=|MtaU!LDPPY7O)L{X#SC+M|v^X2CZ?$GS>U_|aC(VA(mIvCNk+biD| zSpj>gd(v>_Cbq>~-x^Y3o|?eHmuC?E&z>;Ij`%{$Pm$hI}bl0Kd`9KD~AchY+goL1?igDxf$qxL9< z4sW@sD)nwWr`T>e2B8MQN|p*DVTT8)3(%AZ&D|@Zh6`cJFT4G^y6`(UdPLY-&bJYJ z*L06f2~BX9qX}u)nrpmHPG#La#tiZ23<>`R@u8k;ueM6 znuSTY7>XEc+I-(VvL?Y>)adHo(cZ;1I7QP^q%hu#M{BEd8&mG_!EWR7ZV_&EGO;d(hGGJzX|tqyYEg2-m0zLT}a{COi$9!?9yK zGN7&yP$a|0gL`dPUt=4d^}?zrLN?HfKP0_gdRvb}1D73Hx!tXq>7{DWPV;^X{-)cm zFa^H5oBDL3uLkaFDWgFF@HL6Bt+_^g~*o*t`Hgy3M?nHhWvTp^|AQDc9_H< zg>IaSMzd7c(Sey;1SespO=8YUUArZaCc~}}tZZX80w%)fNpMExki-qB+;8xVX@dr; z#L52S6*aM-_$P9xFuIui;dN#qZ_MYy^C^hrY;YAMg;K`!ZpKKFc z9feHsool)`tFSS}Su|cL0%F;h!lpR+ym|P>kE-O`3QnHbJ%gJ$dQ_HPTT~>6WNX41 zoDEUpX-g&Hh&GP3koF4##?q*MX1K`@=W6(Gxm1=2Tb{hn8{sJyhQBoq}S>bZT zisRz-xDBYoYxt6--g2M1yh{#QWFCISux}4==r|7+fYdS$%DZ zXVQu{yPO<)Hn=TK`E@;l!09aY{!TMbT)H-l!(l{0j=SEj@JwW0a_h-2F0MZNpyucb zPPb+4&j?a!6ZnPTB>$t`(XSf-}`&+#rI#`GB> zl=$3HORwccTnA2%>$Nmz)u7j%_ywoGri1UXVNRxSf(<@vDLKKxFo;5pTI$R~a|-sQ zd5Rfwj+$k1t0{J`qOL^q>vZUHc7a^`cKKVa{66z?wMuQAfdZBaVVv@-wamPmes$d! z>gv^xx<0jXOz;7HIQS z4RBIFD?7{o^IQ=sNQ-k!ao*+V*|-^I2=UF?{d>bE9avsWbAs{sRE-y`7r zxVAKA9amvo4T}ZAHSF-{y1GqUHlDp4DO9I3mz5h8n|}P-9nKD|$r9AS3gbF1AX=2B zyaK3TbKYqv%~JHKQH8v+%zQ8UVEGDZY|mb>Oe3JD_Z{+Pq%HB+J1s*y6JOlk`6~H) zKt)YMZ*RkbU!GPHzJltmW-=6zqO=5;S)jz{ zFSx?ryqSMxgx|Nhv3z#kFBTuTBHsViaOHs5e&vXZ@l@mVI37<+^KvTE51!pB4Tggq zz!NlRY2ZLno0&6bA|KHPYOMY;;LZG&_lzuLy{@i$&B(}_*~Zk2 z>bkQ7u&Ww%CFh{aqkT{HCbPbRX&EvPRp=}WKmyHc>S_-qbwAr0<20vEoJ(!?-ucjE zKQ+nSlRL^VnOX0h+WcjGb6WI(8;7bsMaHXDb6ynPoOXMlf9nLKre;w*#E_whR#5!! z!^%_+X3eJVKc$fMZP;+xP$~e(CIP1R&{2m+iTQhDoC8Yl@kLM=Wily_cu>7C1wjVU z-^~I0P06ZSNVaN~A`#cSBH2L&tk6R%dU1(u1XdAx;g+5S^Hn9-L$v@p7CCF&PqV{Z?R$}4EJi36+u2JP7l(@fYfP!=e#76LGy^f>~vs0%s*x@X8`|5 zGd6JOHsQ=feES4Vo8%1P_7F5qjiIm#oRT0kO1(?Z_Dk6oX&j=Xd8Klk(;gk3S(ZFnc^8Gc=d;8O-R9tlGyp=2I@1teAZpGWUi;}`n zbJOS_Z2L16nVtDnPpMn{+wR9&yU9~C<-ncppPee`>@1k7hTl5Fn_3_KzQ)u{iJPp3 z)df?Xo%9ta%(dp@DhKuQj4D8=_!*ra#Ib&OXKrsYvAG%H7Kq|43WbayvsbeeimSa= z8~{7ya9ZUAIgLLPeuNmSB&#-`Je0Lja)M$}I41KHb7dQq$wgwX+EElNxBgyyLbA2* z=c1VJR%EPJEw(7!UE?4w@94{pI3E%(acEYd8*Wmr^R7|IM2RZ-RVXSkXy-8$!(iB* zQA`qh2Ze!EY6}Zs7vRz&nr|L60NlIgnO3L*Yz2k2Ivfen?drnVzzu3)1V&-t5S~S? zw#=Sdh>K@2vA25su*@>npw&7A%|Uh9T1jR$mV*H@)pU0&2#Se`7iJlOr$mp79`DKM z5vr*XLrg7w6lc4&S{So1KGKBqcuJ!E|HVFB?vTOjQHi)g+FwJqX@Y3q(qa#6T@3{q zhc@2T-W}XD9x4u+LCdce$*}x!Sc#+rH-sCz6j}0EE`Tk*irUq)y^za`}^1gFnF)C!yf_l_}I<6qfbT$Gc&Eyr?!QwJR~RE4!gKVmqjbI+I^*^ z&hz^7r-dgm@Mbfc#{JTH&^6sJCZt-NTpChB^fzQ}?etydyf~+)!d%V$0faN(f`rJb zm_YaJZ@>Fg>Ay2&bzTx3w^u-lsulc{mX4-nH*A(32O&b^EWmSuk{#HJk}_ULC}SB(L7`YAs>opp9o5UcnB^kVB*rmW6{s0&~_>J!_#+cEWib@v-Ms`?!&=3fDot`oH9v&$f<52>{n2l* z1FRzJ#yQbTHO}}wt0!y8Eh-0*|Um3vjX-nWH>`JN5tWB_gnW%; zUJ0V?_a#+!=>ahhrbGvmvObe8=v1uI8#gNHJ#>RwxL>E^pT05Br8+$@a9aDC1~$@* zicSQCbQcr=DCHM*?G7Hsovk|{$3oIwvymi#YoXeVfWj{Gd#XmnDgzQPRUKNAAI44y z{1WG&rhIR4ipmvBmq$BZ*5tmPIZmhhWgq|TcuR{6lA)+vhj(cH`0;+B^72{&a7ff* zkrIo|pd-Yxm+VVptC@QNCDk0=Re%Sz%ta7y{5Dn9(EapBS0r zLbDKeZepar5%cAcb<^;m>1{QhMzRmRem=+0I3ERot-)gb`i|sII^A#^Gz+x>TW5A& z3PQcpM$lDy`zb%1yf!e8&_>D02RN950KzW>GN6n@2so&Wu09x@PB=&IkIf|zZ1W}P zAKf*&Mo5@@G=w&290aG1@3=IMCB^|G4L7*xn;r3v&HBrD4D)Zg+)f~Ls$7*P-^i#B z4X7ac=0&58j^@2EBZCs}YPe3rqgLAA1L3Y}o?}$%u~)7Rk=LLFbAdSy@-Uw6lv?0K z&P@@M`o2Rll3GoYjotf@WNNjHbe|R?IKVn*?Rzf9v9QoFMq)ODF~>L}26@z`KA82t z43e!^z&WGqAk$Ww8j6bc3$I|;5^BHwt`?e)zf|&+l#!8uJV_Cwy-n1yS0^Q{W*a8B zTzTYL>tt&I&9vzGQUrO?YIm6C1r>eyh|qw~-&;7s7u1achP$K3VnXd8sV8J7ZTxTh z5+^*J5%_#X)XL2@>h(Gmv$@)fZ@ikR$v(2Rax89xscFEi!3_;ORI0dBxw)S{r50qf zg&_a*>2Xe{s@)7OX9O!C?^6fD8tc3bQTq9}fxhbx2@QeaO9Ej+2m!u~+u%Q6?Tgz{ zjYS}bleKcVhW~1$?t*AO^p!=Xkkgwx6OTik*R3~yg^L`wUU9Dq#$Z*iW%?s6pO_f8 zJ8w#u#Eaw7=8n{zJ}C>w{enA6XYHfUf7h)!Qaev)?V=yW{b@-z`hAz;I7^|DoFChP z1aYQnkGauh*ps6x*_S77@z1wwGmF8ky9fMbM$dr*`vsot4uvqWn)0vTRwJqH#&D%g zL3(0dP>%Oj&vm5Re%>*4x|h1J2X*mK5BH1?Nx_#7( zepgF`+n)rHXj!RiipusEq!X81;QQBXlTvLDj=Qub(ha&D=BDx3@-V*d!D9PeXUY?l zwZ0<4=iY!sUj4G>zTS+eYX7knN-8Oynl=NdwHS*nSz_5}*5LQ@=?Yr?uj$`C1m2OR zK`f5SD2|;=BhU#AmaTKe9QaSHQ_DUj1*cUPa*JICFt1<&S3P3zsrs^yUE;tx=x^cmW!Jq!+hohv_B> zPDMT0D&08dC4x@cTD$o1$x%So1Ir(G3_AVQMvQ13un~sP(cEWi$2%5q93E7t{3VJf%K? zuwSyDke~7KuB2?*#DV8YzJw z&}SCDexnUPD!%4|y~7}VzvJ4ch)WT4%sw@ItwoNt(C*RP)h?&~^g##vnhR0!HvIYx z0td2yz9=>t3JNySl*TszmfH6`Ir;ft@RdWs3}!J88UE|gj_GMQ6$ZYphUL2~4OY7} zB*33_bjkRf_@l;Y!7MIdb~bVe;-m78Pz|pdy=O*3kjak63UnLt!{^!!Ljg0rJD3a~ z1Q;y5Z^MF<=Hr}rdoz>yRczx+p3RxxgJE2GX&Si)14B@2t21j4hnnP#U?T3g#+{W+Zb z5s^@>->~-}4|_*!5pIzMCEp|3+i1XKcfUxW`8|ezAh>y{WiRcjSG*asw6;Ef(k#>V ztguN?EGkV_mGFdq!n#W)<7E}1#EZN8O$O|}qdoE|7K?F4zo1jL-v}E8v?9qz(d$&2 zMwyK&xlC9rXo_2xw7Qe0caC?o?Pc*-QAOE!+UvRuKjG+;dk|jQhDDBe?`XT7Y5lte zqSu0t5`;>Wv%|nhj|ZiE^IqA_lZu7OWh!2Y(627zb=r7Ends}wVk7Q5o09a@ojhH7 zU0m&h*8+j4e|OqWyJ&B`V`y=>MVO;K9=hk^6EsmVAGkLT{oUtR{JqSRY{Qi{kKw1k z6s;0SMPJOLp!som|A`*q3t0wIj-=bG8a#MC)MHcMSQU98Juv$?$CvYX)(n`P^!`5| zv3q@@|G@6wMqh;d;m4qvdibx2Yjml}vG9mDv&!0ne02M#D`Bo}xIB0VWh8>>WtNZQ z$&ISlJX;*ORQIO;k62qA{^6P%3!Z=Y1EbmY02{w^yB$`;%!{kur&XTGDiO2cjA)lr zsY^XZWy^DSAaz;kZ_VG?uWnJR7qdN18$~)>(kOoybY0~QYu9||K#|$Mby{3GduV~N zk9H7$7=RSo+?CUYF502`b76ytBy}sFak&|HIwRvB=0D|S`c#QCJPq zP)uOWI)#(n&{6|C4A^G~%B~BY21aOMoz9RuuM`Ip%oBz+NoAlb7?#`E^}7xXo!4S? zFg8I~G%!@nXi8&aJSGFcZAxQf;0m}942=i#p-&teLvE{AKm7Sl2f}Io?!IqbC|J;h z`=5LFOnU5?^w~SV@YwNZx$k_(kLNxZDE z3cf08^-rIT_>A$}B%IJBPcN^)4;90BQtiEi!gT#+EqyAUZ|}*b_}R>SGloq&6?opL zuT_+lwQMgg6!Cso$BwUA;k-1NcrzyE>(_X$B0HocjY~=Pk~Q08+N}(|%HjO_i+*=o z%G6C6A30Ch<0UlG;Zdj@ed!rfUY_i9mYwK8(aYuzcUzlTJ1yPz|Bb-9b33A9zRhGl>Ny-Q#JAq-+qtI@B@&w z$;PJbyiW=!py@g2hAi0)U1v=;avka`gd@8LC4=BEbNqL&K^UAQ5%r95#x%^qRB%KLaqMnG|6xKAm}sx!Qwo}J=2C;NROi$mfADui4)y(3wVA3k~{j^_5%H)C6K zlYAm1eY**HZOj($)xfKIQFtIVw$4&yvz9>(Crs>Gh{ zya6-FG7Dgi92#K)64=9Csj5?Zqe~_9TwSI!2quAwa1w-*uC5!}xY`?tltb0Hq740< zsq2QelPveZ4chr$=~U3!+c&>xyfvA1`)owOqj=i4wjY=A1577Gwg&Ko7;?il9r|_* z8P&IDV_g2D{in5OLFxsO!kx3AhO$5aKeoM|!q|VokqMlYM@HtsRuMtBY%I35#5$+G zpp|JOeoj^U=95HLemB04Yqv{a8X<^K9G2`&ShM_6&Bi1n?o?@MXsDj9Z*A3>#XK%J zRc*&SlFl>l)9DyRQ{*%Z+^e1XpH?0@vhpXrnPPU*d%vOhKkimm-u3c%Q^v3RKp9kx@A2dS?QfS=iigGr7m><)YkV=%LA5h@Uj@9=~ABPMJ z1UE;F&;Ttg5Kc^Qy!1SuvbNEqdgu3*l`=>s5_}dUv$B%BJbMiWrrMm7OXOdi=GOmh zZBvXXK7VqO&zojI2Om9};zCB5i|<210I{iwiGznGCx=FT89=Ef)5!lB1cZ6lbzgDn07*he}G&w7m!;|E(L-?+cz@0<9ZI~LqYQE7>HnPA436}oeN2Y(VfG6 zxNZuMK3Crm^Z_AFeHc~CVRrSl0W^?+Gbteu1g8NGYa3(8f*P{(ZT>%!jtSl6WbYVv zmE(37t0C8vJ6O-5+o*lL9XRcFbd~GSBGbGh3~R!67g&l)7n!kJlWd)~TUyXus#!&G6sR%(l(h1$xyrR5j_jM1zj#giA&@(Xl26@n<9>folx!92bQ z24h570+<)4!$!IQ(5yOU|4_E6aN@4v0+{Kx~Z z;q7fp%0cHziuI%!kB~w}g9@V+1wDz0wFlzX2UOvOy|&;e;t!lAR8tV2KQHgtfk8Uf zw;rs!(4JPODERk4ckd5I2Vq|0rd@@Mwd8MID%0^fITjYIQom^q;qhP8@|eJx{?5xX zc1@Fj*kDknlk{c-rnCloQ3hGh7OU+@efO3>fkRMcM>J?AeVP& zlfzX%cdp=N+4S#E*%^=BQ+N`A7C}|k%$|QUn0yI6S3$MS-NjO!4hm55uyju)Q6e!} z*OVO@A#-mfC9Pha6ng((Xl^V7{d+&u+yx)_B1{~t7d5e8L^i4J>;x<7@5;+l7-Gge zf#9diXJ$&v^rbN5V(ee%q0xBMEgS6%qZm7hNUP%G;^J44I!BmI@M*+FWz0!+s;+iQ zU4CuI+27bvNK8v>?7PZnVxB=heJ&_ymE0nN^W#-rqB%+JXkYGDuRw>JM_LdtLkiq* z6%%3&^BX$jnM@2bjiGc-DymKly)wVkA-pq;jSWL#7_*moZZ4I|-N}o8SK?sIv)p|c zu~9-B%tMc=!)YMFp*SiC0>kfnH8+X5>;+FFVN{~a9YVdIg1uGkZ~kegFy{^PU(4{( z`CbY`XmVA3esai686Yw8djCEyF7`bfB^F1)nwv+AqYLZ&Zy=eFhYT2uMd@{sP_qS4 zbJ&>PxajjZt?&c<1^!T|pLHfX=E^FJ>-l_XCZzvRV%x}@u(FtF(mS+Umw$e+IA74e>gCdTqi;6&=euAIpxd=Y3I5xWR zBhGoT+T`V1@91OlQ}2YO*~P4ukd*TBBdt?Plt)_ou6Y@Db`ss+Q~A-48s>?eaJYA2 zRGOa8^~Em}EFTmKIVVbMb|ob)hJJ7ITg>yHAn2i|{2ZJU!cwt9YNDT0=*WO7Bq#Xj zg@FjEaKoolrF8%c;49|`IT&25?O$dq8kp3#la9&6aH z6G|{>^C(>yP7#Dr$aeFyS0Ai_$ILhL43#*mgEl(c*4?Ae;tRL&S7Vc}Szl>B`mBuI zB9Y%xp%CZwlH!3V(`6W4-ZuETssvI&B~_O;CbULfl)X1V%(H7VSPf`_Ka9ak@8A=z z1l|B1QKT}NLI`WVTRd;2En5u{0CRqy9PTi$ja^inu){LJ&E&6W%JJPw#&PaTxpt?k zpC~gjN*22Q8tpGHR|tg~ye#9a8N<%odhZJnk7Oh=(PKfhYfzLAxdE36r<6a?A;rO&ELp_Y?8Pdw(PT^Fxn!eG_|LEbSYoBrsBA|6Fgr zt5LntyusI{Q2fdy=>ditS;}^B;I2MD4=(>7fWt0Jp~y=?VvfvzHvQhj6dyIef46J$ zl4Xu7U9v_NJV?uBBC0!kcTS0UcrV7+@~is?Fi+jrr@l3XwD|uG zr26jUWiv>Ju48Y^#qn7r9mwIH-Pv6Y|V|V-GZ&+&gQ?S?-`&ts{@5GXPqbmyZjUACC&oVXfNwUX0}ba(v978 zp8z!v9~8Zx8qB@7>oFPDm^iR@+yw`79YF)w^OHB_N;&&x7c3l^3!)IY#)}x)@D(iNaOm9 zC=^*!{`7={3*S=%iU=KsPXh=DDZcc``Ss>057i{pdW8M@4q+Ba@Tt%OytH!4>rbIbQw^-pR zGGYNPzw@n=PV@)b7yVbFr;glF*Qq3>F9oBN5PUXt!?2mdGcpv^o1?Thp`jP10G2Yi z(c93td3F3SW!Le5DUwdub!aDKoVLU6g!O?Ret21l$qOC;kdd@L#M&baVu&JZGt&<6 z!VCkvgRaav6QDW2x}tUy4~Y5(B+#Ej-8vM?DM-1?J_*&PntI3E96M!`WL#<&Z5n2u zo`P!~vBT$YOT~gU9#PB)%JZ zcd_u=m^LYzC!pH#W`yA1!(fA;D~b zG#73@l)NNd;n#XrKXZEfab;@kQRnOFU2Th-1m<4mJzlj9b3pv-GF$elX7ib9!uILM_$ke zHIGB*&=5=;ynQA{y7H93%i^d)T}y@(p>8vVhJ4L)M{0Q*@D^+SPp`EW+G6E%+`Z;u zS3goV@Dic7vc5`?!pCN44Ts@*{)zwy)9?B||AM{zKlN4T}qQRL2 zgv+{K8bv7w)#xge16;kI1fU87!W4pX)N&|cq8&i^1r`W|Hg4366r(?-ecEJ9u&Eaw zrhyikXQB>C9d>cpPGiu=VU3Z-u4|0V_iap!_J3o+K_R5EXk@sfu~zHwwYkpncVh!R zqNe7Cmf_|Wmeq4#(mIO&(wCK@b4(x0?W1Qtk(`$?+$uCJCGZm_%k?l32vuShgDFMa ztc`{$8DhB9)&?~(m&EUc=LzI1=qo#zjy#2{hLT_*aj<618qQ7mD#k2ZFGou&69;=2 z1j7=Su8k}{L*h&mfs7jg^PN&9C1Z@U!p6gXk&-7xM~{X`nqH#aGO`;Xy_zbz^rYacIq0AH%4!Oh93TzJ820%ur)8OyeS@K?sF1V(iFO z37Nnqj1z#1{|v7=_CX`lQA|$<1gtuNMHGNJYp1D_k;WQk-b+T6VmUK(x=bWviOZ~T z|4e%SpuaWLWD?qN2%`S*`P;BQBw(B__wTD6epvGdJ+>DBq2oVlf&F*lz+#avb4)3P1c^Mf#olQheVvZ|Z5 z>xXfgmv!5Z^SYn+_x}K5B%G^sRwiez&z9|f!E!#oJlT2kCOV0000$L_|bHBqAarB4TD{W@grX1CUr72@caw0faEd7-K|4L_|cawbojjHdpd6 zI6~Iv5J?-Q4*&oF000000FV;^004t70Z6Qk1Xl{X9oJ{sRC2(cs?- diff --git a/docs/api/img/favicon.ico b/docs/api/img/favicon.ico deleted file mode 100644 index c307a043933f0e860284157007820fccbe0fc96f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 894 zcmdUuF-rqM6ojAn2d)y!l(7l<0Sa4)bsGCC1jQ;~7c8z2NtY8s$`~6pMGzDegoNu- zL@-!L!~}wc5V437IkY*y&4xu5e}L}I?#-JU-p($Z$Q+O73G1S4&5JCENScWxDW=x- zP<(U8O;P?D)-rOqJxf*D5X#fMtSq@XeWi86$CGh&FK141Qt~NVWtAj}bFN-DLPvaT z*RIZLGz1Vz2nbHj-L#d^{{!N!&pBAbk2j(^U(2=VbJTML#&?*0s93%{?MEL%tQGVj{yYS9qIdd y=|=!E>V$}|g9zOiSnsP@V9MK)_i(HXtO!B3{(nl`|3Ly2=CXc=hEFxke;MD%5Rt_I diff --git a/docs/api/index.html b/docs/api/index.html deleted file mode 100644 index 5f04deda..00000000 --- a/docs/api/index.html +++ /dev/null @@ -1,669 +0,0 @@ - - - - - Loading... - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
- -
- -
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-

Loading...

-
-
- - - - diff --git a/docs/api/locales/ca.js b/docs/api/locales/ca.js deleted file mode 100644 index 65af5df2..00000000 --- a/docs/api/locales/ca.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - ca: { - 'Allowed values:' : 'Valors permesos:', - 'Compare all with predecessor': 'Comparar tot amb versió anterior', - 'compare changes to:' : 'comparar canvis amb:', - 'compared to' : 'comparat amb', - 'Default value:' : 'Valor per defecte:', - 'Description' : 'Descripció', - 'Field' : 'Camp', - 'General' : 'General', - 'Generated with' : 'Generat amb', - 'Name' : 'Nom', - 'No response values.' : 'Sense valors en la resposta.', - 'optional' : 'opcional', - 'Parameter' : 'Paràmetre', - 'Permission:' : 'Permisos:', - 'Response' : 'Resposta', - 'Send' : 'Enviar', - 'Send a Sample Request' : 'Enviar una petició d\'exemple', - 'show up to version:' : 'mostrar versió:', - 'Size range:' : 'Tamany de rang:', - 'Type' : 'Tipus', - 'url' : 'url' - } -}); diff --git a/docs/api/locales/cs.js b/docs/api/locales/cs.js deleted file mode 100644 index b7796d8f..00000000 --- a/docs/api/locales/cs.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - cs: { - 'Allowed values:' : 'Povolené hodnoty:', - 'Compare all with predecessor': 'Porovnat vše s předchozími verzemi', - 'compare changes to:' : 'porovnat změny s:', - 'compared to' : 'porovnat s', - 'Default value:' : 'Výchozí hodnota:', - 'Description' : 'Popis', - 'Field' : 'Pole', - 'General' : 'Obecné', - 'Generated with' : 'Vygenerováno pomocí', - 'Name' : 'Název', - 'No response values.' : 'Nebyly vráceny žádné hodnoty.', - 'optional' : 'volitelné', - 'Parameter' : 'Parametr', - 'Permission:' : 'Oprávnění:', - 'Response' : 'Odpověď', - 'Send' : 'Odeslat', - 'Send a Sample Request' : 'Odeslat ukázkový požadavek', - 'show up to version:' : 'zobrazit po verzi:', - 'Size range:' : 'Rozsah velikosti:', - 'Type' : 'Typ', - 'url' : 'url' - } -}); diff --git a/docs/api/locales/de.js b/docs/api/locales/de.js deleted file mode 100644 index f66420d0..00000000 --- a/docs/api/locales/de.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - de: { - 'Allowed values:' : 'Erlaubte Werte:', - 'Compare all with predecessor': 'Vergleiche alle mit ihren Vorgängern', - 'compare changes to:' : 'vergleiche Änderungen mit:', - 'compared to' : 'verglichen mit', - 'Default value:' : 'Standardwert:', - 'Description' : 'Beschreibung', - 'Field' : 'Feld', - 'General' : 'Allgemein', - 'Generated with' : 'Erstellt mit', - 'Name' : 'Name', - 'No response values.' : 'Keine Rückgabewerte.', - 'optional' : 'optional', - 'Parameter' : 'Parameter', - 'Permission:' : 'Berechtigung:', - 'Response' : 'Antwort', - 'Send' : 'Senden', - 'Send a Sample Request' : 'Eine Beispielanfrage senden', - 'show up to version:' : 'zeige bis zur Version:', - 'Size range:' : 'Größenbereich:', - 'Type' : 'Typ', - 'url' : 'url' - } -}); diff --git a/docs/api/locales/es.js b/docs/api/locales/es.js deleted file mode 100644 index 3d47e800..00000000 --- a/docs/api/locales/es.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - es: { - 'Allowed values:' : 'Valores permitidos:', - 'Compare all with predecessor': 'Comparar todo con versión anterior', - 'compare changes to:' : 'comparar cambios con:', - 'compared to' : 'comparado con', - 'Default value:' : 'Valor por defecto:', - 'Description' : 'Descripción', - 'Field' : 'Campo', - 'General' : 'General', - 'Generated with' : 'Generado con', - 'Name' : 'Nombre', - 'No response values.' : 'Sin valores en la respuesta.', - 'optional' : 'opcional', - 'Parameter' : 'Parámetro', - 'Permission:' : 'Permisos:', - 'Response' : 'Respuesta', - 'Send' : 'Enviar', - 'Send a Sample Request' : 'Enviar una petición de ejemplo', - 'show up to version:' : 'mostrar a versión:', - 'Size range:' : 'Tamaño de rango:', - 'Type' : 'Tipo', - 'url' : 'url' - } -}); diff --git a/docs/api/locales/fr.js b/docs/api/locales/fr.js deleted file mode 100644 index 100a6429..00000000 --- a/docs/api/locales/fr.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - fr: { - 'Allowed values:' : 'Valeurs autorisées :', - 'Compare all with predecessor': 'Tout comparer avec ...', - 'compare changes to:' : 'comparer les changements à :', - 'compared to' : 'comparer à', - 'Default value:' : 'Valeur par défaut :', - 'Description' : 'Description', - 'Field' : 'Champ', - 'General' : 'Général', - 'Generated with' : 'Généré avec', - 'Name' : 'Nom', - 'No response values.' : 'Aucune valeur de réponse.', - 'optional' : 'optionnel', - 'Parameter' : 'Paramètre', - 'Permission:' : 'Permission :', - 'Response' : 'Réponse', - 'Send' : 'Envoyer', - 'Send a Sample Request' : 'Envoyer une requête représentative', - 'show up to version:' : 'Montrer à partir de la version :', - 'Size range:' : 'Ordre de grandeur :', - 'Type' : 'Type', - 'url' : 'url' - } -}); diff --git a/docs/api/locales/it.js b/docs/api/locales/it.js deleted file mode 100644 index 8117108c..00000000 --- a/docs/api/locales/it.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - it: { - 'Allowed values:' : 'Valori permessi:', - 'Compare all with predecessor': 'Confronta tutto con versioni precedenti', - 'compare changes to:' : 'confronta modifiche con:', - 'compared to' : 'confrontato con', - 'Default value:' : 'Valore predefinito:', - 'Description' : 'Descrizione', - 'Field' : 'Campo', - 'General' : 'Generale', - 'Generated with' : 'Creato con', - 'Name' : 'Nome', - 'No response values.' : 'Nessun valore di risposta.', - 'optional' : 'opzionale', - 'Parameter' : 'Parametro', - 'Permission:' : 'Permessi:', - 'Response' : 'Risposta', - 'Send' : 'Invia', - 'Send a Sample Request' : 'Invia una richiesta di esempio', - 'show up to version:' : 'mostra alla versione:', - 'Size range:' : 'Intervallo dimensione:', - 'Type' : 'Tipo', - 'url' : 'url' - } -}); diff --git a/docs/api/locales/locale.js b/docs/api/locales/locale.js deleted file mode 100644 index 3530705e..00000000 --- a/docs/api/locales/locale.js +++ /dev/null @@ -1,51 +0,0 @@ -define([ - './locales/ca.js', - './locales/cs.js', - './locales/de.js', - './locales/es.js', - './locales/fr.js', - './locales/it.js', - './locales/nl.js', - './locales/pl.js', - './locales/pt_br.js', - './locales/ro.js', - './locales/ru.js', - './locales/tr.js', - './locales/vi.js', - './locales/zh.js', - './locales/zh_cn.js' -], function() { - var langId = (navigator.language || navigator.userLanguage).toLowerCase().replace('-', '_'); - var language = langId.substr(0, 2); - var locales = {}; - - for (index in arguments) { - for (property in arguments[index]) - locales[property] = arguments[index][property]; - } - if ( ! locales['en']) - locales['en'] = {}; - - if ( ! locales[langId] && ! locales[language]) - language = 'en'; - - var locale = (locales[langId] ? locales[langId] : locales[language]); - - function __(text) { - var index = locale[text]; - if (index === undefined) - return text; - return index; - }; - - function setLanguage(language) { - locale = locales[language]; - } - - return { - __ : __, - locales : locales, - locale : locale, - setLanguage: setLanguage - }; -}); diff --git a/docs/api/locales/nl.js b/docs/api/locales/nl.js deleted file mode 100644 index bddfeeb1..00000000 --- a/docs/api/locales/nl.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - nl: { - 'Allowed values:' : 'Toegestane waarden:', - 'Compare all with predecessor': 'Vergelijk alle met voorgaande versie', - 'compare changes to:' : 'vergelijk veranderingen met:', - 'compared to' : 'vergelijk met', - 'Default value:' : 'Standaard waarde:', - 'Description' : 'Omschrijving', - 'Field' : 'Veld', - 'General' : 'Algemeen', - 'Generated with' : 'Gegenereerd met', - 'Name' : 'Naam', - 'No response values.' : 'Geen response waardes.', - 'optional' : 'optioneel', - 'Parameter' : 'Parameter', - 'Permission:' : 'Permissie:', - 'Response' : 'Antwoorden', - 'Send' : 'Sturen', - 'Send a Sample Request' : 'Stuur een sample aanvragen', - 'show up to version:' : 'toon tot en met versie:', - 'Size range:' : 'Maatbereik:', - 'Type' : 'Type', - 'url' : 'url' - } -}); diff --git a/docs/api/locales/pl.js b/docs/api/locales/pl.js deleted file mode 100644 index db645ee1..00000000 --- a/docs/api/locales/pl.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - pl: { - 'Allowed values:' : 'Dozwolone wartości:', - 'Compare all with predecessor': 'Porównaj z poprzednimi wersjami', - 'compare changes to:' : 'porównaj zmiany do:', - 'compared to' : 'porównaj do:', - 'Default value:' : 'Wartość domyślna:', - 'Description' : 'Opis', - 'Field' : 'Pole', - 'General' : 'Generalnie', - 'Generated with' : 'Wygenerowano z', - 'Name' : 'Nazwa', - 'No response values.' : 'Brak odpowiedzi.', - 'optional' : 'opcjonalny', - 'Parameter' : 'Parametr', - 'Permission:' : 'Uprawnienia:', - 'Response' : 'Odpowiedź', - 'Send' : 'Wyślij', - 'Send a Sample Request' : 'Wyślij przykładowe żądanie', - 'show up to version:' : 'pokaż do wersji:', - 'Size range:' : 'Zakres rozmiaru:', - 'Type' : 'Typ', - 'url' : 'url' - } -}); diff --git a/docs/api/locales/pt_br.js b/docs/api/locales/pt_br.js deleted file mode 100644 index 2bd78b0d..00000000 --- a/docs/api/locales/pt_br.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - 'pt_br': { - 'Allowed values:' : 'Valores permitidos:', - 'Compare all with predecessor': 'Compare todos com antecessores', - 'compare changes to:' : 'comparar alterações com:', - 'compared to' : 'comparado com', - 'Default value:' : 'Valor padrão:', - 'Description' : 'Descrição', - 'Field' : 'Campo', - 'General' : 'Geral', - 'Generated with' : 'Gerado com', - 'Name' : 'Nome', - 'No response values.' : 'Sem valores de resposta.', - 'optional' : 'opcional', - 'Parameter' : 'Parâmetro', - 'Permission:' : 'Permissão:', - 'Response' : 'Resposta', - 'Send' : 'Enviar', - 'Send a Sample Request' : 'Enviar um Exemplo de Pedido', - 'show up to version:' : 'aparecer para a versão:', - 'Size range:' : 'Faixa de tamanho:', - 'Type' : 'Tipo', - 'url' : 'url' - } -}); diff --git a/docs/api/locales/ro.js b/docs/api/locales/ro.js deleted file mode 100644 index 8d4e4ed8..00000000 --- a/docs/api/locales/ro.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - ro: { - 'Allowed values:' : 'Valori permise:', - 'Compare all with predecessor': 'Compară toate cu versiunea precedentă', - 'compare changes to:' : 'compară cu versiunea:', - 'compared to' : 'comparat cu', - 'Default value:' : 'Valoare implicită:', - 'Description' : 'Descriere', - 'Field' : 'Câmp', - 'General' : 'General', - 'Generated with' : 'Generat cu', - 'Name' : 'Nume', - 'No response values.' : 'Nici o valoare returnată.', - 'optional' : 'opțional', - 'Parameter' : 'Parametru', - 'Permission:' : 'Permisiune:', - 'Response' : 'Răspuns', - 'Send' : 'Trimite', - 'Send a Sample Request' : 'Trimite o cerere de probă', - 'show up to version:' : 'arată până la versiunea:', - 'Size range:' : 'Interval permis:', - 'Type' : 'Tip', - 'url' : 'url' - } -}); diff --git a/docs/api/locales/ru.js b/docs/api/locales/ru.js deleted file mode 100644 index c5f33821..00000000 --- a/docs/api/locales/ru.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - ru: { - 'Allowed values:' : 'Допустимые значения:', - 'Compare all with predecessor': 'Сравнить с предыдущей версией', - 'compare changes to:' : 'сравнить с:', - 'compared to' : 'в сравнении с', - 'Default value:' : 'По умолчанию:', - 'Description' : 'Описание', - 'Field' : 'Название', - 'General' : 'Общая информация', - 'Generated with' : 'Сгенерировано с помощью', - 'Name' : 'Название', - 'No response values.' : 'Нет значений для ответа.', - 'optional' : 'необязательный', - 'Parameter' : 'Параметр', - 'Permission:' : 'Разрешено:', - 'Response' : 'Ответ', - 'Send' : 'Отправить', - 'Send a Sample Request' : 'Отправить тестовый запрос', - 'show up to version:' : 'показать версию:', - 'Size range:' : 'Ограничения:', - 'Type' : 'Тип', - 'url' : 'URL' - } -}); diff --git a/docs/api/locales/tr.js b/docs/api/locales/tr.js deleted file mode 100644 index 5c64e52d..00000000 --- a/docs/api/locales/tr.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - tr: { - 'Allowed values:' : 'İzin verilen değerler:', - 'Compare all with predecessor': 'Tümünü öncekiler ile karşılaştır', - 'compare changes to:' : 'değişiklikleri karşılaştır:', - 'compared to' : 'karşılaştır', - 'Default value:' : 'Varsayılan değer:', - 'Description' : 'Açıklama', - 'Field' : 'Alan', - 'General' : 'Genel', - 'Generated with' : 'Oluşturan', - 'Name' : 'İsim', - 'No response values.' : 'Dönüş verisi yok.', - 'optional' : 'opsiyonel', - 'Parameter' : 'Parametre', - 'Permission:' : 'İzin:', - 'Response' : 'Dönüş', - 'Send' : 'Gönder', - 'Send a Sample Request' : 'Örnek istek gönder', - 'show up to version:' : 'bu versiyona kadar göster:', - 'Size range:' : 'Boyut aralığı:', - 'Type' : 'Tip', - 'url' : 'url' - } -}); diff --git a/docs/api/locales/vi.js b/docs/api/locales/vi.js deleted file mode 100644 index 7ce77050..00000000 --- a/docs/api/locales/vi.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - vi: { - 'Allowed values:' : 'Giá trị chấp nhận:', - 'Compare all with predecessor': 'So sánh với tất cả phiên bản trước', - 'compare changes to:' : 'so sánh sự thay đổi với:', - 'compared to' : 'so sánh với', - 'Default value:' : 'Giá trị mặc định:', - 'Description' : 'Chú thích', - 'Field' : 'Trường dữ liệu', - 'General' : 'Tổng quan', - 'Generated with' : 'Được tạo bởi', - 'Name' : 'Tên', - 'No response values.' : 'Không có kết quả trả về.', - 'optional' : 'Tùy chọn', - 'Parameter' : 'Tham số', - 'Permission:' : 'Quyền hạn:', - 'Response' : 'Kết quả', - 'Send' : 'Gửi', - 'Send a Sample Request' : 'Gửi một yêu cầu mẫu', - 'show up to version:' : 'hiển thị phiên bản:', - 'Size range:' : 'Kích cỡ:', - 'Type' : 'Kiểu', - 'url' : 'liên kết' - } -}); diff --git a/docs/api/locales/zh.js b/docs/api/locales/zh.js deleted file mode 100644 index 66522067..00000000 --- a/docs/api/locales/zh.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - zh: { - 'Allowed values​​:' : '允許值:', - 'Compare all with predecessor': '預先比較所有', - 'compare changes to:' : '比較變更:', - 'compared to' : '對比', - 'Default value:' : '默認值:', - 'Description' : '描述', - 'Field' : '字段', - 'General' : '概括', - 'Generated with' : '生成工具', - 'Name' : '名稱', - 'No response values​​.' : '無對應資料.', - 'optional' : '選項', - 'Parameter' : '參數', - 'Permission:' : '允許:', - 'Response' : '回應', - 'Send' : '發送', - 'Send a Sample Request' : '發送試用需求', - 'show up to version:' : '顯示到版本:', - 'Size range:' : '尺寸範圍:', - 'Type' : '類型', - 'url' : '網址' - } -}); diff --git a/docs/api/locales/zh_cn.js b/docs/api/locales/zh_cn.js deleted file mode 100644 index 1938ca18..00000000 --- a/docs/api/locales/zh_cn.js +++ /dev/null @@ -1,25 +0,0 @@ -define({ - 'zh_cn': { - 'Allowed values:' : '允许值:', - 'Compare all with predecessor': '与所有较早的比较', - 'compare changes to:' : '将当前版本与指定版本比较:', - 'compared to' : '相比于', - 'Default value:' : '默认值:', - 'Description' : '描述', - 'Field' : '字段', - 'General' : '概要', - 'Generated with' : '基于', - 'Name' : '名称', - 'No response values.' : '无返回值.', - 'optional' : '可选', - 'Parameter' : '参数', - 'Permission:' : '权限:', - 'Response' : '返回', - 'Send' : '发送', - 'Send a Sample Request' : '发送示例请求', - 'show up to version:' : '显示到指定版本:', - 'Size range:' : '取值范围:', - 'Type' : '类型', - 'url' : '网址' - } -}); diff --git a/docs/api/main.js b/docs/api/main.js deleted file mode 100644 index 9d31fa5f..00000000 --- a/docs/api/main.js +++ /dev/null @@ -1,827 +0,0 @@ -require.config({ - paths: { - bootstrap: './vendor/bootstrap.min', - diffMatchPatch: './vendor/diff_match_patch.min', - handlebars: './vendor/handlebars.min', - handlebarsExtended: './utils/handlebars_helper', - jquery: './vendor/jquery.min', - locales: './locales/locale', - lodash: './vendor/lodash.custom.min', - pathToRegexp: './vendor/path-to-regexp/index', - prettify: './vendor/prettify/prettify', - semver: './vendor/semver.min', - utilsSampleRequest: './utils/send_sample_request', - webfontloader: './vendor/webfontloader', - list: './vendor/list.min' - }, - shim: { - bootstrap: { - deps: ['jquery'] - }, - diffMatchPatch: { - exports: 'diff_match_patch' - }, - handlebars: { - exports: 'Handlebars' - }, - handlebarsExtended: { - deps: ['jquery', 'handlebars'], - exports: 'Handlebars' - }, - prettify: { - exports: 'prettyPrint' - } - }, - urlArgs: 'v=' + (new Date()).getTime(), - waitSeconds: 15 -}); - -require([ - 'jquery', - 'lodash', - 'locales', - 'handlebarsExtended', - './api_project.js', - './api_data.js', - 'prettify', - 'utilsSampleRequest', - 'semver', - 'webfontloader', - 'bootstrap', - 'pathToRegexp', - 'list' -], function($, _, locale, Handlebars, apiProject, apiData, prettyPrint, sampleRequest, semver, WebFont) { - - // load google web fonts - loadGoogleFontCss(); - - var api = apiData.api; - - // - // Templates - // - var templateHeader = Handlebars.compile( $('#template-header').html() ); - var templateFooter = Handlebars.compile( $('#template-footer').html() ); - var templateArticle = Handlebars.compile( $('#template-article').html() ); - var templateCompareArticle = Handlebars.compile( $('#template-compare-article').html() ); - var templateGenerator = Handlebars.compile( $('#template-generator').html() ); - var templateProject = Handlebars.compile( $('#template-project').html() ); - var templateSections = Handlebars.compile( $('#template-sections').html() ); - var templateSidenav = Handlebars.compile( $('#template-sidenav').html() ); - - // - // apiProject defaults - // - if ( ! apiProject.template) - apiProject.template = {}; - - if (apiProject.template.withCompare == null) - apiProject.template.withCompare = true; - - if (apiProject.template.withGenerator == null) - apiProject.template.withGenerator = true; - - if (apiProject.template.forceLanguage) - locale.setLanguage(apiProject.template.forceLanguage); - - // Setup jQuery Ajax - $.ajaxSetup(apiProject.template.jQueryAjaxSetup); - - // - // Data transform - // - // grouped by group - var apiByGroup = _.groupBy(api, function(entry) { - return entry.group; - }); - - // grouped by group and name - var apiByGroupAndName = {}; - $.each(apiByGroup, function(index, entries) { - apiByGroupAndName[index] = _.groupBy(entries, function(entry) { - return entry.name; - }); - }); - - // - // sort api within a group by title ASC and custom order - // - var newList = []; - var umlauts = { 'ä': 'ae', 'ü': 'ue', 'ö': 'oe', 'ß': 'ss' }; // TODO: remove in version 1.0 - $.each (apiByGroupAndName, function(index, groupEntries) { - // get titles from the first entry of group[].name[] (name has versioning) - var titles = []; - $.each (groupEntries, function(titleName, entries) { - var title = entries[0].title; - if(title !== undefined) { - title.toLowerCase().replace(/[äöüß]/g, function($0) { return umlauts[$0]; }); - titles.push(title + '#~#' + titleName); // '#~#' keep reference to titleName after sorting - } - }); - // sort by name ASC - titles.sort(); - - // custom order - if (apiProject.order) - titles = sortByOrder(titles, apiProject.order, '#~#'); - - // add single elements to the new list - titles.forEach(function(name) { - var values = name.split('#~#'); - var key = values[1]; - groupEntries[key].forEach(function(entry) { - newList.push(entry); - }); - }); - }); - // api overwrite with ordered list - api = newList; - - // - // Group- and Versionlists - // - var apiGroups = {}; - var apiGroupTitles = {}; - var apiVersions = {}; - apiVersions[apiProject.version] = 1; - - $.each(api, function(index, entry) { - apiGroups[entry.group] = 1; - apiGroupTitles[entry.group] = entry.groupTitle || entry.group; - apiVersions[entry.version] = 1; - }); - - // sort groups - apiGroups = Object.keys(apiGroups); - apiGroups.sort(); - - // custom order - if (apiProject.order) - apiGroups = sortByOrder(apiGroups, apiProject.order); - - // sort versions DESC - apiVersions = Object.keys(apiVersions); - apiVersions.sort(semver.compare); - apiVersions.reverse(); - - // - // create Navigationlist - // - var nav = []; - apiGroups.forEach(function(group) { - // Mainmenu entry - nav.push({ - group: group, - isHeader: true, - title: apiGroupTitles[group] - }); - - // Submenu - var oldName = ''; - api.forEach(function(entry) { - if (entry.group === group) { - if (oldName !== entry.name) { - nav.push({ - title: entry.title, - group: group, - name: entry.name, - type: entry.type, - version: entry.version - }); - } else { - nav.push({ - title: entry.title, - group: group, - hidden: true, - name: entry.name, - type: entry.type, - version: entry.version - }); - } - oldName = entry.name; - } - }); - }); - - /** - * Add navigation items by analyzing the HTML content and searching for h1 and h2 tags - * @param nav Object the navigation array - * @param content string the compiled HTML content - * @param index where to insert items - * @return boolean true if any good-looking (i.e. with a group identifier)

tag was found - */ - function add_nav(nav, content, index) { - var found_level1 = false; - if ( ! content) { - return found_level1; - } - var topics = content.match(/(.+?)<\/h(1|2)>/gi); - if ( topics ) { - topics.forEach(function(entry) { - var level = entry.substring(2,3); - var title = entry.replace(/<.+?>/g, ''); // Remove all HTML tags for the title - var entry_tags = entry.match(/id="api-([^\-]+)(?:-(.+))?"/); // Find the group and name in the id property - var group = (entry_tags ? entry_tags[1] : null); - var name = (entry_tags ? entry_tags[2] : null); - if (level==1 && title && group) { - nav.splice(index, 0, { - group: group, - isHeader: true, - title: title, - isFixed: true - }); - index++; - found_level1 = true; - } - if (level==2 && title && group && name) { - nav.splice(index, 0, { - group: group, - name: name, - isHeader: false, - title: title, - isFixed: false, - version: '1.0' - }); - index++; - } - }); - } - return found_level1; - } - - // Mainmenu Header entry - if (apiProject.header) { - var found_level1 = add_nav(nav, apiProject.header.content, 0); // Add level 1 and 2 titles - if (!found_level1) { // If no Level 1 tags were found, make a title - nav.unshift({ - group: '_', - isHeader: true, - title: (apiProject.header.title == null) ? locale.__('General') : apiProject.header.title, - isFixed: true - }); - } - } - - // Mainmenu Footer entry - if (apiProject.footer) { - var last_nav_index = nav.length; - var found_level1 = add_nav(nav, apiProject.footer.content, nav.length); // Add level 1 and 2 titles - if (!found_level1 && apiProject.footer.title != null) { // If no Level 1 tags were found, make a title - nav.splice(last_nav_index, 0, { - group: '_footer', - isHeader: true, - title: apiProject.footer.title, - isFixed: true - }); - } - } - - // render pagetitle - var title = apiProject.title ? apiProject.title : 'apiDoc: ' + apiProject.name + ' - ' + apiProject.version; - $(document).attr('title', title); - - // remove loader - $('#loader').remove(); - - // render sidenav - var fields = { - nav: nav - }; - $('#sidenav').append( templateSidenav(fields) ); - - // render Generator - $('#generator').append( templateGenerator(apiProject) ); - - // render Project - _.extend(apiProject, { versions: apiVersions}); - $('#project').append( templateProject(apiProject) ); - - // render apiDoc, header/footer documentation - if (apiProject.header) - $('#header').append( templateHeader(apiProject.header) ); - - if (apiProject.footer) - $('#footer').append( templateFooter(apiProject.footer) ); - - // - // Render Sections and Articles - // - var articleVersions = {}; - var content = ''; - apiGroups.forEach(function(groupEntry) { - var articles = []; - var oldName = ''; - var fields = {}; - var title = groupEntry; - var description = ''; - articleVersions[groupEntry] = {}; - - // render all articles of a group - api.forEach(function(entry) { - if(groupEntry === entry.group) { - if (oldName !== entry.name) { - // determine versions - api.forEach(function(versionEntry) { - if (groupEntry === versionEntry.group && entry.name === versionEntry.name) { - if ( ! articleVersions[entry.group].hasOwnProperty(entry.name) ) { - articleVersions[entry.group][entry.name] = []; - } - articleVersions[entry.group][entry.name].push(versionEntry.version); - } - }); - fields = { - article: entry, - versions: articleVersions[entry.group][entry.name] - }; - } else { - fields = { - article: entry, - hidden: true, - versions: articleVersions[entry.group][entry.name] - }; - } - - // add prefix URL for endpoint - if (apiProject.url) - fields.article.url = apiProject.url + fields.article.url; - - addArticleSettings(fields, entry); - - if (entry.groupTitle) - title = entry.groupTitle; - - // TODO: make groupDescription compareable with older versions (not important for the moment) - if (entry.groupDescription) - description = entry.groupDescription; - - articles.push({ - article: templateArticle(fields), - group: entry.group, - name: entry.name - }); - oldName = entry.name; - } - }); - - // render Section with Articles - var fields = { - group: groupEntry, - title: title, - description: description, - articles: articles - }; - content += templateSections(fields); - }); - $('#sections').append( content ); - - // Bootstrap Scrollspy - $(this).scrollspy({ target: '#scrollingNav', offset: 18 }); - - // Content-Scroll on Navigation click. - $('.sidenav').find('a').on('click', function(e) { - e.preventDefault(); - var id = $(this).attr('href'); - if ($(id).length > 0) - $('html,body').animate({ scrollTop: parseInt($(id).offset().top) }, 400); - window.location.hash = $(this).attr('href'); - }); - - // Quickjump on Pageload to hash position. - if(window.location.hash) { - var id = window.location.hash; - if ($(id).length > 0) - $('html,body').animate({ scrollTop: parseInt($(id).offset().top) }, 0); - } - - /** - * Check if Parameter (sub) List has a type Field. - * Example: @apiSuccess varname1 No type. - * @apiSuccess {String} varname2 With type. - * - * @param {Object} fields - */ - function _hasTypeInFields(fields) { - var result = false; - $.each(fields, function(name) { - result = result || _.some(fields[name], function(item) { return item.type; }); - }); - return result; - } - - /** - * On Template changes, recall plugins. - */ - function initDynamic() { - // Bootstrap popover - $('button[data-toggle="popover"]').popover().click(function(e) { - e.preventDefault(); - }); - - var version = $('#version strong').html(); - $('#sidenav li').removeClass('is-new'); - if (apiProject.template.withCompare) { - $('#sidenav li[data-version=\'' + version + '\']').each(function(){ - var group = $(this).data('group'); - var name = $(this).data('name'); - var length = $('#sidenav li[data-group=\'' + group + '\'][data-name=\'' + name + '\']').length; - var index = $('#sidenav li[data-group=\'' + group + '\'][data-name=\'' + name + '\']').index($(this)); - if (length === 1 || index === (length - 1)) - $(this).addClass('is-new'); - }); - } - - // tabs - $('.nav-tabs-examples a').click(function (e) { - e.preventDefault(); - $(this).tab('show'); - }); - $('.nav-tabs-examples').find('a:first').tab('show'); - - // sample request switch - $('.sample-request-switch').click(function (e) { - var name = '.' + $(this).attr('name') + '-fields'; - $(name).addClass('hide'); - $(this).parent().next(name).removeClass('hide'); - }); - - // call scrollspy refresh method - $(window).scrollspy('refresh'); - - // init modules - sampleRequest.initDynamic(); - } - initDynamic(); - - // Pre- / Code-Format - prettyPrint(); - - // - // HTML-Template specific jQuery-Functions - // - // Change Main Version - $('#versions li.version a').on('click', function(e) { - e.preventDefault(); - - var selectedVersion = $(this).html(); - $('#version strong').html(selectedVersion); - - // hide all - $('article').addClass('hide'); - $('#sidenav li:not(.nav-fixed)').addClass('hide'); - - // show 1st equal or lower Version of each entry - $('article[data-version]').each(function(index) { - var group = $(this).data('group'); - var name = $(this).data('name'); - var version = $(this).data('version'); - - if (semver.lte(version, selectedVersion)) { - if ($('article[data-group=\'' + group + '\'][data-name=\'' + name + '\']:visible').length === 0) { - // enable Article - $('article[data-group=\'' + group + '\'][data-name=\'' + name + '\'][data-version=\'' + version + '\']').removeClass('hide'); - // enable Navigation - $('#sidenav li[data-group=\'' + group + '\'][data-name=\'' + name + '\'][data-version=\'' + version + '\']').removeClass('hide'); - $('#sidenav li.nav-header[data-group=\'' + group + '\']').removeClass('hide'); - } - } - }); - - // show 1st equal or lower Version of each entry - $('article[data-version]').each(function(index) { - var group = $(this).data('group'); - $('section#api-' + group).removeClass('hide'); - if ($('section#api-' + group + ' article:visible').length === 0) { - $('section#api-' + group).addClass('hide'); - } else { - $('section#api-' + group).removeClass('hide'); - } - }); - - initDynamic(); - return; - }); - - // compare all article with their predecessor - $('#compareAllWithPredecessor').on('click', changeAllVersionCompareTo); - - // change version of an article - $('article .versions li.version a').on('click', changeVersionCompareTo); - - // compare url-parameter - $.urlParam = function(name) { - var results = new RegExp('[\\?&]' + name + '=([^&#]*)').exec(window.location.href); - return (results && results[1]) ? results[1] : null; - }; - - if ($.urlParam('compare')) { - // URL Paramter ?compare=1 is set - $('#compareAllWithPredecessor').trigger('click'); - - if (window.location.hash) { - var id = window.location.hash; - $('html,body').animate({ scrollTop: parseInt($(id).offset().top) - 18 }, 0); - } - } - - /** - * Initialize search - */ - var options = { - valueNames: [ 'nav-list-item' ] - }; - var endpointsList = new List('scrollingNav', options); - - /** - * Set initial focus to search input - */ - $('#scrollingNav .sidenav-search input.search').focus(); - - /** - * Detect ESC key to reset search - */ - $(document).keyup(function(e) { - if (e.keyCode === 27) $('span.search-reset').click(); - }); - - /** - * Search reset - */ - $('span.search-reset').on('click', function() { - $('#scrollingNav .sidenav-search input.search') - .val("") - .focus() - ; - endpointsList.search(); - }); - - /** - * Change version of an article to compare it to an other version. - */ - function changeVersionCompareTo(e) { - e.preventDefault(); - - var $root = $(this).parents('article'); - var selectedVersion = $(this).html(); - var $button = $root.find('.version'); - var currentVersion = $button.find('strong').html(); - $button.find('strong').html(selectedVersion); - - var group = $root.data('group'); - var name = $root.data('name'); - var version = $root.data('version'); - - var compareVersion = $root.data('compare-version'); - - if (compareVersion === selectedVersion) - return; - - if ( ! compareVersion && version == selectedVersion) - return; - - if (compareVersion && articleVersions[group][name][0] === selectedVersion || version === selectedVersion) { - // the version of the entry is set to the highest version (reset) - resetArticle(group, name, version); - } else { - var $compareToArticle = $('article[data-group=\'' + group + '\'][data-name=\'' + name + '\'][data-version=\'' + selectedVersion + '\']'); - - var sourceEntry = {}; - var compareEntry = {}; - $.each(apiByGroupAndName[group][name], function(index, entry) { - if (entry.version === version) - sourceEntry = entry; - if (entry.version === selectedVersion) - compareEntry = entry; - }); - - var fields = { - article: sourceEntry, - compare: compareEntry, - versions: articleVersions[group][name] - }; - - // add unique id - // TODO: replace all group-name-version in template with id. - fields.article.id = fields.article.group + '-' + fields.article.name + '-' + fields.article.version; - fields.article.id = fields.article.id.replace(/\./g, '_'); - - fields.compare.id = fields.compare.group + '-' + fields.compare.name + '-' + fields.compare.version; - fields.compare.id = fields.compare.id.replace(/\./g, '_'); - - var entry = sourceEntry; - if (entry.parameter && entry.parameter.fields) - fields._hasTypeInParameterFields = _hasTypeInFields(entry.parameter.fields); - - if (entry.error && entry.error.fields) - fields._hasTypeInErrorFields = _hasTypeInFields(entry.error.fields); - - if (entry.success && entry.success.fields) - fields._hasTypeInSuccessFields = _hasTypeInFields(entry.success.fields); - - if (entry.info && entry.info.fields) - fields._hasTypeInInfoFields = _hasTypeInFields(entry.info.fields); - - var entry = compareEntry; - if (fields._hasTypeInParameterFields !== true && entry.parameter && entry.parameter.fields) - fields._hasTypeInParameterFields = _hasTypeInFields(entry.parameter.fields); - - if (fields._hasTypeInErrorFields !== true && entry.error && entry.error.fields) - fields._hasTypeInErrorFields = _hasTypeInFields(entry.error.fields); - - if (fields._hasTypeInSuccessFields !== true && entry.success && entry.success.fields) - fields._hasTypeInSuccessFields = _hasTypeInFields(entry.success.fields); - - if (fields._hasTypeInInfoFields !== true && entry.info && entry.info.fields) - fields._hasTypeInInfoFields = _hasTypeInFields(entry.info.fields); - - var content = templateCompareArticle(fields); - $root.after(content); - var $content = $root.next(); - - // Event on.click re-assign - $content.find('.versions li.version a').on('click', changeVersionCompareTo); - - // select navigation - $('#sidenav li[data-group=\'' + group + '\'][data-name=\'' + name + '\'][data-version=\'' + currentVersion + '\']').addClass('has-modifications'); - - $root.remove(); - // TODO: on change main version or select the highest version re-render - } - - initDynamic(); - } - - /** - * Compare all currently selected Versions with their predecessor. - */ - function changeAllVersionCompareTo(e) { - e.preventDefault(); - $('article:visible .versions').each(function(){ - var $root = $(this).parents('article'); - var currentVersion = $root.data('version'); - var $foundElement = null; - $(this).find('li.version a').each(function() { - var selectVersion = $(this).html(); - if (selectVersion < currentVersion && ! $foundElement) - $foundElement = $(this); - }); - - if($foundElement) - $foundElement.trigger('click'); - }); - initDynamic(); - } - - /** - * Sort the fields. - */ - function sortFields(fields_object) { - $.each(fields_object, function (key, fields) { - - var reversed = fields.slice().reverse() - - var max_dot_count = Math.max.apply(null, reversed.map(function (item) { - return item.field.split(".").length - 1; - })) - - for (var dot_count = 1; dot_count <= max_dot_count; dot_count++) { - reversed.forEach(function (item, index) { - var parts = item.field.split("."); - if (parts.length - 1 == dot_count) { - var fields_names = fields.map(function (item) { return item.field; }); - if (parts.slice(1).length >= 1) { - var prefix = parts.slice(0, parts.length - 1).join("."); - var prefix_index = fields_names.indexOf(prefix); - if (prefix_index > -1) { - fields.splice(fields_names.indexOf(item.field), 1); - fields.splice(prefix_index + 1, 0, item); - } - } - } - }); - } - }); - } - - /** - * Add article settings. - */ - function addArticleSettings(fields, entry) { - // add unique id - // TODO: replace all group-name-version in template with id. - fields.id = fields.article.group + '-' + fields.article.name + '-' + fields.article.version; - fields.id = fields.id.replace(/\./g, '_'); - - if (entry.header && entry.header.fields) { - sortFields(entry.header.fields); - fields._hasTypeInHeaderFields = _hasTypeInFields(entry.header.fields); - } - - if (entry.parameter && entry.parameter.fields) { - sortFields(entry.parameter.fields); - fields._hasTypeInParameterFields = _hasTypeInFields(entry.parameter.fields); - } - - if (entry.error && entry.error.fields) { - sortFields(entry.error.fields); - fields._hasTypeInErrorFields = _hasTypeInFields(entry.error.fields); - } - - if (entry.success && entry.success.fields) { - sortFields(entry.success.fields); - fields._hasTypeInSuccessFields = _hasTypeInFields(entry.success.fields); - } - - if (entry.info && entry.info.fields) { - sortFields(entry.info.fields); - fields._hasTypeInInfoFields = _hasTypeInFields(entry.info.fields); - } - - // add template settings - fields.template = apiProject.template; - } - - /** - * Render Article. - */ - function renderArticle(group, name, version) { - var entry = {}; - $.each(apiByGroupAndName[group][name], function(index, currentEntry) { - if (currentEntry.version === version) - entry = currentEntry; - }); - var fields = { - article: entry, - versions: articleVersions[group][name] - }; - - addArticleSettings(fields, entry); - - return templateArticle(fields); - } - - /** - * Render original Article and remove the current visible Article. - */ - function resetArticle(group, name, version) { - var $root = $('article[data-group=\'' + group + '\'][data-name=\'' + name + '\']:visible'); - var content = renderArticle(group, name, version); - - $root.after(content); - var $content = $root.next(); - - // Event on.click muss neu zugewiesen werden (sollte eigentlich mit on automatisch funktionieren... sollte) - $content.find('.versions li.version a').on('click', changeVersionCompareTo); - - $('#sidenav li[data-group=\'' + group + '\'][data-name=\'' + name + '\'][data-version=\'' + version + '\']').removeClass('has-modifications'); - - $root.remove(); - return; - } - - /** - * Load google fonts. - */ - function loadGoogleFontCss() { - WebFont.load({ - active: function() { - // Update scrollspy - $(window).scrollspy('refresh') - }, - google: { - families: ['Source Code Pro', 'Source Sans Pro:n4,n6,n7'] - } - }); - } - - /** - * Return ordered entries by custom order and append not defined entries to the end. - * @param {String[]} elements - * @param {String[]} order - * @param {String} splitBy - * @return {String[]} Custom ordered list. - */ - function sortByOrder(elements, order, splitBy) { - var results = []; - order.forEach (function(name) { - if (splitBy) - elements.forEach (function(element) { - var parts = element.split(splitBy); - var key = parts[1]; // reference keep for sorting - if (key == name) - results.push(element); - }); - else - elements.forEach (function(key) { - if (key == name) - results.push(name); - }); - }); - // Append all other entries that ar not defined in order - elements.forEach(function(element) { - if (results.indexOf(element) === -1) - results.push(element); - }); - return results; - } - -}); diff --git a/docs/api/utils/handlebars_helper.js b/docs/api/utils/handlebars_helper.js deleted file mode 100644 index a5d5c4fd..00000000 --- a/docs/api/utils/handlebars_helper.js +++ /dev/null @@ -1,357 +0,0 @@ -define([ - 'locales', - 'handlebars', - 'diffMatchPatch' -], function(locale, Handlebars, DiffMatchPatch) { - - /** - * Return a text as markdown. - * Currently only a little helper to replace apidoc-inline Links (#Group:Name). - * Should be replaced with a full markdown lib. - * @param string text - */ - Handlebars.registerHelper('markdown', function(text) { - if ( ! text ) { - return text; - } - text = text.replace(/((\[(.*?)\])?\(#)((.+?):(.+?))(\))/mg, function(match, p1, p2, p3, p4, p5, p6) { - var link = p3 || p5 + '/' + p6; - return '' + link + ''; - }); - return text; - }); - - /** - * start/stop timer for simple performance check. - */ - var timer; - Handlebars.registerHelper('startTimer', function(text) { - timer = new Date(); - return ''; - }); - - Handlebars.registerHelper('stopTimer', function(text) { - console.log(new Date() - timer); - return ''; - }); - - /** - * Return localized Text. - * @param string text - */ - Handlebars.registerHelper('__', function(text) { - return locale.__(text); - }); - - /** - * Console log. - * @param mixed obj - */ - Handlebars.registerHelper('cl', function(obj) { - console.log(obj); - return ''; - }); - - /** - * Replace underscore with space. - * @param string text - */ - Handlebars.registerHelper('underscoreToSpace', function(text) { - return text.replace(/(_+)/g, ' '); - }); - - /** - * - */ - Handlebars.registerHelper('assign', function(name) { - if(arguments.length > 0) { - var type = typeof(arguments[1]); - var arg = null; - if(type === 'string' || type === 'number' || type === 'boolean') arg = arguments[1]; - Handlebars.registerHelper(name, function() { return arg; }); - } - return ''; - }); - - /** - * - */ - Handlebars.registerHelper('nl2br', function(text) { - return _handlebarsNewlineToBreak(text); - }); - - /** - * - */ - Handlebars.registerHelper('if_eq', function(context, options) { - var compare = context; - // Get length if context is an object - if (context instanceof Object && ! (options.hash.compare instanceof Object)) - compare = Object.keys(context).length; - - if (compare === options.hash.compare) - return options.fn(this); - - return options.inverse(this); - }); - - /** - * - */ - Handlebars.registerHelper('if_gt', function(context, options) { - var compare = context; - // Get length if context is an object - if (context instanceof Object && ! (options.hash.compare instanceof Object)) - compare = Object.keys(context).length; - - if(compare > options.hash.compare) - return options.fn(this); - - return options.inverse(this); - }); - - /** - * - */ - var templateCache = {}; - Handlebars.registerHelper('subTemplate', function(name, sourceContext) { - if ( ! templateCache[name]) - templateCache[name] = Handlebars.compile($('#template-' + name).html()); - - var template = templateCache[name]; - var templateContext = $.extend({}, this, sourceContext.hash); - return new Handlebars.SafeString( template(templateContext) ); - }); - - /** - * - */ - Handlebars.registerHelper('toLowerCase', function(value) { - return (value && typeof value === 'string') ? value.toLowerCase() : ''; - }); - - /** - * - */ - Handlebars.registerHelper('splitFill', function(value, splitChar, fillChar) { - var splits = value.split(splitChar); - return new Array(splits.length).join(fillChar) + splits[splits.length - 1]; - }); - - /** - * Convert Newline to HTML-Break (nl2br). - * - * @param {String} text - * @returns {String} - */ - function _handlebarsNewlineToBreak(text) { - return ('' + text).replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + '
' + '$2'); - } - - /** - * - */ - Handlebars.registerHelper('each_compare_list_field', function(source, compare, options) { - var fieldName = options.hash.field; - var newSource = []; - if (source) { - source.forEach(function(entry) { - var values = entry; - values['key'] = entry[fieldName]; - newSource.push(values); - }); - } - - var newCompare = []; - if (compare) { - compare.forEach(function(entry) { - var values = entry; - values['key'] = entry[fieldName]; - newCompare.push(values); - }); - } - return _handlebarsEachCompared('key', newSource, newCompare, options); - }); - - /** - * - */ - Handlebars.registerHelper('each_compare_keys', function(source, compare, options) { - var newSource = []; - if (source) { - var sourceFields = Object.keys(source); - sourceFields.forEach(function(name) { - var values = {}; - values['value'] = source[name]; - values['key'] = name; - newSource.push(values); - }); - } - - var newCompare = []; - if (compare) { - var compareFields = Object.keys(compare); - compareFields.forEach(function(name) { - var values = {}; - values['value'] = compare[name]; - values['key'] = name; - newCompare.push(values); - }); - } - return _handlebarsEachCompared('key', newSource, newCompare, options); - }); - - /** - * - */ - Handlebars.registerHelper('each_compare_field', function(source, compare, options) { - return _handlebarsEachCompared('field', source, compare, options); - }); - - /** - * - */ - Handlebars.registerHelper('each_compare_title', function(source, compare, options) { - return _handlebarsEachCompared('title', source, compare, options); - }); - - /** - * - */ - Handlebars.registerHelper('reformat', function(source, type){ - if (type == 'json') - try { - return JSON.stringify(JSON.parse(source.trim()),null, " "); - } catch(e) { - - } - return source - }); - - /** - * - */ - Handlebars.registerHelper('showDiff', function(source, compare, options) { - var ds = ''; - if(source === compare) { - ds = source; - } else { - if( ! source) - return compare; - - if( ! compare) - return source; - - var d = diffMatchPatch.diff_main(compare, source); - diffMatchPatch.diff_cleanupSemantic(d); - ds = diffMatchPatch.diff_prettyHtml(d); - ds = ds.replace(/¶/gm, ''); - } - if(options === 'nl2br') - ds = _handlebarsNewlineToBreak(ds); - - return ds; - }); - - /** - * - */ - function _handlebarsEachCompared(fieldname, source, compare, options) - { - var dataList = []; - var index = 0; - if(source) { - source.forEach(function(sourceEntry) { - var found = false; - if (compare) { - compare.forEach(function(compareEntry) { - if(sourceEntry[fieldname] === compareEntry[fieldname]) { - var data = { - typeSame: true, - source: sourceEntry, - compare: compareEntry, - index: index - }; - dataList.push(data); - found = true; - index++; - } - }); - } - if ( ! found) { - var data = { - typeIns: true, - source: sourceEntry, - index: index - }; - dataList.push(data); - index++; - } - }); - } - - if (compare) { - compare.forEach(function(compareEntry) { - var found = false; - if (source) { - source.forEach(function(sourceEntry) { - if(sourceEntry[fieldname] === compareEntry[fieldname]) - found = true; - }); - } - if ( ! found) { - var data = { - typeDel: true, - compare: compareEntry, - index: index - }; - dataList.push(data); - index++; - } - }); - } - - var ret = ''; - var length = dataList.length; - for (var index in dataList) { - if(index == (length - 1)) - dataList[index]['_last'] = true; - ret = ret + options.fn(dataList[index]); - } - return ret; - } - - var diffMatchPatch = new DiffMatchPatch(); - - /** - * Overwrite Colors - */ - DiffMatchPatch.prototype.diff_prettyHtml = function(diffs) { - var html = []; - var pattern_amp = /&/g; - var pattern_lt = //g; - var pattern_para = /\n/g; - for (var x = 0; x < diffs.length; x++) { - var op = diffs[x][0]; // Operation (insert, delete, equal) - var data = diffs[x][1]; // Text of change. - var text = data.replace(pattern_amp, '&').replace(pattern_lt, '<') - .replace(pattern_gt, '>').replace(pattern_para, '¶
'); - switch (op) { - case DIFF_INSERT: - html[x] = '' + text + ''; - break; - case DIFF_DELETE: - html[x] = '' + text + ''; - break; - case DIFF_EQUAL: - html[x] = '' + text + ''; - break; - } - } - return html.join(''); - }; - - // Exports - return Handlebars; -}); diff --git a/docs/api/utils/send_sample_request.js b/docs/api/utils/send_sample_request.js deleted file mode 100755 index f2396ea9..00000000 --- a/docs/api/utils/send_sample_request.js +++ /dev/null @@ -1,184 +0,0 @@ -define([ - 'jquery', - 'lodash' -], function($, _) { - - var initDynamic = function() { - // Button send - $(".sample-request-send").off("click"); - $(".sample-request-send").on("click", function(e) { - e.preventDefault(); - var $root = $(this).parents("article"); - var group = $root.data("group"); - var name = $root.data("name"); - var version = $root.data("version"); - sendSampleRequest(group, name, version, $(this).data("sample-request-type")); - }); - - // Button clear - $(".sample-request-clear").off("click"); - $(".sample-request-clear").on("click", function(e) { - e.preventDefault(); - var $root = $(this).parents("article"); - var group = $root.data("group"); - var name = $root.data("name"); - var version = $root.data("version"); - clearSampleRequest(group, name, version); - }); - }; // initDynamic - - function sendSampleRequest(group, name, version, type) - { - var $root = $('article[data-group="' + group + '"][data-name="' + name + '"][data-version="' + version + '"]'); - - // Optional header - var header = {}; - $root.find(".sample-request-header:checked").each(function(i, element) { - var group = $(element).data("sample-request-header-group-id"); - $root.find("[data-sample-request-header-group=\"" + group + "\"]").each(function(i, element) { - var key = $(element).data("sample-request-header-name"); - var value = element.value; - if ( ! element.optional && element.defaultValue !== '') { - value = element.defaultValue; - } - header[key] = value; - }); - }); - - // create JSON dictionary of parameters - var param = {}; - var paramType = {}; - $root.find(".sample-request-param:checked").each(function(i, element) { - var group = $(element).data("sample-request-param-group-id"); - $root.find("[data-sample-request-param-group=\"" + group + "\"]").not(function(){ - return $(this).val() == "" && $(this).is("[data-sample-request-param-optional='true']"); - }).each(function(i, element) { - var key = $(element).data("sample-request-param-name"); - var value = element.value; - if ( ! element.optional && element.defaultValue !== '') { - value = element.defaultValue; - } - param[key] = value; - paramType[key] = $(element).next().text(); - }); - }); - - // grab user-inputted URL - var url = $root.find(".sample-request-url").val(); - - // Insert url parameter - var pattern = pathToRegexp(url, null); - var matches = pattern.exec(url); - for (var i = 1; i < matches.length; i++) { - var key = matches[i].substr(1); - if (param[key] !== undefined) { - url = url.replace(matches[i], encodeURIComponent(param[key])); - - // remove URL parameters from list - delete param[key]; - } - } // for - - $root.find(".sample-request-response").fadeTo(250, 1); - $root.find(".sample-request-response-json").html("Loading..."); - refreshScrollSpy(); - - _.each( param, function( val, key ) { - var t = paramType[ key ].toLowerCase(); - if ( t === 'object' || t === 'array' ) { - try { - param[ key ] = JSON.parse( val ); - } catch (e) { - } - } - }); - - // send AJAX request, catch success or error callback - var ajaxRequest = { - url : url, - headers : header, - data : param, - type : type.toUpperCase(), - success : displaySuccess, - error : displayError - }; - - $.ajax(ajaxRequest); - - - function displaySuccess(data, status, jqXHR) { - var jsonResponse; - try { - jsonResponse = JSON.parse(jqXHR.responseText); - jsonResponse = JSON.stringify(jsonResponse, null, 4); - } catch (e) { - jsonResponse = data; - } - $root.find(".sample-request-response-json").html(jsonResponse); - refreshScrollSpy(); - }; - - function displayError(jqXHR, textStatus, error) { - var message = "Error " + jqXHR.status + ": " + error; - var jsonResponse; - try { - jsonResponse = JSON.parse(jqXHR.responseText); - jsonResponse = JSON.stringify(jsonResponse, null, 4); - } catch (e) { - jsonResponse = escape(jqXHR.responseText); - } - - if (jsonResponse) - message += "
" + jsonResponse; - - // flicker on previous error to make clear that there is a new response - if($root.find(".sample-request-response").is(":visible")) - $root.find(".sample-request-response").fadeTo(1, 0.1); - - $root.find(".sample-request-response").fadeTo(250, 1); - $root.find(".sample-request-response-json").html(message); - refreshScrollSpy(); - }; - } - - function clearSampleRequest(group, name, version) - { - var $root = $('article[data-group="' + group + '"][data-name="' + name + '"][data-version="' + version + '"]'); - - // hide sample response - $root.find(".sample-request-response-json").html(""); - $root.find(".sample-request-response").hide(); - - // reset value of parameters - $root.find(".sample-request-param").each(function(i, element) { - element.value = ""; - }); - - // restore default URL - var $urlElement = $root.find(".sample-request-url"); - $urlElement.val($urlElement.prop("defaultValue")); - - refreshScrollSpy(); - } - - function refreshScrollSpy() - { - $('[data-spy="scroll"]').each(function () { - $(this).scrollspy("refresh"); - }); - } - - function escapeHtml(str) { - var div = document.createElement("div"); - div.appendChild(document.createTextNode(str)); - return div.innerHTML; - } - - /** - * Exports. - */ - return { - initDynamic: initDynamic - }; - -}); diff --git a/docs/api/vendor/bootstrap.min.css b/docs/api/vendor/bootstrap.min.css deleted file mode 100644 index ed3905e0..00000000 --- a/docs/api/vendor/bootstrap.min.css +++ /dev/null @@ -1,6 +0,0 @@ -/*! - * Bootstrap v3.3.7 (http://getbootstrap.com) - * Copyright 2011-2016 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\002a"}.glyphicon-plus:before{content:"\002b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control::-ms-expand{background-color:transparent;border:0}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled.focus,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled].focus,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled].focus,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled].focus,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled].focus,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled].focus,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled].focus,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:focus{z-index:3}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:2;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:3;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{padding-right:15px;padding-left:15px;border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);background-color:rgba(0,0,0,0);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-10px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.modal-header:after,.modal-header:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.modal-header:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} -/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/docs/api/vendor/bootstrap.min.js b/docs/api/vendor/bootstrap.min.js deleted file mode 100644 index 9bcd2fcc..00000000 --- a/docs/api/vendor/bootstrap.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * Bootstrap v3.3.7 (http://getbootstrap.com) - * Copyright 2011-2016 Twitter, Inc. - * Licensed under the MIT license - */ -if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>3)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){if(a(b.target).is(this))return b.handleObj.handler.apply(this,arguments)}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.7",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a("#"===f?[]:f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.7",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c).prop(c,!0)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c).prop(c,!1))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target).closest(".btn");b.call(d,"toggle"),a(c.target).is('input[type="radio"], input[type="checkbox"]')||(c.preventDefault(),d.is("input,button")?d.trigger("focus"):d.find("input:visible,button:visible").first().trigger("focus"))}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.7",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));if(!(a>this.$items.length-1||a<0))return this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){if(!this.sliding)return this.slide("next")},c.prototype.prev=function(){if(!this.sliding)return this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.7",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",f)))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.7",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger(a.Event("shown.bs.dropdown",h))}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&jdocument.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth
',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);if(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),!c.isInStateTrue())return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-mo.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null,a.$element=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;!e&&/destroy|hide/.test(b)||(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.7",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.7",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.7",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return e=a-d&&"bottom"},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); \ No newline at end of file diff --git a/docs/api/vendor/diff_match_patch.min.js b/docs/api/vendor/diff_match_patch.min.js deleted file mode 100644 index c41b5132..00000000 --- a/docs/api/vendor/diff_match_patch.min.js +++ /dev/null @@ -1,49 +0,0 @@ -(function(){function diff_match_patch(){this.Diff_Timeout=1;this.Diff_EditCost=4;this.Match_Threshold=0.5;this.Match_Distance=1E3;this.Patch_DeleteThreshold=0.5;this.Patch_Margin=4;this.Match_MaxBits=32} -diff_match_patch.prototype.diff_main=function(a,b,c,d){"undefined"==typeof d&&(d=0>=this.Diff_Timeout?Number.MAX_VALUE:(new Date).getTime()+1E3*this.Diff_Timeout);if(null==a||null==b)throw Error("Null input. (diff_main)");if(a==b)return a?[[0,a]]:[];"undefined"==typeof c&&(c=!0);var e=c,f=this.diff_commonPrefix(a,b);c=a.substring(0,f);a=a.substring(f);b=b.substring(f);var f=this.diff_commonSuffix(a,b),g=a.substring(a.length-f);a=a.substring(0,a.length-f);b=b.substring(0,b.length-f);a=this.diff_compute_(a, -b,e,d);c&&a.unshift([0,c]);g&&a.push([0,g]);this.diff_cleanupMerge(a);return a}; -diff_match_patch.prototype.diff_compute_=function(a,b,c,d){if(!a)return[[1,b]];if(!b)return[[-1,a]];var e=a.length>b.length?a:b,f=a.length>b.length?b:a,g=e.indexOf(f);return-1!=g?(c=[[1,e.substring(0,g)],[0,f],[1,e.substring(g+f.length)]],a.length>b.length&&(c[0][0]=c[2][0]=-1),c):1==f.length?[[-1,a],[1,b]]:(e=this.diff_halfMatch_(a,b))?(f=e[0],a=e[1],g=e[2],b=e[3],e=e[4],f=this.diff_main(f,g,c,d),c=this.diff_main(a,b,c,d),f.concat([[0,e]],c)):c&&100c);v++){for(var n=-v+r;n<=v-t;n+=2){var l=g+n,m;m=n==-v||n!=v&&j[l-1]d)t+=2;else if(s>e)r+=2;else if(q&&(l=g+k-n,0<=l&&l= -u)return this.diff_bisectSplit_(a,b,m,s,c)}}for(n=-v+p;n<=v-w;n+=2){l=g+n;u=n==-v||n!=v&&i[l-1]d)w+=2;else if(m>e)p+=2;else if(!q&&(l=g+k-n,0<=l&&(l=u)))return this.diff_bisectSplit_(a,b,m,s,c)}}return[[-1,a],[1,b]]}; -diff_match_patch.prototype.diff_bisectSplit_=function(a,b,c,d,e){var f=a.substring(0,c),g=b.substring(0,d);a=a.substring(c);b=b.substring(d);f=this.diff_main(f,g,!1,e);e=this.diff_main(a,b,!1,e);return f.concat(e)}; -diff_match_patch.prototype.diff_linesToChars_=function(a,b){function c(a){for(var b="",c=0,f=-1,g=d.length;fd?a=a.substring(c-d):c=a.length?[h,j,n,l,g]:null}if(0>=this.Diff_Timeout)return null; -var d=a.length>b.length?a:b,e=a.length>b.length?b:a;if(4>d.length||2*e.lengthd[4].length?g:d:d:g;var j;a.length>b.length?(g=h[0],d=h[1],e=h[2],j=h[3]):(e=h[0],j=h[1],g=h[2],d=h[3]);h=h[4];return[g,d,e,j,h]}; -diff_match_patch.prototype.diff_cleanupSemantic=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=0,h=0,j=0,i=0;f=e){if(d>=b.length/2||d>=c.length/2)a.splice(f,0,[0,c.substring(0,d)]),a[f-1][1]=b.substring(0,b.length-d),a[f+1][1]=c.substring(d),f++}else if(e>=b.length/2||e>=c.length/2)a.splice(f,0,[0,b.substring(0,e)]),a[f-1][0]=1,a[f-1][1]=c.substring(0,c.length-e),a[f+1][0]=-1,a[f+1][1]=b.substring(e),f++;f++}f++}}; -diff_match_patch.prototype.diff_cleanupSemanticLossless=function(a){function b(a,b){if(!a||!b)return 6;var c=a.charAt(a.length-1),d=b.charAt(0),e=c.match(diff_match_patch.nonAlphaNumericRegex_),f=d.match(diff_match_patch.nonAlphaNumericRegex_),g=e&&c.match(diff_match_patch.whitespaceRegex_),h=f&&d.match(diff_match_patch.whitespaceRegex_),c=g&&c.match(diff_match_patch.linebreakRegex_),d=h&&d.match(diff_match_patch.linebreakRegex_),i=c&&a.match(diff_match_patch.blanklineEndRegex_),j=d&&b.match(diff_match_patch.blanklineStartRegex_); -return i||j?5:c||d?4:e&&!g&&h?3:g||h?2:e||f?1:0}for(var c=1;c=i&&(i=k,g=d,h=e,j=f)}a[c-1][1]!=g&&(g?a[c-1][1]=g:(a.splice(c-1,1),c--),a[c][1]= -h,j?a[c+1][1]=j:(a.splice(c+1,1),c--))}c++}};diff_match_patch.nonAlphaNumericRegex_=/[^a-zA-Z0-9]/;diff_match_patch.whitespaceRegex_=/\s/;diff_match_patch.linebreakRegex_=/[\r\n]/;diff_match_patch.blanklineEndRegex_=/\n\r?\n$/;diff_match_patch.blanklineStartRegex_=/^\r?\n\r?\n/; -diff_match_patch.prototype.diff_cleanupEfficiency=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=!1,h=!1,j=!1,i=!1;fb)break;e=c;f=d}return a.length!=g&&-1===a[g][0]?f:f+(b-e)}; -diff_match_patch.prototype.diff_prettyHtml=function(a){for(var b=[],c=/&/g,d=//g,f=/\n/g,g=0;g");switch(h){case 1:b[g]=''+j+"";break;case -1:b[g]=''+j+"";break;case 0:b[g]=""+j+""}}return b.join("")}; -diff_match_patch.prototype.diff_text1=function(a){for(var b=[],c=0;cthis.Match_MaxBits)throw Error("Pattern too long for this browser.");var e=this.match_alphabet_(b),f=this,g=this.Match_Threshold,h=a.indexOf(b,c);-1!=h&&(g=Math.min(d(0,h),g),h=a.lastIndexOf(b,c+b.length),-1!=h&&(g=Math.min(d(0,h),g)));for(var j=1<=i;p--){var w=e[a.charAt(p-1)];k[p]=0===t?(k[p+1]<<1|1)&w:(k[p+1]<<1|1)&w|((r[p+1]|r[p])<<1|1)|r[p+1];if(k[p]&j&&(w=d(t,p-1),w<=g))if(g=w,h=p-1,h>c)i=Math.max(1,2*c-h);else break}if(d(t+1,c)>g)break;r=k}return h}; -diff_match_patch.prototype.match_alphabet_=function(a){for(var b={},c=0;c=2*this.Patch_Margin&& -e&&(this.patch_addContext_(a,h),c.push(a),a=new diff_match_patch.patch_obj,e=0,h=d,f=g)}1!==i&&(f+=k.length);-1!==i&&(g+=k.length)}e&&(this.patch_addContext_(a,h),c.push(a));return c};diff_match_patch.prototype.patch_deepCopy=function(a){for(var b=[],c=0;cthis.Match_MaxBits){if(j=this.match_main(b,h.substring(0,this.Match_MaxBits),g),-1!=j&&(i=this.match_main(b,h.substring(h.length-this.Match_MaxBits),g+h.length-this.Match_MaxBits),-1==i||j>=i))j=-1}else j=this.match_main(b,h,g); -if(-1==j)e[f]=!1,d-=a[f].length2-a[f].length1;else if(e[f]=!0,d=j-g,g=-1==i?b.substring(j,j+h.length):b.substring(j,i+this.Match_MaxBits),h==g)b=b.substring(0,j)+this.diff_text2(a[f].diffs)+b.substring(j+h.length);else if(g=this.diff_main(h,g,!1),h.length>this.Match_MaxBits&&this.diff_levenshtein(g)/h.length>this.Patch_DeleteThreshold)e[f]=!1;else{this.diff_cleanupSemanticLossless(g);for(var h=0,k,i=0;ie[0][1].length){var f=b-e[0][1].length;e[0][1]=c.substring(e[0][1].length)+e[0][1];d.start1-=f;d.start2-=f;d.length1+=f;d.length2+=f}d=a[a.length-1];e=d.diffs;0==e.length||0!=e[e.length-1][0]?(e.push([0, -c]),d.length1+=b,d.length2+=b):b>e[e.length-1][1].length&&(f=b-e[e.length-1][1].length,e[e.length-1][1]+=c.substring(0,f),d.length1+=f,d.length2+=f);return c}; -diff_match_patch.prototype.patch_splitMax=function(a){for(var b=this.Match_MaxBits,c=0;c2*b?(h.length1+=i.length,e+=i.length,j=!1,h.diffs.push([g,i]),d.diffs.shift()):(i=i.substring(0,b-h.length1-this.Patch_Margin),h.length1+=i.length,e+=i.length,0===g?(h.length2+=i.length,f+=i.length):j=!1,h.diffs.push([g,i]),i==d.diffs[0][1]?d.diffs.shift():d.diffs[0][1]=d.diffs[0][1].substring(i.length))}g=this.diff_text2(h.diffs);g=g.substring(g.length-this.Patch_Margin);i=this.diff_text1(d.diffs).substring(0,this.Patch_Margin);""!==i&& -(h.length1+=i.length,h.length2+=i.length,0!==h.diffs.length&&0===h.diffs[h.diffs.length-1][0]?h.diffs[h.diffs.length-1][1]+=i:h.diffs.push([0,i]));j||a.splice(++c,0,h)}}};diff_match_patch.prototype.patch_toText=function(a){for(var b=[],c=0;c= 2.0.0-beta.1",7:">= 4.0.0"};b.REVISION_CHANGES=o;var p="[object Object]";d.prototype={constructor:d,logger:l["default"],log:l["default"].log,registerHelper:function(a,b){if(f.toString.call(a)===p){if(b)throw new h["default"]("Arg not supported with multiple helpers");f.extend(this.helpers,a)}else this.helpers[a]=b},unregisterHelper:function(a){delete this.helpers[a]},registerPartial:function(a,b){if(f.toString.call(a)===p)f.extend(this.partials,a);else{if("undefined"==typeof b)throw new h["default"]('Attempting to register a partial called "'+a+'" as undefined');this.partials[a]=b}},unregisterPartial:function(a){delete this.partials[a]},registerDecorator:function(a,b){if(f.toString.call(a)===p){if(b)throw new h["default"]("Arg not supported with multiple decorators");f.extend(this.decorators,a)}else this.decorators[a]=b},unregisterDecorator:function(a){delete this.decorators[a]}};var q=l["default"].log;b.log=q,b.createFrame=f.createFrame,b.logger=l["default"]},function(a,b){"use strict";function c(a){return k[a]}function d(a){for(var b=1;bc;c++)if(a[c]===b)return c;return-1}function f(a){if("string"!=typeof a){if(a&&a.toHTML)return a.toHTML();if(null==a)return"";if(!a)return a+"";a=""+a}return m.test(a)?a.replace(l,c):a}function g(a){return a||0===a?p(a)&&0===a.length?!0:!1:!0}function h(a){var b=d({},a);return b._parent=a,b}function i(a,b){return a.path=b,a}function j(a,b){return(a?a+".":"")+b}b.__esModule=!0,b.extend=d,b.indexOf=e,b.escapeExpression=f,b.isEmpty=g,b.createFrame=h,b.blockParams=i,b.appendContextPath=j;var k={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`","=":"="},l=/[&<>"'`=]/g,m=/[&<>"'`=]/,n=Object.prototype.toString;b.toString=n;var o=function(a){return"function"==typeof a};o(/x/)&&(b.isFunction=o=function(a){return"function"==typeof a&&"[object Function]"===n.call(a)}),b.isFunction=o;var p=Array.isArray||function(a){return a&&"object"==typeof a?"[object Array]"===n.call(a):!1};b.isArray=p},function(a,b){"use strict";function c(a,b){var e=b&&b.loc,f=void 0,g=void 0;e&&(f=e.start.line,g=e.start.column,a+=" - "+f+":"+g);for(var h=Error.prototype.constructor.call(this,a),i=0;i0?(c.ids&&(c.ids=[c.name]),a.helpers.each(b,c)):e(this);if(c.data&&c.ids){var g=d.createFrame(c.data);g.contextPath=d.appendContextPath(c.data.contextPath,c.name),c={data:g}}return f(b,c)})},a.exports=b["default"]},function(a,b,c){"use strict";var d=c(1)["default"];b.__esModule=!0;var e=c(5),f=c(6),g=d(f);b["default"]=function(a){a.registerHelper("each",function(a,b){function c(b,c,f){j&&(j.key=b,j.index=c,j.first=0===c,j.last=!!f,k&&(j.contextPath=k+b)),i+=d(a[b],{data:j,blockParams:e.blockParams([a[b],b],[k+b,null])})}if(!b)throw new g["default"]("Must pass iterator to #each");var d=b.fn,f=b.inverse,h=0,i="",j=void 0,k=void 0;if(b.data&&b.ids&&(k=e.appendContextPath(b.data.contextPath,b.ids[0])+"."),e.isFunction(a)&&(a=a.call(this)),b.data&&(j=e.createFrame(b.data)),a&&"object"==typeof a)if(e.isArray(a))for(var l=a.length;l>h;h++)h in a&&c(h,h,h===a.length-1);else{var m=void 0;for(var n in a)a.hasOwnProperty(n)&&(void 0!==m&&c(m,h-1),m=n,h++);void 0!==m&&c(m,h-1,!0)}return 0===h&&(i=f(this)),i})},a.exports=b["default"]},function(a,b,c){"use strict";var d=c(1)["default"];b.__esModule=!0;var e=c(6),f=d(e);b["default"]=function(a){a.registerHelper("helperMissing",function(){if(1!==arguments.length)throw new f["default"]('Missing helper: "'+arguments[arguments.length-1].name+'"')})},a.exports=b["default"]},function(a,b,c){"use strict";b.__esModule=!0;var d=c(5);b["default"]=function(a){a.registerHelper("if",function(a,b){return d.isFunction(a)&&(a=a.call(this)),!b.hash.includeZero&&!a||d.isEmpty(a)?b.inverse(this):b.fn(this)}),a.registerHelper("unless",function(b,c){return a.helpers["if"].call(this,b,{fn:c.inverse,inverse:c.fn,hash:c.hash})})},a.exports=b["default"]},function(a,b){"use strict";b.__esModule=!0,b["default"]=function(a){a.registerHelper("log",function(){for(var b=[void 0],c=arguments[arguments.length-1],d=0;d=0?b:parseInt(a,10)}return a},log:function(a){if(a=e.lookupLevel(a),"undefined"!=typeof console&&e.lookupLevel(e.level)<=a){var b=e.methodMap[a];console[b]||(b="log");for(var c=arguments.length,d=Array(c>1?c-1:0),f=1;c>f;f++)d[f-1]=arguments[f];console[b].apply(console,d)}}};b["default"]=e,a.exports=b["default"]},function(a,b){"use strict";function c(a){this.string=a}b.__esModule=!0,c.prototype.toString=c.prototype.toHTML=function(){return""+this.string},b["default"]=c,a.exports=b["default"]},function(a,b,c){"use strict";function d(a){var b=a&&a[0]||1,c=r.COMPILER_REVISION;if(b!==c){if(c>b){var d=r.REVISION_CHANGES[c],e=r.REVISION_CHANGES[b];throw new q["default"]("Template was precompiled with an older version of Handlebars than the current runtime. Please update your precompiler to a newer version ("+d+") or downgrade your runtime to an older version ("+e+").")}throw new q["default"]("Template was precompiled with a newer version of Handlebars than the current runtime. Please update your runtime to a newer version ("+a[1]+").")}}function e(a,b){function c(c,d,e){e.hash&&(d=o.extend({},d,e.hash),e.ids&&(e.ids[0]=!0)),c=b.VM.resolvePartial.call(this,c,d,e);var f=b.VM.invokePartial.call(this,c,d,e);if(null==f&&b.compile&&(e.partials[e.name]=b.compile(c,a.compilerOptions,b),f=e.partials[e.name](d,e)),null!=f){if(e.indent){for(var g=f.split("\n"),h=0,i=g.length;i>h&&(g[h]||h+1!==i);h++)g[h]=e.indent+g[h];f=g.join("\n")}return f}throw new q["default"]("The partial "+e.name+" could not be compiled when running in runtime-only mode")}function d(b){function c(b){return""+a.main(e,b,e.helpers,e.partials,g,i,h)}var f=arguments.length<=1||void 0===arguments[1]?{}:arguments[1],g=f.data;d._setup(f),!f.partial&&a.useData&&(g=j(b,g));var h=void 0,i=a.useBlockParams?[]:void 0;return a.useDepths&&(h=f.depths?b!==f.depths[0]?[b].concat(f.depths):f.depths:[b]),(c=k(a.main,c,e,f.depths||[],g,i))(b,f)}if(!b)throw new q["default"]("No environment passed to template");if(!a||!a.main)throw new q["default"]("Unknown template object: "+typeof a);a.main.decorator=a.main_d,b.VM.checkRevision(a.compiler);var e={strict:function(a,b){if(!(b in a))throw new q["default"]('"'+b+'" not defined in '+a);return a[b]},lookup:function(a,b){for(var c=a.length,d=0;c>d;d++)if(a[d]&&null!=a[d][b])return a[d][b]},lambda:function(a,b){return"function"==typeof a?a.call(b):a},escapeExpression:o.escapeExpression,invokePartial:c,fn:function(b){var c=a[b];return c.decorator=a[b+"_d"],c},programs:[],program:function(a,b,c,d,e){var g=this.programs[a],h=this.fn(a);return b||e||d||c?g=f(this,a,h,b,c,d,e):g||(g=this.programs[a]=f(this,a,h)),g},data:function(a,b){for(;a&&b--;)a=a._parent;return a},merge:function(a,b){var c=a||b;return a&&b&&a!==b&&(c=o.extend({},b,a)),c},noop:b.VM.noop,compilerInfo:a.compiler};return d.isTop=!0,d._setup=function(c){c.partial?(e.helpers=c.helpers,e.partials=c.partials,e.decorators=c.decorators):(e.helpers=e.merge(c.helpers,b.helpers),a.usePartial&&(e.partials=e.merge(c.partials,b.partials)),(a.usePartial||a.useDecorators)&&(e.decorators=e.merge(c.decorators,b.decorators)))},d._child=function(b,c,d,g){if(a.useBlockParams&&!d)throw new q["default"]("must pass block params");if(a.useDepths&&!g)throw new q["default"]("must pass parent depths");return f(e,b,a[b],c,0,d,g)},d}function f(a,b,c,d,e,f,g){function h(b){var e=arguments.length<=1||void 0===arguments[1]?{}:arguments[1],h=g;return g&&b!==g[0]&&(h=[b].concat(g)),c(a,b,a.helpers,a.partials,e.data||d,f&&[e.blockParams].concat(f),h)}return h=k(c,h,a,g,d,f),h.program=b,h.depth=g?g.length:0,h.blockParams=e||0,h}function g(a,b,c){return a?a.call||c.name||(c.name=a,a=c.partials[a]):a="@partial-block"===c.name?c.data["partial-block"]:c.partials[c.name],a}function h(a,b,c){c.partial=!0,c.ids&&(c.data.contextPath=c.ids[0]||c.data.contextPath);var d=void 0;if(c.fn&&c.fn!==i&&(c.data=r.createFrame(c.data),d=c.data["partial-block"]=c.fn,d.partials&&(c.partials=o.extend({},c.partials,d.partials))),void 0===a&&d&&(a=d),void 0===a)throw new q["default"]("The partial "+c.name+" could not be found");return a instanceof Function?a(b,c):void 0}function i(){return""}function j(a,b){return b&&"root"in b||(b=b?r.createFrame(b):{},b.root=a),b}function k(a,b,c,d,e,f){if(a.decorator){var g={};b=a.decorator(b,g,c,d&&d[0],e,f,d),o.extend(b,g)}return b}var l=c(3)["default"],m=c(1)["default"];b.__esModule=!0,b.checkRevision=d,b.template=e,b.wrapProgram=f,b.resolvePartial=g,b.invokePartial=h,b.noop=i;var n=c(5),o=l(n),p=c(6),q=m(p),r=c(4)},function(a,b){(function(c){"use strict";b.__esModule=!0,b["default"]=function(a){var b="undefined"!=typeof c?c:window,d=b.Handlebars;a.noConflict=function(){return b.Handlebars===a&&(b.Handlebars=d),a}},a.exports=b["default"]}).call(b,function(){return this}())},function(a,b){"use strict";b.__esModule=!0;var c={helpers:{helperExpression:function(a){return"SubExpression"===a.type||("MustacheStatement"===a.type||"BlockStatement"===a.type)&&!!(a.params&&a.params.length||a.hash)},scopedId:function(a){return/^\.|this\b/.test(a.original)},simpleId:function(a){return 1===a.parts.length&&!c.helpers.scopedId(a)&&!a.depth}}};b["default"]=c,a.exports=b["default"]},function(a,b,c){"use strict";function d(a,b){if("Program"===a.type)return a;h["default"].yy=n,n.locInfo=function(a){return new n.SourceLocation(b&&b.srcName,a)};var c=new j["default"](b);return c.accept(h["default"].parse(a))}var e=c(1)["default"],f=c(3)["default"];b.__esModule=!0,b.parse=d;var g=c(23),h=e(g),i=c(24),j=e(i),k=c(26),l=f(k),m=c(5);b.parser=h["default"];var n={};m.extend(n,l)},function(a,b){"use strict";var c=function(){function a(){this.yy={}}var b={trace:function(){},yy:{},symbols_:{error:2,root:3,program:4,EOF:5,program_repetition0:6,statement:7,mustache:8,block:9,rawBlock:10,partial:11,partialBlock:12,content:13,COMMENT:14,CONTENT:15,openRawBlock:16,rawBlock_repetition_plus0:17,END_RAW_BLOCK:18,OPEN_RAW_BLOCK:19,helperName:20,openRawBlock_repetition0:21,openRawBlock_option0:22,CLOSE_RAW_BLOCK:23,openBlock:24,block_option0:25,closeBlock:26,openInverse:27,block_option1:28,OPEN_BLOCK:29,openBlock_repetition0:30,openBlock_option0:31,openBlock_option1:32,CLOSE:33,OPEN_INVERSE:34,openInverse_repetition0:35,openInverse_option0:36,openInverse_option1:37,openInverseChain:38,OPEN_INVERSE_CHAIN:39,openInverseChain_repetition0:40,openInverseChain_option0:41,openInverseChain_option1:42,inverseAndProgram:43,INVERSE:44,inverseChain:45,inverseChain_option0:46,OPEN_ENDBLOCK:47,OPEN:48,mustache_repetition0:49,mustache_option0:50,OPEN_UNESCAPED:51,mustache_repetition1:52,mustache_option1:53,CLOSE_UNESCAPED:54,OPEN_PARTIAL:55,partialName:56,partial_repetition0:57,partial_option0:58,openPartialBlock:59,OPEN_PARTIAL_BLOCK:60,openPartialBlock_repetition0:61,openPartialBlock_option0:62,param:63,sexpr:64,OPEN_SEXPR:65,sexpr_repetition0:66,sexpr_option0:67,CLOSE_SEXPR:68,hash:69,hash_repetition_plus0:70,hashSegment:71,ID:72,EQUALS:73,blockParams:74,OPEN_BLOCK_PARAMS:75,blockParams_repetition_plus0:76,CLOSE_BLOCK_PARAMS:77,path:78,dataName:79,STRING:80,NUMBER:81,BOOLEAN:82,UNDEFINED:83,NULL:84,DATA:85,pathSegments:86,SEP:87,$accept:0,$end:1},terminals_:{2:"error",5:"EOF",14:"COMMENT",15:"CONTENT",18:"END_RAW_BLOCK",19:"OPEN_RAW_BLOCK",23:"CLOSE_RAW_BLOCK",29:"OPEN_BLOCK",33:"CLOSE",34:"OPEN_INVERSE",39:"OPEN_INVERSE_CHAIN",44:"INVERSE",47:"OPEN_ENDBLOCK",48:"OPEN",51:"OPEN_UNESCAPED",54:"CLOSE_UNESCAPED",55:"OPEN_PARTIAL",60:"OPEN_PARTIAL_BLOCK",65:"OPEN_SEXPR",68:"CLOSE_SEXPR",72:"ID",73:"EQUALS",75:"OPEN_BLOCK_PARAMS",77:"CLOSE_BLOCK_PARAMS",80:"STRING",81:"NUMBER",82:"BOOLEAN",83:"UNDEFINED",84:"NULL",85:"DATA",87:"SEP"},productions_:[0,[3,2],[4,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[13,1],[10,3],[16,5],[9,4],[9,4],[24,6],[27,6],[38,6],[43,2],[45,3],[45,1],[26,3],[8,5],[8,5],[11,5],[12,3],[59,5],[63,1],[63,1],[64,5],[69,1],[71,3],[74,3],[20,1],[20,1],[20,1],[20,1],[20,1],[20,1],[20,1],[56,1],[56,1],[79,2],[78,1],[86,3],[86,1],[6,0],[6,2],[17,1],[17,2],[21,0],[21,2],[22,0],[22,1],[25,0],[25,1],[28,0],[28,1],[30,0],[30,2],[31,0],[31,1],[32,0],[32,1],[35,0],[35,2],[36,0],[36,1],[37,0],[37,1],[40,0],[40,2],[41,0],[41,1],[42,0],[42,1],[46,0],[46,1],[49,0],[49,2],[50,0],[50,1],[52,0],[52,2],[53,0],[53,1],[57,0],[57,2],[58,0],[58,1],[61,0],[61,2],[62,0],[62,1],[66,0],[66,2],[67,0],[67,1],[70,1],[70,2],[76,1],[76,2]],performAction:function(a,b,c,d,e,f,g){var h=f.length-1;switch(e){case 1:return f[h-1];case 2:this.$=d.prepareProgram(f[h]);break;case 3:this.$=f[h];break;case 4:this.$=f[h];break;case 5:this.$=f[h];break;case 6:this.$=f[h];break;case 7:this.$=f[h];break;case 8:this.$=f[h];break;case 9:this.$={type:"CommentStatement",value:d.stripComment(f[h]),strip:d.stripFlags(f[h],f[h]),loc:d.locInfo(this._$)};break;case 10:this.$={type:"ContentStatement",original:f[h],value:f[h],loc:d.locInfo(this._$)};break;case 11:this.$=d.prepareRawBlock(f[h-2],f[h-1],f[h],this._$);break;case 12:this.$={path:f[h-3],params:f[h-2],hash:f[h-1]};break;case 13:this.$=d.prepareBlock(f[h-3],f[h-2],f[h-1],f[h],!1,this._$);break;case 14:this.$=d.prepareBlock(f[h-3],f[h-2],f[h-1],f[h],!0,this._$);break;case 15:this.$={open:f[h-5],path:f[h-4],params:f[h-3],hash:f[h-2],blockParams:f[h-1],strip:d.stripFlags(f[h-5],f[h])};break;case 16:this.$={path:f[h-4],params:f[h-3],hash:f[h-2],blockParams:f[h-1],strip:d.stripFlags(f[h-5],f[h])};break;case 17:this.$={path:f[h-4],params:f[h-3],hash:f[h-2],blockParams:f[h-1],strip:d.stripFlags(f[h-5],f[h])};break;case 18:this.$={strip:d.stripFlags(f[h-1],f[h-1]),program:f[h]};break;case 19:var i=d.prepareBlock(f[h-2],f[h-1],f[h],f[h],!1,this._$),j=d.prepareProgram([i],f[h-1].loc);j.chained=!0,this.$={strip:f[h-2].strip,program:j,chain:!0};break;case 20:this.$=f[h];break;case 21:this.$={path:f[h-1],strip:d.stripFlags(f[h-2],f[h])};break;case 22:this.$=d.prepareMustache(f[h-3],f[h-2],f[h-1],f[h-4],d.stripFlags(f[h-4],f[h]),this._$);break;case 23:this.$=d.prepareMustache(f[h-3],f[h-2],f[h-1],f[h-4],d.stripFlags(f[h-4],f[h]),this._$);break;case 24:this.$={type:"PartialStatement",name:f[h-3],params:f[h-2],hash:f[h-1],indent:"",strip:d.stripFlags(f[h-4],f[h]),loc:d.locInfo(this._$)};break;case 25:this.$=d.preparePartialBlock(f[h-2],f[h-1],f[h],this._$);break;case 26:this.$={path:f[h-3],params:f[h-2],hash:f[h-1],strip:d.stripFlags(f[h-4],f[h])};break;case 27:this.$=f[h];break;case 28:this.$=f[h];break;case 29:this.$={type:"SubExpression",path:f[h-3],params:f[h-2],hash:f[h-1],loc:d.locInfo(this._$)};break;case 30:this.$={type:"Hash",pairs:f[h],loc:d.locInfo(this._$)};break;case 31:this.$={type:"HashPair",key:d.id(f[h-2]),value:f[h],loc:d.locInfo(this._$)};break;case 32:this.$=d.id(f[h-1]);break;case 33:this.$=f[h];break;case 34:this.$=f[h];break;case 35:this.$={type:"StringLiteral",value:f[h],original:f[h],loc:d.locInfo(this._$)};break;case 36:this.$={type:"NumberLiteral",value:Number(f[h]),original:Number(f[h]),loc:d.locInfo(this._$)};break;case 37:this.$={type:"BooleanLiteral",value:"true"===f[h],original:"true"===f[h],loc:d.locInfo(this._$)};break;case 38:this.$={type:"UndefinedLiteral",original:void 0,value:void 0,loc:d.locInfo(this._$)};break;case 39:this.$={type:"NullLiteral",original:null,value:null,loc:d.locInfo(this._$)};break;case 40:this.$=f[h];break;case 41:this.$=f[h];break;case 42:this.$=d.preparePath(!0,f[h],this._$);break;case 43:this.$=d.preparePath(!1,f[h],this._$);break;case 44:f[h-2].push({part:d.id(f[h]),original:f[h],separator:f[h-1]}),this.$=f[h-2];break;case 45:this.$=[{part:d.id(f[h]),original:f[h]}];break;case 46:this.$=[];break;case 47:f[h-1].push(f[h]);break;case 48:this.$=[f[h]];break;case 49:f[h-1].push(f[h]);break;case 50:this.$=[];break;case 51:f[h-1].push(f[h]);break;case 58:this.$=[];break;case 59:f[h-1].push(f[h]);break;case 64:this.$=[];break;case 65:f[h-1].push(f[h]);break;case 70:this.$=[];break;case 71:f[h-1].push(f[h]);break;case 78:this.$=[];break;case 79:f[h-1].push(f[h]);break;case 82:this.$=[];break;case 83:f[h-1].push(f[h]);break;case 86:this.$=[];break;case 87:f[h-1].push(f[h]);break;case 90:this.$=[];break;case 91:f[h-1].push(f[h]);break;case 94:this.$=[];break;case 95:f[h-1].push(f[h]);break;case 98:this.$=[f[h]];break;case 99:f[h-1].push(f[h]);break;case 100:this.$=[f[h]];break;case 101:f[h-1].push(f[h])}},table:[{3:1,4:2,5:[2,46],6:3,14:[2,46],15:[2,46],19:[2,46],29:[2,46],34:[2,46],48:[2,46],51:[2,46],55:[2,46],60:[2,46]},{1:[3]},{5:[1,4]},{5:[2,2],7:5,8:6,9:7,10:8,11:9,12:10,13:11,14:[1,12],15:[1,20],16:17,19:[1,23],24:15,27:16,29:[1,21],34:[1,22],39:[2,2],44:[2,2],47:[2,2],48:[1,13],51:[1,14],55:[1,18],59:19,60:[1,24]},{1:[2,1]},{5:[2,47],14:[2,47],15:[2,47],19:[2,47],29:[2,47],34:[2,47],39:[2,47],44:[2,47],47:[2,47],48:[2,47],51:[2,47],55:[2,47],60:[2,47]},{5:[2,3],14:[2,3],15:[2,3],19:[2,3],29:[2,3],34:[2,3],39:[2,3],44:[2,3],47:[2,3],48:[2,3],51:[2,3],55:[2,3],60:[2,3]},{5:[2,4],14:[2,4],15:[2,4],19:[2,4],29:[2,4],34:[2,4],39:[2,4],44:[2,4],47:[2,4],48:[2,4],51:[2,4],55:[2,4],60:[2,4]},{5:[2,5],14:[2,5],15:[2,5],19:[2,5],29:[2,5],34:[2,5],39:[2,5],44:[2,5],47:[2,5],48:[2,5],51:[2,5],55:[2,5],60:[2,5]},{5:[2,6],14:[2,6],15:[2,6],19:[2,6],29:[2,6],34:[2,6],39:[2,6],44:[2,6],47:[2,6],48:[2,6],51:[2,6],55:[2,6],60:[2,6]},{5:[2,7],14:[2,7],15:[2,7],19:[2,7],29:[2,7],34:[2,7],39:[2,7],44:[2,7],47:[2,7],48:[2,7],51:[2,7],55:[2,7],60:[2,7]},{5:[2,8],14:[2,8],15:[2,8],19:[2,8],29:[2,8],34:[2,8],39:[2,8],44:[2,8],47:[2,8],48:[2,8],51:[2,8],55:[2,8],60:[2,8]},{5:[2,9],14:[2,9],15:[2,9],19:[2,9],29:[2,9],34:[2,9],39:[2,9],44:[2,9],47:[2,9],48:[2,9],51:[2,9],55:[2,9],60:[2,9]},{20:25,72:[1,35],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{20:36,72:[1,35],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{4:37,6:3,14:[2,46],15:[2,46],19:[2,46],29:[2,46],34:[2,46],39:[2,46],44:[2,46],47:[2,46],48:[2,46],51:[2,46],55:[2,46],60:[2,46]},{4:38,6:3,14:[2,46],15:[2,46],19:[2,46],29:[2,46],34:[2,46],44:[2,46],47:[2,46],48:[2,46],51:[2,46],55:[2,46],60:[2,46]},{13:40,15:[1,20],17:39},{20:42,56:41,64:43,65:[1,44],72:[1,35],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{4:45,6:3,14:[2,46],15:[2,46],19:[2,46],29:[2,46],34:[2,46],47:[2,46],48:[2,46],51:[2,46],55:[2,46],60:[2,46]},{5:[2,10],14:[2,10],15:[2,10],18:[2,10],19:[2,10],29:[2,10],34:[2,10],39:[2,10],44:[2,10],47:[2,10],48:[2,10],51:[2,10],55:[2,10],60:[2,10]},{20:46,72:[1,35],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{20:47,72:[1,35],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{20:48,72:[1,35],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{20:42,56:49,64:43,65:[1,44],72:[1,35],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{33:[2,78],49:50,65:[2,78],72:[2,78],80:[2,78],81:[2,78],82:[2,78],83:[2,78],84:[2,78],85:[2,78]},{23:[2,33],33:[2,33],54:[2,33],65:[2,33],68:[2,33],72:[2,33],75:[2,33],80:[2,33],81:[2,33],82:[2,33],83:[2,33],84:[2,33],85:[2,33]},{23:[2,34],33:[2,34],54:[2,34],65:[2,34],68:[2,34],72:[2,34],75:[2,34],80:[2,34],81:[2,34],82:[2,34],83:[2,34],84:[2,34],85:[2,34]},{23:[2,35],33:[2,35],54:[2,35],65:[2,35],68:[2,35],72:[2,35],75:[2,35],80:[2,35],81:[2,35],82:[2,35],83:[2,35],84:[2,35],85:[2,35]},{23:[2,36],33:[2,36],54:[2,36],65:[2,36],68:[2,36],72:[2,36],75:[2,36],80:[2,36],81:[2,36],82:[2,36],83:[2,36],84:[2,36],85:[2,36]},{23:[2,37],33:[2,37],54:[2,37],65:[2,37],68:[2,37],72:[2,37],75:[2,37],80:[2,37],81:[2,37],82:[2,37],83:[2,37],84:[2,37],85:[2,37]},{23:[2,38],33:[2,38],54:[2,38],65:[2,38],68:[2,38],72:[2,38],75:[2,38],80:[2,38],81:[2,38],82:[2,38],83:[2,38],84:[2,38],85:[2,38]},{23:[2,39],33:[2,39],54:[2,39],65:[2,39],68:[2,39],72:[2,39],75:[2,39],80:[2,39],81:[2,39],82:[2,39],83:[2,39],84:[2,39],85:[2,39]},{23:[2,43],33:[2,43],54:[2,43],65:[2,43],68:[2,43],72:[2,43],75:[2,43],80:[2,43],81:[2,43],82:[2,43],83:[2,43],84:[2,43],85:[2,43],87:[1,51]},{72:[1,35],86:52},{23:[2,45],33:[2,45],54:[2,45],65:[2,45],68:[2,45],72:[2,45],75:[2,45],80:[2,45],81:[2,45],82:[2,45],83:[2,45],84:[2,45],85:[2,45],87:[2,45]},{52:53,54:[2,82],65:[2,82],72:[2,82],80:[2,82],81:[2,82],82:[2,82],83:[2,82],84:[2,82],85:[2,82]},{25:54,38:56,39:[1,58],43:57,44:[1,59],45:55,47:[2,54]},{28:60,43:61,44:[1,59],47:[2,56]},{13:63,15:[1,20],18:[1,62]},{15:[2,48],18:[2,48]},{33:[2,86],57:64,65:[2,86],72:[2,86],80:[2,86],81:[2,86],82:[2,86],83:[2,86],84:[2,86],85:[2,86]},{33:[2,40],65:[2,40],72:[2,40],80:[2,40],81:[2,40],82:[2,40],83:[2,40],84:[2,40],85:[2,40]},{33:[2,41],65:[2,41],72:[2,41],80:[2,41],81:[2,41],82:[2,41],83:[2,41],84:[2,41],85:[2,41]},{20:65,72:[1,35],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{26:66,47:[1,67]},{30:68,33:[2,58],65:[2,58],72:[2,58],75:[2,58],80:[2,58],81:[2,58],82:[2,58],83:[2,58],84:[2,58],85:[2,58]},{33:[2,64],35:69,65:[2,64],72:[2,64],75:[2,64],80:[2,64],81:[2,64],82:[2,64],83:[2,64],84:[2,64],85:[2,64]},{21:70,23:[2,50],65:[2,50],72:[2,50],80:[2,50],81:[2,50],82:[2,50],83:[2,50],84:[2,50],85:[2,50]},{33:[2,90],61:71,65:[2,90],72:[2,90],80:[2,90],81:[2,90],82:[2,90],83:[2,90],84:[2,90],85:[2,90]},{20:75,33:[2,80],50:72,63:73,64:76,65:[1,44],69:74,70:77,71:78,72:[1,79],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{72:[1,80]},{23:[2,42],33:[2,42],54:[2,42],65:[2,42],68:[2,42],72:[2,42],75:[2,42],80:[2,42],81:[2,42],82:[2,42],83:[2,42],84:[2,42],85:[2,42],87:[1,51]},{20:75,53:81,54:[2,84],63:82,64:76,65:[1,44],69:83,70:77,71:78,72:[1,79],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{26:84,47:[1,67]},{47:[2,55]},{4:85,6:3,14:[2,46],15:[2,46],19:[2,46],29:[2,46],34:[2,46],39:[2,46],44:[2,46],47:[2,46],48:[2,46],51:[2,46],55:[2,46],60:[2,46]},{47:[2,20]},{20:86,72:[1,35],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{4:87,6:3,14:[2,46],15:[2,46],19:[2,46],29:[2,46],34:[2,46],47:[2,46],48:[2,46],51:[2,46],55:[2,46],60:[2,46]},{26:88,47:[1,67]},{47:[2,57]},{5:[2,11],14:[2,11],15:[2,11],19:[2,11],29:[2,11],34:[2,11],39:[2,11],44:[2,11],47:[2,11],48:[2,11],51:[2,11],55:[2,11],60:[2,11]},{15:[2,49],18:[2,49]},{20:75,33:[2,88],58:89,63:90,64:76,65:[1,44],69:91,70:77,71:78,72:[1,79],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{65:[2,94],66:92,68:[2,94],72:[2,94],80:[2,94],81:[2,94],82:[2,94],83:[2,94],84:[2,94],85:[2,94]},{5:[2,25],14:[2,25],15:[2,25],19:[2,25],29:[2,25],34:[2,25],39:[2,25],44:[2,25],47:[2,25],48:[2,25],51:[2,25],55:[2,25],60:[2,25]},{20:93,72:[1,35],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{20:75,31:94,33:[2,60],63:95,64:76,65:[1,44],69:96,70:77,71:78,72:[1,79],75:[2,60],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{20:75,33:[2,66],36:97,63:98,64:76,65:[1,44],69:99,70:77,71:78,72:[1,79],75:[2,66],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{20:75,22:100,23:[2,52],63:101,64:76,65:[1,44],69:102,70:77,71:78,72:[1,79],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{20:75,33:[2,92],62:103,63:104,64:76,65:[1,44],69:105,70:77,71:78,72:[1,79],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{33:[1,106]},{33:[2,79],65:[2,79],72:[2,79],80:[2,79],81:[2,79],82:[2,79],83:[2,79],84:[2,79],85:[2,79]},{33:[2,81]},{23:[2,27],33:[2,27],54:[2,27],65:[2,27],68:[2,27],72:[2,27],75:[2,27],80:[2,27],81:[2,27],82:[2,27],83:[2,27],84:[2,27],85:[2,27]},{23:[2,28],33:[2,28],54:[2,28],65:[2,28],68:[2,28],72:[2,28],75:[2,28],80:[2,28],81:[2,28],82:[2,28],83:[2,28],84:[2,28],85:[2,28]},{23:[2,30],33:[2,30],54:[2,30],68:[2,30],71:107,72:[1,108],75:[2,30]},{23:[2,98],33:[2,98],54:[2,98],68:[2,98],72:[2,98],75:[2,98]},{23:[2,45],33:[2,45],54:[2,45],65:[2,45],68:[2,45],72:[2,45],73:[1,109],75:[2,45],80:[2,45],81:[2,45],82:[2,45],83:[2,45],84:[2,45],85:[2,45],87:[2,45]},{23:[2,44],33:[2,44],54:[2,44],65:[2,44],68:[2,44],72:[2,44],75:[2,44],80:[2,44],81:[2,44],82:[2,44],83:[2,44],84:[2,44],85:[2,44],87:[2,44]},{54:[1,110]},{54:[2,83],65:[2,83],72:[2,83],80:[2,83],81:[2,83],82:[2,83],83:[2,83],84:[2,83],85:[2,83]},{54:[2,85]},{5:[2,13],14:[2,13],15:[2,13],19:[2,13],29:[2,13],34:[2,13],39:[2,13],44:[2,13],47:[2,13],48:[2,13],51:[2,13],55:[2,13],60:[2,13]},{38:56,39:[1,58],43:57,44:[1,59],45:112,46:111,47:[2,76]},{33:[2,70],40:113,65:[2,70],72:[2,70],75:[2,70],80:[2,70],81:[2,70],82:[2,70],83:[2,70],84:[2,70],85:[2,70]},{47:[2,18]},{5:[2,14],14:[2,14],15:[2,14],19:[2,14],29:[2,14],34:[2,14],39:[2,14],44:[2,14],47:[2,14],48:[2,14],51:[2,14],55:[2,14],60:[2,14]},{33:[1,114]},{33:[2,87],65:[2,87],72:[2,87],80:[2,87],81:[2,87],82:[2,87],83:[2,87],84:[2,87],85:[2,87]},{33:[2,89]},{20:75,63:116,64:76,65:[1,44],67:115,68:[2,96],69:117,70:77,71:78,72:[1,79],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{33:[1,118]},{32:119,33:[2,62],74:120,75:[1,121]},{33:[2,59],65:[2,59],72:[2,59],75:[2,59],80:[2,59],81:[2,59],82:[2,59],83:[2,59],84:[2,59],85:[2,59]},{33:[2,61],75:[2,61]},{33:[2,68],37:122,74:123,75:[1,121]},{33:[2,65],65:[2,65],72:[2,65],75:[2,65],80:[2,65],81:[2,65],82:[2,65],83:[2,65],84:[2,65],85:[2,65]},{33:[2,67],75:[2,67]},{23:[1,124]},{23:[2,51],65:[2,51],72:[2,51],80:[2,51],81:[2,51],82:[2,51],83:[2,51],84:[2,51],85:[2,51]},{23:[2,53]},{33:[1,125]},{33:[2,91],65:[2,91],72:[2,91],80:[2,91],81:[2,91],82:[2,91],83:[2,91],84:[2,91],85:[2,91]},{33:[2,93]},{5:[2,22],14:[2,22],15:[2,22],19:[2,22],29:[2,22],34:[2,22],39:[2,22],44:[2,22],47:[2,22],48:[2,22],51:[2,22],55:[2,22],60:[2,22]},{23:[2,99],33:[2,99],54:[2,99],68:[2,99],72:[2,99],75:[2,99]},{73:[1,109]},{20:75,63:126,64:76,65:[1,44],72:[1,35],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{5:[2,23],14:[2,23],15:[2,23],19:[2,23],29:[2,23],34:[2,23],39:[2,23],44:[2,23],47:[2,23],48:[2,23],51:[2,23],55:[2,23],60:[2,23]},{47:[2,19]},{47:[2,77]},{20:75,33:[2,72],41:127,63:128,64:76,65:[1,44],69:129,70:77,71:78,72:[1,79],75:[2,72],78:26,79:27,80:[1,28],81:[1,29],82:[1,30],83:[1,31],84:[1,32],85:[1,34],86:33},{5:[2,24],14:[2,24],15:[2,24],19:[2,24],29:[2,24],34:[2,24],39:[2,24],44:[2,24],47:[2,24],48:[2,24],51:[2,24],55:[2,24],60:[2,24]},{68:[1,130]},{65:[2,95],68:[2,95],72:[2,95],80:[2,95],81:[2,95],82:[2,95],83:[2,95],84:[2,95],85:[2,95]},{68:[2,97]},{5:[2,21],14:[2,21],15:[2,21],19:[2,21],29:[2,21],34:[2,21],39:[2,21],44:[2,21],47:[2,21],48:[2,21],51:[2,21],55:[2,21],60:[2,21]},{33:[1,131]},{33:[2,63]},{72:[1,133],76:132},{33:[1,134]},{33:[2,69]},{15:[2,12]},{14:[2,26],15:[2,26],19:[2,26],29:[2,26],34:[2,26],47:[2,26],48:[2,26],51:[2,26],55:[2,26],60:[2,26]},{23:[2,31],33:[2,31],54:[2,31],68:[2,31],72:[2,31],75:[2,31]},{33:[2,74],42:135,74:136,75:[1,121]},{33:[2,71],65:[2,71],72:[2,71],75:[2,71],80:[2,71],81:[2,71],82:[2,71],83:[2,71],84:[2,71],85:[2,71]},{33:[2,73],75:[2,73]},{23:[2,29],33:[2,29],54:[2,29],65:[2,29],68:[2,29],72:[2,29],75:[2,29],80:[2,29],81:[2,29],82:[2,29],83:[2,29],84:[2,29],85:[2,29]},{14:[2,15],15:[2,15],19:[2,15],29:[2,15],34:[2,15],39:[2,15],44:[2,15],47:[2,15],48:[2,15],51:[2,15],55:[2,15],60:[2,15]},{72:[1,138],77:[1,137]},{72:[2,100],77:[2,100]},{14:[2,16],15:[2,16],19:[2,16],29:[2,16],34:[2,16],44:[2,16],47:[2,16], -48:[2,16],51:[2,16],55:[2,16],60:[2,16]},{33:[1,139]},{33:[2,75]},{33:[2,32]},{72:[2,101],77:[2,101]},{14:[2,17],15:[2,17],19:[2,17],29:[2,17],34:[2,17],39:[2,17],44:[2,17],47:[2,17],48:[2,17],51:[2,17],55:[2,17],60:[2,17]}],defaultActions:{4:[2,1],55:[2,55],57:[2,20],61:[2,57],74:[2,81],83:[2,85],87:[2,18],91:[2,89],102:[2,53],105:[2,93],111:[2,19],112:[2,77],117:[2,97],120:[2,63],123:[2,69],124:[2,12],136:[2,75],137:[2,32]},parseError:function(a,b){throw new Error(a)},parse:function(a){function b(){var a;return a=c.lexer.lex()||1,"number"!=typeof a&&(a=c.symbols_[a]||a),a}var c=this,d=[0],e=[null],f=[],g=this.table,h="",i=0,j=0,k=0;this.lexer.setInput(a),this.lexer.yy=this.yy,this.yy.lexer=this.lexer,this.yy.parser=this,"undefined"==typeof this.lexer.yylloc&&(this.lexer.yylloc={});var l=this.lexer.yylloc;f.push(l);var m=this.lexer.options&&this.lexer.options.ranges;"function"==typeof this.yy.parseError&&(this.parseError=this.yy.parseError);for(var n,o,p,q,r,s,t,u,v,w={};;){if(p=d[d.length-1],this.defaultActions[p]?q=this.defaultActions[p]:((null===n||"undefined"==typeof n)&&(n=b()),q=g[p]&&g[p][n]),"undefined"==typeof q||!q.length||!q[0]){var x="";if(!k){v=[];for(s in g[p])this.terminals_[s]&&s>2&&v.push("'"+this.terminals_[s]+"'");x=this.lexer.showPosition?"Parse error on line "+(i+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+v.join(", ")+", got '"+(this.terminals_[n]||n)+"'":"Parse error on line "+(i+1)+": Unexpected "+(1==n?"end of input":"'"+(this.terminals_[n]||n)+"'"),this.parseError(x,{text:this.lexer.match,token:this.terminals_[n]||n,line:this.lexer.yylineno,loc:l,expected:v})}}if(q[0]instanceof Array&&q.length>1)throw new Error("Parse Error: multiple actions possible at state: "+p+", token: "+n);switch(q[0]){case 1:d.push(n),e.push(this.lexer.yytext),f.push(this.lexer.yylloc),d.push(q[1]),n=null,o?(n=o,o=null):(j=this.lexer.yyleng,h=this.lexer.yytext,i=this.lexer.yylineno,l=this.lexer.yylloc,k>0&&k--);break;case 2:if(t=this.productions_[q[1]][1],w.$=e[e.length-t],w._$={first_line:f[f.length-(t||1)].first_line,last_line:f[f.length-1].last_line,first_column:f[f.length-(t||1)].first_column,last_column:f[f.length-1].last_column},m&&(w._$.range=[f[f.length-(t||1)].range[0],f[f.length-1].range[1]]),r=this.performAction.call(w,h,j,i,this.yy,q[1],e,f),"undefined"!=typeof r)return r;t&&(d=d.slice(0,-1*t*2),e=e.slice(0,-1*t),f=f.slice(0,-1*t)),d.push(this.productions_[q[1]][0]),e.push(w.$),f.push(w._$),u=g[d[d.length-2]][d[d.length-1]],d.push(u);break;case 3:return!0}}return!0}},c=function(){var a={EOF:1,parseError:function(a,b){if(!this.yy.parser)throw new Error(a);this.yy.parser.parseError(a,b)},setInput:function(a){return this._input=a,this._more=this._less=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var a=this._input[0];this.yytext+=a,this.yyleng++,this.offset++,this.match+=a,this.matched+=a;var b=a.match(/(?:\r\n?|\n).*/g);return b?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),a},unput:function(a){var b=a.length,c=a.split(/(?:\r\n?|\n)/g);this._input=a+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-b-1),this.offset-=b;var d=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),c.length-1&&(this.yylineno-=c.length-1);var e=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:c?(c.length===d.length?this.yylloc.first_column:0)+d[d.length-c.length].length-c[0].length:this.yylloc.first_column-b},this.options.ranges&&(this.yylloc.range=[e[0],e[0]+this.yyleng-b]),this},more:function(){return this._more=!0,this},less:function(a){this.unput(this.match.slice(a))},pastInput:function(){var a=this.matched.substr(0,this.matched.length-this.match.length);return(a.length>20?"...":"")+a.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var a=this.match;return a.length<20&&(a+=this._input.substr(0,20-a.length)),(a.substr(0,20)+(a.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var a=this.pastInput(),b=new Array(a.length+1).join("-");return a+this.upcomingInput()+"\n"+b+"^"},next:function(){if(this.done)return this.EOF;this._input||(this.done=!0);var a,b,c,d,e;this._more||(this.yytext="",this.match="");for(var f=this._currentRules(),g=0;gb[0].length)||(b=c,d=g,this.options.flex));g++);return b?(e=b[0].match(/(?:\r\n?|\n).*/g),e&&(this.yylineno+=e.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:e?e[e.length-1].length-e[e.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+b[0].length},this.yytext+=b[0],this.match+=b[0],this.matches=b,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._input=this._input.slice(b[0].length),this.matched+=b[0],a=this.performAction.call(this,this.yy,this,f[d],this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),a?a:void 0):""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var a=this.next();return"undefined"!=typeof a?a:this.lex()},begin:function(a){this.conditionStack.push(a)},popState:function(){return this.conditionStack.pop()},_currentRules:function(){return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules},topState:function(){return this.conditionStack[this.conditionStack.length-2]},pushState:function(a){this.begin(a)}};return a.options={},a.performAction=function(a,b,c,d){function e(a,c){return b.yytext=b.yytext.substr(a,b.yyleng-c)}switch(c){case 0:if("\\\\"===b.yytext.slice(-2)?(e(0,1),this.begin("mu")):"\\"===b.yytext.slice(-1)?(e(0,1),this.begin("emu")):this.begin("mu"),b.yytext)return 15;break;case 1:return 15;case 2:return this.popState(),15;case 3:return this.begin("raw"),15;case 4:return this.popState(),"raw"===this.conditionStack[this.conditionStack.length-1]?15:(b.yytext=b.yytext.substr(5,b.yyleng-9),"END_RAW_BLOCK");case 5:return 15;case 6:return this.popState(),14;case 7:return 65;case 8:return 68;case 9:return 19;case 10:return this.popState(),this.begin("raw"),23;case 11:return 55;case 12:return 60;case 13:return 29;case 14:return 47;case 15:return this.popState(),44;case 16:return this.popState(),44;case 17:return 34;case 18:return 39;case 19:return 51;case 20:return 48;case 21:this.unput(b.yytext),this.popState(),this.begin("com");break;case 22:return this.popState(),14;case 23:return 48;case 24:return 73;case 25:return 72;case 26:return 72;case 27:return 87;case 28:break;case 29:return this.popState(),54;case 30:return this.popState(),33;case 31:return b.yytext=e(1,2).replace(/\\"/g,'"'),80;case 32:return b.yytext=e(1,2).replace(/\\'/g,"'"),80;case 33:return 85;case 34:return 82;case 35:return 82;case 36:return 83;case 37:return 84;case 38:return 81;case 39:return 75;case 40:return 77;case 41:return 72;case 42:return b.yytext=b.yytext.replace(/\\([\\\]])/g,"$1"),72;case 43:return"INVALID";case 44:return 5}},a.rules=[/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|\\\{\{|\\\\\{\{|$)))/,/^(?:\{\{\{\{(?=[^\/]))/,/^(?:\{\{\{\{\/[^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=[=}\s\/.])\}\}\}\})/,/^(?:[^\x00]*?(?=(\{\{\{\{)))/,/^(?:[\s\S]*?--(~)?\}\})/,/^(?:\()/,/^(?:\))/,/^(?:\{\{\{\{)/,/^(?:\}\}\}\})/,/^(?:\{\{(~)?>)/,/^(?:\{\{(~)?#>)/,/^(?:\{\{(~)?#\*?)/,/^(?:\{\{(~)?\/)/,/^(?:\{\{(~)?\^\s*(~)?\}\})/,/^(?:\{\{(~)?\s*else\s*(~)?\}\})/,/^(?:\{\{(~)?\^)/,/^(?:\{\{(~)?\s*else\b)/,/^(?:\{\{(~)?\{)/,/^(?:\{\{(~)?&)/,/^(?:\{\{(~)?!--)/,/^(?:\{\{(~)?![\s\S]*?\}\})/,/^(?:\{\{(~)?\*?)/,/^(?:=)/,/^(?:\.\.)/,/^(?:\.(?=([=~}\s\/.)|])))/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}(~)?\}\})/,/^(?:(~)?\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@)/,/^(?:true(?=([~}\s)])))/,/^(?:false(?=([~}\s)])))/,/^(?:undefined(?=([~}\s)])))/,/^(?:null(?=([~}\s)])))/,/^(?:-?[0-9]+(?:\.[0-9]+)?(?=([~}\s)])))/,/^(?:as\s+\|)/,/^(?:\|)/,/^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.)|]))))/,/^(?:\[(\\\]|[^\]])*\])/,/^(?:.)/,/^(?:$)/],a.conditions={mu:{rules:[7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44],inclusive:!1},emu:{rules:[2],inclusive:!1},com:{rules:[6],inclusive:!1},raw:{rules:[3,4,5],inclusive:!1},INITIAL:{rules:[0,1,44],inclusive:!0}},a}();return b.lexer=c,a.prototype=b,b.Parser=a,new a}();b.__esModule=!0,b["default"]=c},function(a,b,c){"use strict";function d(){var a=arguments.length<=0||void 0===arguments[0]?{}:arguments[0];this.options=a}function e(a,b,c){void 0===b&&(b=a.length);var d=a[b-1],e=a[b-2];return d?"ContentStatement"===d.type?(e||!c?/\r?\n\s*?$/:/(^|\r?\n)\s*?$/).test(d.original):void 0:c}function f(a,b,c){void 0===b&&(b=-1);var d=a[b+1],e=a[b+2];return d?"ContentStatement"===d.type?(e||!c?/^\s*?\r?\n/:/^\s*?(\r?\n|$)/).test(d.original):void 0:c}function g(a,b,c){var d=a[null==b?0:b+1];if(d&&"ContentStatement"===d.type&&(c||!d.rightStripped)){var e=d.value;d.value=d.value.replace(c?/^\s+/:/^[ \t]*\r?\n?/,""),d.rightStripped=d.value!==e}}function h(a,b,c){var d=a[null==b?a.length-1:b-1];if(d&&"ContentStatement"===d.type&&(c||!d.leftStripped)){var e=d.value;return d.value=d.value.replace(c?/\s+$/:/[ \t]+$/,""),d.leftStripped=d.value!==e,d.leftStripped}}var i=c(1)["default"];b.__esModule=!0;var j=c(25),k=i(j);d.prototype=new k["default"],d.prototype.Program=function(a){var b=!this.options.ignoreStandalone,c=!this.isRootSeen;this.isRootSeen=!0;for(var d=a.body,i=0,j=d.length;j>i;i++){var k=d[i],l=this.accept(k);if(l){var m=e(d,i,c),n=f(d,i,c),o=l.openStandalone&&m,p=l.closeStandalone&&n,q=l.inlineStandalone&&m&&n;l.close&&g(d,i,!0),l.open&&h(d,i,!0),b&&q&&(g(d,i),h(d,i)&&"PartialStatement"===k.type&&(k.indent=/([ \t]+$)/.exec(d[i-1].original)[1])),b&&o&&(g((k.program||k.inverse).body),h(d,i)),b&&p&&(g(d,i),h((k.inverse||k.program).body))}}return a},d.prototype.BlockStatement=d.prototype.DecoratorBlock=d.prototype.PartialBlockStatement=function(a){this.accept(a.program),this.accept(a.inverse);var b=a.program||a.inverse,c=a.program&&a.inverse,d=c,i=c;if(c&&c.chained)for(d=c.body[0].program;i.chained;)i=i.body[i.body.length-1].program;var j={open:a.openStrip.open,close:a.closeStrip.close,openStandalone:f(b.body),closeStandalone:e((d||b).body)};if(a.openStrip.close&&g(b.body,null,!0),c){var k=a.inverseStrip;k.open&&h(b.body,null,!0),k.close&&g(d.body,null,!0),a.closeStrip.open&&h(i.body,null,!0),!this.options.ignoreStandalone&&e(b.body)&&f(d.body)&&(h(b.body),g(d.body))}else a.closeStrip.open&&h(b.body,null,!0);return j},d.prototype.Decorator=d.prototype.MustacheStatement=function(a){return a.strip},d.prototype.PartialStatement=d.prototype.CommentStatement=function(a){var b=a.strip||{};return{inlineStandalone:!0,open:b.open,close:b.close}},b["default"]=d,a.exports=b["default"]},function(a,b,c){"use strict";function d(){this.parents=[]}function e(a){this.acceptRequired(a,"path"),this.acceptArray(a.params),this.acceptKey(a,"hash")}function f(a){e.call(this,a),this.acceptKey(a,"program"),this.acceptKey(a,"inverse")}function g(a){this.acceptRequired(a,"name"),this.acceptArray(a.params),this.acceptKey(a,"hash")}var h=c(1)["default"];b.__esModule=!0;var i=c(6),j=h(i);d.prototype={constructor:d,mutating:!1,acceptKey:function(a,b){var c=this.accept(a[b]);if(this.mutating){if(c&&!d.prototype[c.type])throw new j["default"]('Unexpected node type "'+c.type+'" found when accepting '+b+" on "+a.type);a[b]=c}},acceptRequired:function(a,b){if(this.acceptKey(a,b),!a[b])throw new j["default"](a.type+" requires "+b)},acceptArray:function(a){for(var b=0,c=a.length;c>b;b++)this.acceptKey(a,b),a[b]||(a.splice(b,1),b--,c--)},accept:function(a){if(a){if(!this[a.type])throw new j["default"]("Unknown type: "+a.type,a);this.current&&this.parents.unshift(this.current),this.current=a;var b=this[a.type](a);return this.current=this.parents.shift(),!this.mutating||b?b:b!==!1?a:void 0}},Program:function(a){this.acceptArray(a.body)},MustacheStatement:e,Decorator:e,BlockStatement:f,DecoratorBlock:f,PartialStatement:g,PartialBlockStatement:function(a){g.call(this,a),this.acceptKey(a,"program")},ContentStatement:function(){},CommentStatement:function(){},SubExpression:e,PathExpression:function(){},StringLiteral:function(){},NumberLiteral:function(){},BooleanLiteral:function(){},UndefinedLiteral:function(){},NullLiteral:function(){},Hash:function(a){this.acceptArray(a.pairs)},HashPair:function(a){this.acceptRequired(a,"value")}},b["default"]=d,a.exports=b["default"]},function(a,b,c){"use strict";function d(a,b){if(b=b.path?b.path.original:b,a.path.original!==b){var c={loc:a.path.loc};throw new q["default"](a.path.original+" doesn't match "+b,c)}}function e(a,b){this.source=a,this.start={line:b.first_line,column:b.first_column},this.end={line:b.last_line,column:b.last_column}}function f(a){return/^\[.*\]$/.test(a)?a.substr(1,a.length-2):a}function g(a,b){return{open:"~"===a.charAt(2),close:"~"===b.charAt(b.length-3)}}function h(a){return a.replace(/^\{\{~?\!-?-?/,"").replace(/-?-?~?\}\}$/,"")}function i(a,b,c){c=this.locInfo(c);for(var d=a?"@":"",e=[],f=0,g="",h=0,i=b.length;i>h;h++){var j=b[h].part,k=b[h].original!==j;if(d+=(b[h].separator||"")+j,k||".."!==j&&"."!==j&&"this"!==j)e.push(j);else{if(e.length>0)throw new q["default"]("Invalid path: "+d,{loc:c});".."===j&&(f++,g+="../")}}return{type:"PathExpression",data:a,depth:f,parts:e,original:d,loc:c}}function j(a,b,c,d,e,f){var g=d.charAt(3)||d.charAt(2),h="{"!==g&&"&"!==g,i=/\*/.test(d);return{type:i?"Decorator":"MustacheStatement",path:a,params:b,hash:c,escaped:h,strip:e,loc:this.locInfo(f)}}function k(a,b,c,e){d(a,c),e=this.locInfo(e);var f={type:"Program",body:b,strip:{},loc:e};return{type:"BlockStatement",path:a.path,params:a.params,hash:a.hash,program:f,openStrip:{},inverseStrip:{},closeStrip:{},loc:e}}function l(a,b,c,e,f,g){e&&e.path&&d(a,e);var h=/\*/.test(a.open);b.blockParams=a.blockParams;var i=void 0,j=void 0;if(c){if(h)throw new q["default"]("Unexpected inverse block on decorator",c);c.chain&&(c.program.body[0].closeStrip=e.strip),j=c.strip,i=c.program}return f&&(f=i,i=b,b=f),{type:h?"DecoratorBlock":"BlockStatement",path:a.path,params:a.params,hash:a.hash,program:b,inverse:i,openStrip:a.strip,inverseStrip:j,closeStrip:e&&e.strip,loc:this.locInfo(g)}}function m(a,b){if(!b&&a.length){var c=a[0].loc,d=a[a.length-1].loc;c&&d&&(b={source:c.source,start:{line:c.start.line,column:c.start.column},end:{line:d.end.line,column:d.end.column}})}return{type:"Program",body:a,strip:{},loc:b}}function n(a,b,c,e){return d(a,c),{type:"PartialBlockStatement",name:a.path,params:a.params,hash:a.hash,program:b,openStrip:a.strip,closeStrip:c&&c.strip,loc:this.locInfo(e)}}var o=c(1)["default"];b.__esModule=!0,b.SourceLocation=e,b.id=f,b.stripFlags=g,b.stripComment=h,b.preparePath=i,b.prepareMustache=j,b.prepareRawBlock=k,b.prepareBlock=l,b.prepareProgram=m,b.preparePartialBlock=n;var p=c(6),q=o(p)},function(a,b,c){"use strict";function d(){}function e(a,b,c){if(null==a||"string"!=typeof a&&"Program"!==a.type)throw new k["default"]("You must pass a string or Handlebars AST to Handlebars.precompile. You passed "+a);b=b||{},"data"in b||(b.data=!0),b.compat&&(b.useDepths=!0);var d=c.parse(a,b),e=(new c.Compiler).compile(d,b);return(new c.JavaScriptCompiler).compile(e,b)}function f(a,b,c){function d(){var d=c.parse(a,b),e=(new c.Compiler).compile(d,b),f=(new c.JavaScriptCompiler).compile(e,b,void 0,!0);return c.template(f)}function e(a,b){return f||(f=d()),f.call(this,a,b)}if(void 0===b&&(b={}),null==a||"string"!=typeof a&&"Program"!==a.type)throw new k["default"]("You must pass a string or Handlebars AST to Handlebars.compile. You passed "+a);"data"in b||(b.data=!0),b.compat&&(b.useDepths=!0);var f=void 0;return e._setup=function(a){return f||(f=d()),f._setup(a)},e._child=function(a,b,c,e){return f||(f=d()),f._child(a,b,c,e)},e}function g(a,b){if(a===b)return!0;if(l.isArray(a)&&l.isArray(b)&&a.length===b.length){for(var c=0;cc;c++){var d=this.opcodes[c],e=a.opcodes[c];if(d.opcode!==e.opcode||!g(d.args,e.args))return!1}b=this.children.length;for(var c=0;b>c;c++)if(!this.children[c].equals(a.children[c]))return!1;return!0},guid:0,compile:function(a,b){this.sourceNode=[],this.opcodes=[],this.children=[],this.options=b,this.stringParams=b.stringParams,this.trackIds=b.trackIds,b.blockParams=b.blockParams||[];var c=b.knownHelpers;if(b.knownHelpers={helperMissing:!0,blockHelperMissing:!0,each:!0,"if":!0,unless:!0,"with":!0,log:!0,lookup:!0},c)for(var d in c)d in c&&(b.knownHelpers[d]=c[d]);return this.accept(a)},compileProgram:function(a){var b=new this.compiler,c=b.compile(a,this.options),d=this.guid++;return this.usePartial=this.usePartial||c.usePartial,this.children[d]=c,this.useDepths=this.useDepths||c.useDepths,d},accept:function(a){if(!this[a.type])throw new k["default"]("Unknown type: "+a.type,a);this.sourceNode.unshift(a);var b=this[a.type](a);return this.sourceNode.shift(),b},Program:function(a){this.options.blockParams.unshift(a.blockParams);for(var b=a.body,c=b.length,d=0;c>d;d++)this.accept(b[d]);return this.options.blockParams.shift(),this.isSimple=1===c,this.blockParams=a.blockParams?a.blockParams.length:0,this},BlockStatement:function(a){h(a);var b=a.program,c=a.inverse;b=b&&this.compileProgram(b),c=c&&this.compileProgram(c);var d=this.classifySexpr(a);"helper"===d?this.helperSexpr(a,b,c):"simple"===d?(this.simpleSexpr(a),this.opcode("pushProgram",b),this.opcode("pushProgram",c),this.opcode("emptyHash"),this.opcode("blockValue",a.path.original)):(this.ambiguousSexpr(a,b,c),this.opcode("pushProgram",b),this.opcode("pushProgram",c),this.opcode("emptyHash"),this.opcode("ambiguousBlockValue")),this.opcode("append")},DecoratorBlock:function(a){var b=a.program&&this.compileProgram(a.program),c=this.setupFullMustacheParams(a,b,void 0),d=a.path;this.useDecorators=!0,this.opcode("registerDecorator",c.length,d.original)},PartialStatement:function(a){this.usePartial=!0;var b=a.program;b&&(b=this.compileProgram(a.program));var c=a.params;if(c.length>1)throw new k["default"]("Unsupported number of partial arguments: "+c.length,a);c.length||(this.options.explicitPartialContext?this.opcode("pushLiteral","undefined"):c.push({type:"PathExpression",parts:[],depth:0}));var d=a.name.original,e="SubExpression"===a.name.type;e&&this.accept(a.name),this.setupFullMustacheParams(a,b,void 0,!0);var f=a.indent||"";this.options.preventIndent&&f&&(this.opcode("appendContent",f),f=""),this.opcode("invokePartial",e,d,f),this.opcode("append")},PartialBlockStatement:function(a){this.PartialStatement(a)},MustacheStatement:function(a){this.SubExpression(a),a.escaped&&!this.options.noEscape?this.opcode("appendEscaped"):this.opcode("append")},Decorator:function(a){this.DecoratorBlock(a)},ContentStatement:function(a){a.value&&this.opcode("appendContent",a.value)},CommentStatement:function(){},SubExpression:function(a){h(a);var b=this.classifySexpr(a);"simple"===b?this.simpleSexpr(a):"helper"===b?this.helperSexpr(a):this.ambiguousSexpr(a)},ambiguousSexpr:function(a,b,c){var d=a.path,e=d.parts[0],f=null!=b||null!=c;this.opcode("getContext",d.depth),this.opcode("pushProgram",b),this.opcode("pushProgram",c),d.strict=!0,this.accept(d),this.opcode("invokeAmbiguous",e,f)},simpleSexpr:function(a){var b=a.path;b.strict=!0,this.accept(b),this.opcode("resolvePossibleLambda")},helperSexpr:function(a,b,c){var d=this.setupFullMustacheParams(a,b,c),e=a.path,f=e.parts[0];if(this.options.knownHelpers[f])this.opcode("invokeKnownHelper",d.length,f);else{if(this.options.knownHelpersOnly)throw new k["default"]("You specified knownHelpersOnly, but used the unknown helper "+f,a);e.strict=!0,e.falsy=!0,this.accept(e),this.opcode("invokeHelper",d.length,e.original,n["default"].helpers.simpleId(e))}},PathExpression:function(a){this.addDepth(a.depth),this.opcode("getContext",a.depth);var b=a.parts[0],c=n["default"].helpers.scopedId(a),d=!a.depth&&!c&&this.blockParamIndex(b);d?this.opcode("lookupBlockParam",d,a.parts):b?a.data?(this.options.data=!0,this.opcode("lookupData",a.depth,a.parts,a.strict)):this.opcode("lookupOnContext",a.parts,a.falsy,a.strict,c):this.opcode("pushContext")},StringLiteral:function(a){this.opcode("pushString",a.value)},NumberLiteral:function(a){this.opcode("pushLiteral",a.value)},BooleanLiteral:function(a){this.opcode("pushLiteral",a.value)},UndefinedLiteral:function(){this.opcode("pushLiteral","undefined")},NullLiteral:function(){this.opcode("pushLiteral","null")},Hash:function(a){var b=a.pairs,c=0,d=b.length;for(this.opcode("pushHash");d>c;c++)this.pushParam(b[c].value);for(;c--;)this.opcode("assignToHash",b[c].key);this.opcode("popHash")},opcode:function(a){this.opcodes.push({opcode:a,args:o.call(arguments,1),loc:this.sourceNode[0].loc})},addDepth:function(a){a&&(this.useDepths=!0)},classifySexpr:function(a){var b=n["default"].helpers.simpleId(a.path),c=b&&!!this.blockParamIndex(a.path.parts[0]),d=!c&&n["default"].helpers.helperExpression(a),e=!c&&(d||b);if(e&&!d){var f=a.path.parts[0],g=this.options;g.knownHelpers[f]?d=!0:g.knownHelpersOnly&&(e=!1)}return d?"helper":e?"ambiguous":"simple"},pushParams:function(a){for(var b=0,c=a.length;c>b;b++)this.pushParam(a[b])},pushParam:function(a){var b=null!=a.value?a.value:a.original||"";if(this.stringParams)b.replace&&(b=b.replace(/^(\.?\.\/)*/g,"").replace(/\//g,".")),a.depth&&this.addDepth(a.depth),this.opcode("getContext",a.depth||0),this.opcode("pushStringParam",b,a.type),"SubExpression"===a.type&&this.accept(a);else{if(this.trackIds){var c=void 0;if(!a.parts||n["default"].helpers.scopedId(a)||a.depth||(c=this.blockParamIndex(a.parts[0])),c){var d=a.parts.slice(1).join(".");this.opcode("pushId","BlockParam",c,d)}else b=a.original||b,b.replace&&(b=b.replace(/^this(?:\.|$)/,"").replace(/^\.\//,"").replace(/^\.$/,"")),this.opcode("pushId",a.type,b)}this.accept(a)}},setupFullMustacheParams:function(a,b,c,d){var e=a.params;return this.pushParams(e),this.opcode("pushProgram",b),this.opcode("pushProgram",c),a.hash?this.accept(a.hash):this.opcode("emptyHash",d),e},blockParamIndex:function(a){for(var b=0,c=this.options.blockParams.length;c>b;b++){var d=this.options.blockParams[b],e=d&&l.indexOf(d,a);if(d&&e>=0)return[b,e]}}}},function(a,b,c){"use strict";function d(a){this.value=a}function e(){}function f(a,b,c,d){var e=b.popStack(),f=0,g=c.length;for(a&&g--;g>f;f++)e=b.nameLookup(e,c[f],d);return a?[b.aliasable("container.strict"),"(",e,", ",b.quotedString(c[f]),")"]:e}var g=c(1)["default"];b.__esModule=!0;var h=c(4),i=c(6),j=g(i),k=c(5),l=c(29),m=g(l);e.prototype={nameLookup:function(a,b){return e.isValidJavaScriptVariableName(b)?[a,".",b]:[a,"[",JSON.stringify(b),"]"]},depthedLookup:function(a){return[this.aliasable("container.lookup"),'(depths, "',a,'")']},compilerInfo:function(){var a=h.COMPILER_REVISION,b=h.REVISION_CHANGES[a];return[a,b]},appendToBuffer:function(a,b,c){return k.isArray(a)||(a=[a]),a=this.source.wrap(a,b),this.environment.isSimple?["return ",a,";"]:c?["buffer += ",a,";"]:(a.appendToBuffer=!0,a)},initializeBuffer:function(){return this.quotedString("")},compile:function(a,b,c,d){this.environment=a,this.options=b,this.stringParams=this.options.stringParams,this.trackIds=this.options.trackIds,this.precompile=!d,this.name=this.environment.name,this.isChild=!!c,this.context=c||{decorators:[],programs:[],environments:[]},this.preamble(),this.stackSlot=0,this.stackVars=[],this.aliases={},this.registers={list:[]},this.hashes=[],this.compileStack=[],this.inlineStack=[],this.blockParams=[],this.compileChildren(a,b),this.useDepths=this.useDepths||a.useDepths||a.useDecorators||this.options.compat,this.useBlockParams=this.useBlockParams||a.useBlockParams;var e=a.opcodes,f=void 0,g=void 0,h=void 0,i=void 0;for(h=0,i=e.length;i>h;h++)f=e[h],this.source.currentLocation=f.loc,g=g||f.loc,this[f.opcode].apply(this,f.args);if(this.source.currentLocation=g,this.pushSource(""),this.stackSlot||this.inlineStack.length||this.compileStack.length)throw new j["default"]("Compile completed with content left on stack");this.decorators.isEmpty()?this.decorators=void 0:(this.useDecorators=!0,this.decorators.prepend("var decorators = container.decorators;\n"),this.decorators.push("return fn;"),d?this.decorators=Function.apply(this,["fn","props","container","depth0","data","blockParams","depths",this.decorators.merge()]):(this.decorators.prepend("function(fn, props, container, depth0, data, blockParams, depths) {\n"),this.decorators.push("}\n"),this.decorators=this.decorators.merge()));var k=this.createFunctionContext(d);if(this.isChild)return k;var l={compiler:this.compilerInfo(),main:k};this.decorators&&(l.main_d=this.decorators,l.useDecorators=!0);var m=this.context,n=m.programs,o=m.decorators;for(h=0,i=n.length;i>h;h++)n[h]&&(l[h]=n[h],o[h]&&(l[h+"_d"]=o[h],l.useDecorators=!0));return this.environment.usePartial&&(l.usePartial=!0),this.options.data&&(l.useData=!0),this.useDepths&&(l.useDepths=!0),this.useBlockParams&&(l.useBlockParams=!0),this.options.compat&&(l.compat=!0),d?l.compilerOptions=this.options:(l.compiler=JSON.stringify(l.compiler),this.source.currentLocation={start:{line:1,column:0}},l=this.objectLiteral(l),b.srcName?(l=l.toStringWithSourceMap({file:b.destName}),l.map=l.map&&l.map.toString()):l=l.toString()),l},preamble:function(){this.lastContext=0,this.source=new m["default"](this.options.srcName),this.decorators=new m["default"](this.options.srcName)},createFunctionContext:function(a){var b="",c=this.stackVars.concat(this.registers.list);c.length>0&&(b+=", "+c.join(", "));var d=0;for(var e in this.aliases){var f=this.aliases[e];this.aliases.hasOwnProperty(e)&&f.children&&f.referenceCount>1&&(b+=", alias"+ ++d+"="+e,f.children[0]="alias"+d)}var g=["container","depth0","helpers","partials","data"];(this.useBlockParams||this.useDepths)&&g.push("blockParams"),this.useDepths&&g.push("depths");var h=this.mergeSource(b);return a?(g.push(h),Function.apply(this,g)):this.source.wrap(["function(",g.join(","),") {\n ",h,"}"])},mergeSource:function(a){var b=this.environment.isSimple,c=!this.forceBuffer,d=void 0,e=void 0,f=void 0,g=void 0;return this.source.each(function(a){a.appendToBuffer?(f?a.prepend(" + "):f=a,g=a):(f&&(e?f.prepend("buffer += "):d=!0,g.add(";"),f=g=void 0),e=!0,b||(c=!1))}),c?f?(f.prepend("return "),g.add(";")):e||this.source.push('return "";'):(a+=", buffer = "+(d?"":this.initializeBuffer()),f?(f.prepend("return buffer + "),g.add(";")):this.source.push("return buffer;")),a&&this.source.prepend("var "+a.substring(2)+(d?"":";\n")),this.source.merge()},blockValue:function(a){var b=this.aliasable("helpers.blockHelperMissing"),c=[this.contextName(0)];this.setupHelperArgs(a,0,c);var d=this.popStack();c.splice(1,0,d),this.push(this.source.functionCall(b,"call",c))},ambiguousBlockValue:function(){var a=this.aliasable("helpers.blockHelperMissing"),b=[this.contextName(0)];this.setupHelperArgs("",0,b,!0),this.flushInline();var c=this.topStack();b.splice(1,0,c),this.pushSource(["if (!",this.lastHelper,") { ",c," = ",this.source.functionCall(a,"call",b),"}"])},appendContent:function(a){this.pendingContent?a=this.pendingContent+a:this.pendingLocation=this.source.currentLocation,this.pendingContent=a},append:function(){if(this.isInline())this.replaceStack(function(a){return[" != null ? ",a,' : ""']}),this.pushSource(this.appendToBuffer(this.popStack()));else{var a=this.popStack();this.pushSource(["if (",a," != null) { ",this.appendToBuffer(a,void 0,!0)," }"]),this.environment.isSimple&&this.pushSource(["else { ",this.appendToBuffer("''",void 0,!0)," }"])}},appendEscaped:function(){this.pushSource(this.appendToBuffer([this.aliasable("container.escapeExpression"),"(",this.popStack(),")"]))},getContext:function(a){this.lastContext=a},pushContext:function(){this.pushStackLiteral(this.contextName(this.lastContext))},lookupOnContext:function(a,b,c,d){var e=0;d||!this.options.compat||this.lastContext?this.pushContext():this.push(this.depthedLookup(a[e++])),this.resolvePath("context",a,e,b,c)},lookupBlockParam:function(a,b){this.useBlockParams=!0,this.push(["blockParams[",a[0],"][",a[1],"]"]),this.resolvePath("context",b,1)},lookupData:function(a,b,c){a?this.pushStackLiteral("container.data(data, "+a+")"):this.pushStackLiteral("data"),this.resolvePath("data",b,0,!0,c)},resolvePath:function(a,b,c,d,e){var g=this;if(this.options.strict||this.options.assumeObjects)return void this.push(f(this.options.strict&&e,this,b,a));for(var h=b.length;h>c;c++)this.replaceStack(function(e){var f=g.nameLookup(e,b[c],a);return d?[" && ",f]:[" != null ? ",f," : ",e]})},resolvePossibleLambda:function(){this.push([this.aliasable("container.lambda"),"(",this.popStack(),", ",this.contextName(0),")"])},pushStringParam:function(a,b){this.pushContext(),this.pushString(b),"SubExpression"!==b&&("string"==typeof a?this.pushString(a):this.pushStackLiteral(a))},emptyHash:function(a){this.trackIds&&this.push("{}"),this.stringParams&&(this.push("{}"),this.push("{}")),this.pushStackLiteral(a?"undefined":"{}")},pushHash:function(){this.hash&&this.hashes.push(this.hash),this.hash={values:[],types:[],contexts:[],ids:[]}},popHash:function(){var a=this.hash;this.hash=this.hashes.pop(),this.trackIds&&this.push(this.objectLiteral(a.ids)),this.stringParams&&(this.push(this.objectLiteral(a.contexts)),this.push(this.objectLiteral(a.types))),this.push(this.objectLiteral(a.values))},pushString:function(a){this.pushStackLiteral(this.quotedString(a))},pushLiteral:function(a){this.pushStackLiteral(a)},pushProgram:function(a){null!=a?this.pushStackLiteral(this.programExpression(a)):this.pushStackLiteral(null)},registerDecorator:function(a,b){var c=this.nameLookup("decorators",b,"decorator"),d=this.setupHelperArgs(b,a);this.decorators.push(["fn = ",this.decorators.functionCall(c,"",["fn","props","container",d])," || fn;"])},invokeHelper:function(a,b,c){var d=this.popStack(),e=this.setupHelper(a,b),f=c?[e.name," || "]:"",g=["("].concat(f,d);this.options.strict||g.push(" || ",this.aliasable("helpers.helperMissing")),g.push(")"),this.push(this.source.functionCall(g,"call",e.callParams))},invokeKnownHelper:function(a,b){var c=this.setupHelper(a,b);this.push(this.source.functionCall(c.name,"call",c.callParams))},invokeAmbiguous:function(a,b){this.useRegister("helper");var c=this.popStack();this.emptyHash();var d=this.setupHelper(0,a,b),e=this.lastHelper=this.nameLookup("helpers",a,"helper"),f=["(","(helper = ",e," || ",c,")"];this.options.strict||(f[0]="(helper = ",f.push(" != null ? helper : ",this.aliasable("helpers.helperMissing"))),this.push(["(",f,d.paramsInit?["),(",d.paramsInit]:[],"),","(typeof helper === ",this.aliasable('"function"')," ? ",this.source.functionCall("helper","call",d.callParams)," : helper))"])},invokePartial:function(a,b,c){var d=[],e=this.setupParams(b,1,d);a&&(b=this.popStack(),delete e.name),c&&(e.indent=JSON.stringify(c)),e.helpers="helpers",e.partials="partials",e.decorators="container.decorators",a?d.unshift(b):d.unshift(this.nameLookup("partials",b,"partial")),this.options.compat&&(e.depths="depths"),e=this.objectLiteral(e), -d.push(e),this.push(this.source.functionCall("container.invokePartial","",d))},assignToHash:function(a){var b=this.popStack(),c=void 0,d=void 0,e=void 0;this.trackIds&&(e=this.popStack()),this.stringParams&&(d=this.popStack(),c=this.popStack());var f=this.hash;c&&(f.contexts[a]=c),d&&(f.types[a]=d),e&&(f.ids[a]=e),f.values[a]=b},pushId:function(a,b,c){"BlockParam"===a?this.pushStackLiteral("blockParams["+b[0]+"].path["+b[1]+"]"+(c?" + "+JSON.stringify("."+c):"")):"PathExpression"===a?this.pushString(b):"SubExpression"===a?this.pushStackLiteral("true"):this.pushStackLiteral("null")},compiler:e,compileChildren:function(a,b){for(var c=a.children,d=void 0,e=void 0,f=0,g=c.length;g>f;f++){d=c[f],e=new this.compiler;var h=this.matchExistingProgram(d);null==h?(this.context.programs.push(""),h=this.context.programs.length,d.index=h,d.name="program"+h,this.context.programs[h]=e.compile(d,b,this.context,!this.precompile),this.context.decorators[h]=e.decorators,this.context.environments[h]=d,this.useDepths=this.useDepths||e.useDepths,this.useBlockParams=this.useBlockParams||e.useBlockParams):(d.index=h,d.name="program"+h,this.useDepths=this.useDepths||d.useDepths,this.useBlockParams=this.useBlockParams||d.useBlockParams)}},matchExistingProgram:function(a){for(var b=0,c=this.context.environments.length;c>b;b++){var d=this.context.environments[b];if(d&&d.equals(a))return b}},programExpression:function(a){var b=this.environment.children[a],c=[b.index,"data",b.blockParams];return(this.useBlockParams||this.useDepths)&&c.push("blockParams"),this.useDepths&&c.push("depths"),"container.program("+c.join(", ")+")"},useRegister:function(a){this.registers[a]||(this.registers[a]=!0,this.registers.list.push(a))},push:function(a){return a instanceof d||(a=this.source.wrap(a)),this.inlineStack.push(a),a},pushStackLiteral:function(a){this.push(new d(a))},pushSource:function(a){this.pendingContent&&(this.source.push(this.appendToBuffer(this.source.quotedString(this.pendingContent),this.pendingLocation)),this.pendingContent=void 0),a&&this.source.push(a)},replaceStack:function(a){var b=["("],c=void 0,e=void 0,f=void 0;if(!this.isInline())throw new j["default"]("replaceStack on non-inline");var g=this.popStack(!0);if(g instanceof d)c=[g.value],b=["(",c],f=!0;else{e=!0;var h=this.incrStack();b=["((",this.push(h)," = ",g,")"],c=this.topStack()}var i=a.call(this,c);f||this.popStack(),e&&this.stackSlot--,this.push(b.concat(i,")"))},incrStack:function(){return this.stackSlot++,this.stackSlot>this.stackVars.length&&this.stackVars.push("stack"+this.stackSlot),this.topStackName()},topStackName:function(){return"stack"+this.stackSlot},flushInline:function(){var a=this.inlineStack;this.inlineStack=[];for(var b=0,c=a.length;c>b;b++){var e=a[b];if(e instanceof d)this.compileStack.push(e);else{var f=this.incrStack();this.pushSource([f," = ",e,";"]),this.compileStack.push(f)}}},isInline:function(){return this.inlineStack.length},popStack:function(a){var b=this.isInline(),c=(b?this.inlineStack:this.compileStack).pop();if(!a&&c instanceof d)return c.value;if(!b){if(!this.stackSlot)throw new j["default"]("Invalid stack pop");this.stackSlot--}return c},topStack:function(){var a=this.isInline()?this.inlineStack:this.compileStack,b=a[a.length-1];return b instanceof d?b.value:b},contextName:function(a){return this.useDepths&&a?"depths["+a+"]":"depth"+a},quotedString:function(a){return this.source.quotedString(a)},objectLiteral:function(a){return this.source.objectLiteral(a)},aliasable:function(a){var b=this.aliases[a];return b?(b.referenceCount++,b):(b=this.aliases[a]=this.source.wrap(a),b.aliasable=!0,b.referenceCount=1,b)},setupHelper:function(a,b,c){var d=[],e=this.setupHelperArgs(b,a,d,c),f=this.nameLookup("helpers",b,"helper"),g=this.aliasable(this.contextName(0)+" != null ? "+this.contextName(0)+" : {}");return{params:d,paramsInit:e,name:f,callParams:[g].concat(d)}},setupParams:function(a,b,c){var d={},e=[],f=[],g=[],h=!c,i=void 0;h&&(c=[]),d.name=this.quotedString(a),d.hash=this.popStack(),this.trackIds&&(d.hashIds=this.popStack()),this.stringParams&&(d.hashTypes=this.popStack(),d.hashContexts=this.popStack());var j=this.popStack(),k=this.popStack();(k||j)&&(d.fn=k||"container.noop",d.inverse=j||"container.noop");for(var l=b;l--;)i=this.popStack(),c[l]=i,this.trackIds&&(g[l]=this.popStack()),this.stringParams&&(f[l]=this.popStack(),e[l]=this.popStack());return h&&(d.args=this.source.generateArray(c)),this.trackIds&&(d.ids=this.source.generateArray(g)),this.stringParams&&(d.types=this.source.generateArray(f),d.contexts=this.source.generateArray(e)),this.options.data&&(d.data="data"),this.useBlockParams&&(d.blockParams="blockParams"),d},setupHelperArgs:function(a,b,c,d){var e=this.setupParams(a,b,c);return e=this.objectLiteral(e),d?(this.useRegister("options"),c.push("options"),["options=",e]):c?(c.push(e),""):e}},function(){for(var a="break else new var case finally return void catch for switch while continue function this with default if throw delete in try do instanceof typeof abstract enum int short boolean export interface static byte extends long super char final native synchronized class float package throws const goto private transient debugger implements protected volatile double import public let yield await null true false".split(" "),b=e.RESERVED_WORDS={},c=0,d=a.length;d>c;c++)b[a[c]]=!0}(),e.isValidJavaScriptVariableName=function(a){return!e.RESERVED_WORDS[a]&&/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(a)},b["default"]=e,a.exports=b["default"]},function(a,b,c){"use strict";function d(a,b,c){if(f.isArray(a)){for(var d=[],e=0,g=a.length;g>e;e++)d.push(b.wrap(a[e],c));return d}return"boolean"==typeof a||"number"==typeof a?a+"":a}function e(a){this.srcFile=a,this.source=[]}b.__esModule=!0;var f=c(5),g=void 0;try{}catch(h){}g||(g=function(a,b,c,d){this.src="",d&&this.add(d)},g.prototype={add:function(a){f.isArray(a)&&(a=a.join("")),this.src+=a},prepend:function(a){f.isArray(a)&&(a=a.join("")),this.src=a+this.src},toStringWithSourceMap:function(){return{code:this.toString()}},toString:function(){return this.src}}),e.prototype={isEmpty:function(){return!this.source.length},prepend:function(a,b){this.source.unshift(this.wrap(a,b))},push:function(a,b){this.source.push(this.wrap(a,b))},merge:function(){var a=this.empty();return this.each(function(b){a.add([" ",b,"\n"])}),a},each:function(a){for(var b=0,c=this.source.length;c>b;b++)a(this.source[b])},empty:function(){var a=this.currentLocation||{start:{}};return new g(a.start.line,a.start.column,this.srcFile)},wrap:function(a){var b=arguments.length<=1||void 0===arguments[1]?this.currentLocation||{start:{}}:arguments[1];return a instanceof g?a:(a=d(a,this,b),new g(b.start.line,b.start.column,this.srcFile,a))},functionCall:function(a,b,c){return c=this.generateList(c),this.wrap([a,b?"."+b+"(":"(",c,")"])},quotedString:function(a){return'"'+(a+"").replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029")+'"'},objectLiteral:function(a){var b=[];for(var c in a)if(a.hasOwnProperty(c)){var e=d(a[c],this);"undefined"!==e&&b.push([this.quotedString(c),":",e])}var f=this.generateList(b);return f.prepend("{"),f.add("}"),f},generateList:function(a){for(var b=this.empty(),c=0,e=a.length;e>c;c++)c&&b.add(","),b.add(d(a[c],this));return b},generateArray:function(a){var b=this.generateList(a);return b.prepend("["),b.add("]"),b}},b["default"]=e,a.exports=b["default"]}])}); \ No newline at end of file diff --git a/docs/api/vendor/jquery.min.js b/docs/api/vendor/jquery.min.js deleted file mode 100644 index 349030de..00000000 --- a/docs/api/vendor/jquery.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! jQuery v2.2.1 | (c) jQuery Foundation | jquery.org/license */ -!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=a.document,e=c.slice,f=c.concat,g=c.push,h=c.indexOf,i={},j=i.toString,k=i.hasOwnProperty,l={},m="2.2.1",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return e.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:e.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a){return n.each(this,a)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(e.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:g,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){var b=a&&a.toString();return!n.isArray(a)&&b-parseFloat(b)+1>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!k.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?i[j.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=d.createElement("script"),b.text=a,d.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(s(a)){for(c=a.length;c>d;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):g.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:h.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,g=0,h=[];if(s(a))for(d=a.length;d>g;g++)e=b(a[g],g,c),null!=e&&h.push(e);else for(g in a)e=b(a[g],g,c),null!=e&&h.push(e);return f.apply([],h)},guid:1,proxy:function(a,b){var c,d,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(d=e.call(arguments,2),f=function(){return a.apply(b||this,d.concat(e.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:l}),"function"==typeof Symbol&&(n.fn[Symbol.iterator]=c[Symbol.iterator]),n.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){i["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=!!a&&"length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ga(),z=ga(),A=ga(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+M+"))|)"+L+"*\\]",O=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+N+")*)|.*)\\)|)",P=new RegExp(L+"+","g"),Q=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),R=new RegExp("^"+L+"*,"+L+"*"),S=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),T=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),U=new RegExp(O),V=new RegExp("^"+M+"$"),W={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M+"|[*])"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},X=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Z=/^[^{]+\{\s*\[native \w/,$=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,_=/[+~]/,aa=/'|\\/g,ba=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),ca=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},da=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(ea){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fa(a,b,d,e){var f,h,j,k,l,o,r,s,w=b&&b.ownerDocument,x=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==x&&9!==x&&11!==x)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==x&&(o=$.exec(a)))if(f=o[1]){if(9===x){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(w&&(j=w.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(o[2])return H.apply(d,b.getElementsByTagName(a)),d;if((f=o[3])&&c.getElementsByClassName&&b.getElementsByClassName)return H.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==x)w=b,s=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(aa,"\\$&"):b.setAttribute("id",k=u),r=g(a),h=r.length,l=V.test(k)?"#"+k:"[id='"+k+"']";while(h--)r[h]=l+" "+qa(r[h]);s=r.join(","),w=_.test(a)&&oa(b.parentNode)||b}if(s)try{return H.apply(d,w.querySelectorAll(s)),d}catch(y){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(Q,"$1"),b,d,e)}function ga(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ha(a){return a[u]=!0,a}function ia(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ja(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function ka(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function la(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function na(a){return ha(function(b){return b=+b,ha(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function oa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=fa.support={},f=fa.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fa.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ia(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ia(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Z.test(n.getElementsByClassName),c.getById=ia(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return"undefined"!=typeof b.getElementsByClassName&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=Z.test(n.querySelectorAll))&&(ia(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ia(function(a){var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Z.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ia(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",O)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Z.test(o.compareDocumentPosition),t=b||Z.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return ka(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?ka(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},fa.matches=function(a,b){return fa(a,null,null,b)},fa.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(T,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fa(b,n,null,[a]).length>0},fa.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fa.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fa.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fa.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fa.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fa.selectors={cacheLength:50,createPseudo:ha,match:W,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ba,ca),a[3]=(a[3]||a[4]||a[5]||"").replace(ba,ca),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fa.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fa.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return W.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&U.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ba,ca).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fa.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(P," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fa.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ha(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ha(function(a){var b=[],c=[],d=h(a.replace(Q,"$1"));return d[u]?ha(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ha(function(a){return function(b){return fa(a,b).length>0}}),contains:ha(function(a){return a=a.replace(ba,ca),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ha(function(a){return V.test(a||"")||fa.error("unsupported lang: "+a),a=a.replace(ba,ca).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Y.test(a.nodeName)},input:function(a){return X.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:na(function(){return[0]}),last:na(function(a,b){return[b-1]}),eq:na(function(a,b,c){return[0>c?c+b:c]}),even:na(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:na(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:na(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:na(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function ra(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j,k=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(j=b[u]||(b[u]={}),i=j[b.uniqueID]||(j[b.uniqueID]={}),(h=i[d])&&h[0]===w&&h[1]===f)return k[2]=h[2];if(i[d]=k,k[2]=a(b,c,g))return!0}}}function sa(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ta(a,b,c){for(var d=0,e=b.length;e>d;d++)fa(a,b[d],c);return c}function ua(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function va(a,b,c,d,e,f){return d&&!d[u]&&(d=va(d)),e&&!e[u]&&(e=va(e,f)),ha(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ta(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ua(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ua(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ua(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function wa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ra(function(a){return a===b},h,!0),l=ra(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[ra(sa(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return va(i>1&&sa(m),i>1&&qa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(Q,"$1"),c,e>i&&wa(a.slice(i,e)),f>e&&wa(a=a.slice(e)),f>e&&qa(a))}m.push(c)}return sa(m)}function xa(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=F.call(i));u=ua(u)}H.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&fa.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ha(f):f}return h=fa.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xa(e,d)),f.selector=a}return f},i=fa.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ba,ca),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=W.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ba,ca),_.test(j[0].type)&&oa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qa(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||_.test(a)&&oa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ia(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ia(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ja("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ia(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ja("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ia(function(a){return null==a.getAttribute("disabled")})||ja(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fa}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.uniqueSort=n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},v=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},w=n.expr.match.needsContext,x=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,y=/^.[^:#\[\.,]*$/;function z(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(y.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return h.call(b,a)>-1!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(z(this,a||[],!1))},not:function(a){return this.pushStack(z(this,a||[],!0))},is:function(a){return!!z(this,"string"==typeof a&&w.test(a)?n(a):a||[],!1).length}});var A,B=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=n.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||A,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:B.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),x.test(e[1])&&n.isPlainObject(b))for(e in b)n.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&f.parentNode&&(this.length=1,this[0]=f),this.context=d,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?void 0!==c.ready?c.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};C.prototype=n.fn,A=n(d);var D=/^(?:parents|prev(?:Until|All))/,E={children:!0,contents:!0,next:!0,prev:!0};n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=w.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?h.call(n(a),this[0]):h.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.uniqueSort(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function F(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return u(a,"parentNode")},parentsUntil:function(a,b,c){return u(a,"parentNode",c)},next:function(a){return F(a,"nextSibling")},prev:function(a){return F(a,"previousSibling")},nextAll:function(a){return u(a,"nextSibling")},prevAll:function(a){return u(a,"previousSibling")},nextUntil:function(a,b,c){return u(a,"nextSibling",c)},prevUntil:function(a,b,c){return u(a,"previousSibling",c)},siblings:function(a){return v((a.parentNode||{}).firstChild,a)},children:function(a){return v(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(E[a]||n.uniqueSort(e),D.test(a)&&e.reverse()),this.pushStack(e)}});var G=/\S+/g;function H(a){var b={};return n.each(a.match(G)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?H(a):n.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h-1)f.splice(c,1),h>=c&&h--}),this},has:function(a){return a?n.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().progress(c.notify).done(c.resolve).fail(c.reject):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=e.call(arguments),d=c.length,f=1!==d||a&&n.isFunction(a.promise)?d:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?e.call(arguments):d,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(d>1)for(i=new Array(d),j=new Array(d),k=new Array(d);d>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().progress(h(b,j,i)).done(h(b,k,c)).fail(g.reject):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(d,[n]),n.fn.triggerHandler&&(n(d).triggerHandler("ready"),n(d).off("ready"))))}});function J(){d.removeEventListener("DOMContentLoaded",J),a.removeEventListener("load",J),n.ready()}n.ready.promise=function(b){return I||(I=n.Deferred(),"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(n.ready):(d.addEventListener("DOMContentLoaded",J),a.addEventListener("load",J))),I.promise(b)},n.ready.promise();var K=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)K(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},L=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function M(){this.expando=n.expando+M.uid++}M.uid=1,M.prototype={register:function(a,b){var c=b||{};return a.nodeType?a[this.expando]=c:Object.defineProperty(a,this.expando,{value:c,writable:!0,configurable:!0}),a[this.expando]},cache:function(a){if(!L(a))return{};var b=a[this.expando];return b||(b={},L(a)&&(a.nodeType?a[this.expando]=b:Object.defineProperty(a,this.expando,{value:b,configurable:!0}))),b},set:function(a,b,c){var d,e=this.cache(a);if("string"==typeof b)e[b]=c;else for(d in b)e[d]=b[d];return e},get:function(a,b){return void 0===b?this.cache(a):a[this.expando]&&a[this.expando][b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=a[this.expando];if(void 0!==f){if(void 0===b)this.register(a);else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in f?d=[b,e]:(d=e,d=d in f?[d]:d.match(G)||[])),c=d.length;while(c--)delete f[d[c]]}(void 0===b||n.isEmptyObject(f))&&(a.nodeType?a[this.expando]=void 0:delete a[this.expando])}},hasData:function(a){var b=a[this.expando];return void 0!==b&&!n.isEmptyObject(b)}};var N=new M,O=new M,P=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,Q=/[A-Z]/g;function R(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(Q,"-$&").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:P.test(c)?n.parseJSON(c):c}catch(e){}O.set(a,b,c); -}else c=void 0;return c}n.extend({hasData:function(a){return O.hasData(a)||N.hasData(a)},data:function(a,b,c){return O.access(a,b,c)},removeData:function(a,b){O.remove(a,b)},_data:function(a,b,c){return N.access(a,b,c)},_removeData:function(a,b){N.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=O.get(f),1===f.nodeType&&!N.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),R(f,d,e[d])));N.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){O.set(this,a)}):K(this,function(b){var c,d;if(f&&void 0===b){if(c=O.get(f,a)||O.get(f,a.replace(Q,"-$&").toLowerCase()),void 0!==c)return c;if(d=n.camelCase(a),c=O.get(f,d),void 0!==c)return c;if(c=R(f,d,void 0),void 0!==c)return c}else d=n.camelCase(a),this.each(function(){var c=O.get(this,d);O.set(this,d,b),a.indexOf("-")>-1&&void 0!==c&&O.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){O.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=N.get(a,b),c&&(!d||n.isArray(c)?d=N.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return N.get(a,c)||N.access(a,c,{empty:n.Callbacks("once memory").add(function(){N.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length",""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};$.optgroup=$.option,$.tbody=$.tfoot=$.colgroup=$.caption=$.thead,$.th=$.td;function _(a,b){var c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function aa(a,b){for(var c=0,d=a.length;d>c;c++)N.set(a[c],"globalEval",!b||N.get(b[c],"globalEval"))}var ba=/<|&#?\w+;/;function ca(a,b,c,d,e){for(var f,g,h,i,j,k,l=b.createDocumentFragment(),m=[],o=0,p=a.length;p>o;o++)if(f=a[o],f||0===f)if("object"===n.type(f))n.merge(m,f.nodeType?[f]:f);else if(ba.test(f)){g=g||l.appendChild(b.createElement("div")),h=(Y.exec(f)||["",""])[1].toLowerCase(),i=$[h]||$._default,g.innerHTML=i[1]+n.htmlPrefilter(f)+i[2],k=i[0];while(k--)g=g.lastChild;n.merge(m,g.childNodes),g=l.firstChild,g.textContent=""}else m.push(b.createTextNode(f));l.textContent="",o=0;while(f=m[o++])if(d&&n.inArray(f,d)>-1)e&&e.push(f);else if(j=n.contains(f.ownerDocument,f),g=_(l.appendChild(f),"script"),j&&aa(g),c){k=0;while(f=g[k++])Z.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var da=/^key/,ea=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,fa=/^([^.]*)(?:\.(.+)|)/;function ga(){return!0}function ha(){return!1}function ia(){try{return d.activeElement}catch(a){}}function ja(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)ja(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=ha;else if(!e)return a;return 1===f&&(g=e,e=function(a){return n().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=n.guid++)),a.each(function(){n.event.add(this,b,e,d,c)})}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=N.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return"undefined"!=typeof n&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(G)||[""],j=b.length;while(j--)h=fa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=N.hasData(a)&&N.get(a);if(r&&(i=r.events)){b=(b||"").match(G)||[""],j=b.length;while(j--)if(h=fa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&N.remove(a,"handle events")}},dispatch:function(a){a=n.event.fix(a);var b,c,d,f,g,h=[],i=e.call(arguments),j=(N.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.rnamespace||a.rnamespace.test(g.namespace))&&(a.handleObj=g,a.data=g.data,d=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==d&&(a.result=d)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&("click"!==a.type||isNaN(a.button)||a.button<1))for(;i!==this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>-1:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,la=/\s*$/g;function pa(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function qa(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function ra(a){var b=na.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function sa(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(N.hasData(a)&&(f=N.access(a),g=N.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}O.hasData(a)&&(h=O.access(a),i=n.extend({},h),O.set(b,i))}}function ta(a,b){var c=b.nodeName.toLowerCase();"input"===c&&X.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}function ua(a,b,c,d){b=f.apply([],b);var e,g,h,i,j,k,m=0,o=a.length,p=o-1,q=b[0],r=n.isFunction(q);if(r||o>1&&"string"==typeof q&&!l.checkClone&&ma.test(q))return a.each(function(e){var f=a.eq(e);r&&(b[0]=q.call(this,e,f.html())),ua(f,b,c,d)});if(o&&(e=ca(b,a[0].ownerDocument,!1,a,d),g=e.firstChild,1===e.childNodes.length&&(e=g),g||d)){for(h=n.map(_(e,"script"),qa),i=h.length;o>m;m++)j=e,m!==p&&(j=n.clone(j,!0,!0),i&&n.merge(h,_(j,"script"))),c.call(a[m],j,m);if(i)for(k=h[h.length-1].ownerDocument,n.map(h,ra),m=0;i>m;m++)j=h[m],Z.test(j.type||"")&&!N.access(j,"globalEval")&&n.contains(k,j)&&(j.src?n._evalUrl&&n._evalUrl(j.src):n.globalEval(j.textContent.replace(oa,"")))}return a}function va(a,b,c){for(var d,e=b?n.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||n.cleanData(_(d)),d.parentNode&&(c&&n.contains(d.ownerDocument,d)&&aa(_(d,"script")),d.parentNode.removeChild(d));return a}n.extend({htmlPrefilter:function(a){return a.replace(ka,"<$1>")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=_(h),f=_(a),d=0,e=f.length;e>d;d++)ta(f[d],g[d]);if(b)if(c)for(f=f||_(a),g=g||_(h),d=0,e=f.length;e>d;d++)sa(f[d],g[d]);else sa(a,h);return g=_(h,"script"),g.length>0&&aa(g,!i&&_(a,"script")),h},cleanData:function(a){for(var b,c,d,e=n.event.special,f=0;void 0!==(c=a[f]);f++)if(L(c)){if(b=c[N.expando]){if(b.events)for(d in b.events)e[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);c[N.expando]=void 0}c[O.expando]&&(c[O.expando]=void 0)}}}),n.fn.extend({domManip:ua,detach:function(a){return va(this,a,!0)},remove:function(a){return va(this,a)},text:function(a){return K(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return ua(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=pa(this,a);b.appendChild(a)}})},prepend:function(){return ua(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=pa(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return ua(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return ua(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(_(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return K(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!la.test(a)&&!$[(Y.exec(a)||["",""])[1].toLowerCase()]){a=n.htmlPrefilter(a);try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(_(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return ua(this,arguments,function(b){var c=this.parentNode;n.inArray(this,a)<0&&(n.cleanData(_(this)),c&&c.replaceChild(b,this))},a)}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),f=e.length-1,h=0;f>=h;h++)c=h===f?this:this.clone(!0),n(e[h])[b](c),g.apply(d,c.get());return this.pushStack(d)}});var wa,xa={HTML:"block",BODY:"block"};function ya(a,b){var c=n(b.createElement(a)).appendTo(b.body),d=n.css(c[0],"display");return c.detach(),d}function za(a){var b=d,c=xa[a];return c||(c=ya(a,b),"none"!==c&&c||(wa=(wa||n("