diff --git a/clear_data.sh b/clear_data.sh index c280170..de1d832 100644 --- a/clear_data.sh +++ b/clear_data.sh @@ -1,8 +1,3 @@ adb shell pm clear com.android.chrome adb shell am set-debug-app --persistent com.android.chrome adb shell am start -n com.android.chrome/com.google.android.apps.chrome.Main -adb shell settings put global http_proxy zproxy.lum-superproxy.io:22225 -adb shell settings put global global_http_proxy_host zproxy.lum-superproxy.io -adb shell settings put global global_http_proxy_port 22225 -adb shell settings put global global_http_proxy_username um-customer-c_daabba94-zone-residential -adb shell settings put global global_http_proxy_password 9dwmh54u3bbh \ No newline at end of file diff --git a/main.js b/main.js index 5a0c9b2..845e1fa 100644 --- a/main.js +++ b/main.js @@ -1,33 +1,28 @@ const {_android: android} = require('playwright'); +const ExcelUtil = require("./src/excel/ExcelUtil"); +const CommandorPage = require("./src/workers/CommandorPage"); const RDV_URL = "https://rendezvousparis.hermes.com/client/register"; // const RDV_URL = "https://bot.sannysoft.com/"; +// const RDV_URL = "http://192.168.0.44:8000/test_appointment.html" +function delay(delayInms) { + return new Promise(resolve => { + setTimeout(() => { + resolve(2); + }, delayInms); + }); +} -(async () => { - // Connect to the device. - const [device] = await android.devices(); - console.log(`Model: ${device.model()}`); - console.log(`Serial: ${device.serial()}`); - // Take screenshot of the whole device. - await device.screenshot({path: 'device.png'}); - - { - // --------------------- Browser ----------------------- - - // Launch Chrome browser. - await device.shell('am force-stop com.android.chrome'); - const context = await device.launchBrowser({command: '--incognito'}); - - // Use BrowserContext as usual. - const page = await context.newPage(); - await page.goto(RDV_URL); - console.log(await page.evaluate(() => window.location.href)); - await page.screenshot({path: 'page.png'}); - await delay(50000); - await context.close(); - } - - // Close the device. - await device.close(); -})(); \ No newline at end of file +let excelUtil = new ExcelUtil(); +let contactList = excelUtil.readContacts(); +let commandor = new CommandorPage(contactList[2]); +// (async () => { +// Connect to the device. +const [device] = await android.devices(); +console.log(`Model: ${device.model()}`); +console.log(`Serial: ${device.serial()}`); +//read contacts form excel +await commandor.loadPage(); +// Take screenshot of the whole device. +// })(); \ No newline at end of file diff --git a/package.json b/package.json index 7cd9d9d..234145b 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,10 @@ "start": "node main.js" }, "dependencies": { + "axios": "^0.27.2", + "mongodb": "^4.9.1", + "mongoose": "^6.5.4", + "node-xlsx": "^0.21.0", "playwright": "1.23.0" } } diff --git a/src/device.png b/src/device.png new file mode 100644 index 0000000..e48e67a Binary files /dev/null and b/src/device.png differ diff --git a/src/excel/ExcelUtil.js b/src/excel/ExcelUtil.js new file mode 100644 index 0000000..7a26212 --- /dev/null +++ b/src/excel/ExcelUtil.js @@ -0,0 +1,31 @@ +const xlsx = require('node-xlsx'); +const ContactPojo = require("../models/ContactPojo"); + +class ExcelUtil { + + readContacts() { + let workSheetsFromFile = xlsx.parse('/Users/lpan/Desktop/contact_all.xlsx'); + console.log(workSheetsFromFile); + // return a list of contactPojo + let contactList = []; + workSheetsFromFile[0].data.forEach( + (info, index, list) => { + // console.log("info:" + info) + // console.log("index:" + index) + if (index > 0) { + let name = info[0].split(" ") + let firstName = name[1]; + let lastName = name[0]; + let phoneNumber = info[1]; + let passportNumber = info[2]; + let mail = info[3]; + let newContact = new ContactPojo(phoneNumber, passportNumber, lastName, firstName, mail); + contactList.push(newContact); + } + } + ) + return contactList; + } +} + +module.exports = ExcelUtil diff --git a/src/models/ContactPojo.js b/src/models/ContactPojo.js new file mode 100644 index 0000000..7f61a42 --- /dev/null +++ b/src/models/ContactPojo.js @@ -0,0 +1,14 @@ +class ContactPojo { + + constructor(phoneNumber, passportNumber, lastName, firstName, mail) { + this.phoneNumber = phoneNumber; + this.passportNumber = passportNumber; + this.lastName = lastName; + this.firstName = firstName; + this.mail = mail; + } + + +} + +module.exports = ContactPojo \ No newline at end of file diff --git a/src/models/PublishType.js b/src/models/PublishType.js new file mode 100644 index 0000000..f234e47 --- /dev/null +++ b/src/models/PublishType.js @@ -0,0 +1,6 @@ +const PublishType = { + SUCCESS: "SUCCESS", + ERROR: "ERROR", + PENDING: "PENDING", + DUPLICATED: "DUPLICATED", +} \ No newline at end of file diff --git a/src/models/ReserveResultPojo.js b/src/models/ReserveResultPojo.js new file mode 100644 index 0000000..524254f --- /dev/null +++ b/src/models/ReserveResultPojo.js @@ -0,0 +1,32 @@ +class ReserveResultPojo { + constructor(id, phoneNumber, passportNumber, mail, lastName, firstName, storeType, url) { + this.id = id; + this.phoneNumber = phoneNumber; + this.passportNumber = passportNumber; + this.firstName = firstName; + this.lastName = lastName; + this.storeType = storeType; + this.url = url; + this.mail = mail; + } + + to_mongo_dict() { + return { + id: this.id, + phone: this.phoneNumber, + firstName: this.firstName, + lastName: this.lastName, + email: this.mail, + passport: this.passportNumber, + url: this.url, + store_type: this.storeType + } + } + + static create_from_contact(contactPojo, id, url, storeType) { + return new ReserveResultPojo(id, contactPojo.phoneNumber, contactPojo.passportNumber, contactPojo.mail, contactPojo.lastName, contactPojo.firstName, storeType, url); + } + +} + +module.exports = ReserveResultPojo \ No newline at end of file diff --git a/src/page.png b/src/page.png new file mode 100644 index 0000000..7bd9578 Binary files /dev/null and b/src/page.png differ diff --git a/src/workers/CommandorPage.js b/src/workers/CommandorPage.js new file mode 100644 index 0000000..01c08a2 --- /dev/null +++ b/src/workers/CommandorPage.js @@ -0,0 +1,193 @@ +const {_android: android} = require("playwright"); +const SolveCaptcha = require("./SolveCaptcha"); + +// const RDV_URL = "http://192.168.0.44:8000/test_appointment.html" +const RDV_URL = "https://rendezvousparis.hermes.com/client/register"; + +const COUNTRY_ID = "#phone_country" +const PHONE_NUMBER = "#phone_number" +const EMAIL_ID = "#email" +const PREFER_STORE = "#prefer" +const LAST_NAME = "#surname" +const FIRST_NAME = "#name" +const CGU_ID = "#cgu" +const PROCESSING_ID = "#processing" +const PASSPORT_ID = "#passport_id" + +const CONFIRMED_MESSAGE = "Your request for a Leather Goods appointment has been registered" +const CONFIRMED_MESSAGE_FR = "Votre demande de rendez-vous Maroquinerie a bien été enregistrée et nous vous en remercions." +const MESSAGE_URL_VALIDATION_FR = "Nous avons envoyé un lien par e-mail." +const DOUBLE_REQUEST_ERROR_MESSAGE = "A request with the same data has already been validated today." +const DOUBLE_REQUEST_ERROR_MESSAGE_FR = "Une demande avec les données saisies a déjà été validée aujourd’hui." +const TOO_MANY_REQUEST_ERROR_MESSAGE = "Due to a large number of requests" +const TOO_MANY_REQUEST_ERROR_MESSAGE_FR = "Suite à un trop grand nombre de demandes" +const CAPTCHA_ERROR_MESSAGE = "Error verifying captcha, please try again" +const CAPTCHA_ERROR_MESSAGE_FR = "La vérification du captcha a échoué" + +function delay(delayInms) { + return new Promise(resolve => { + setTimeout(() => { + resolve(2); + }, delayInms); + }); +} + +function getRandom() { + return Math.floor(Math.random() * 5); +} + +function getRandomWaitTime() { + return getRandom() * 1000 +} + +class CommandorPage { + constructor(contact) { + this.contact = contact; + } + + async loadPage() { + // Connect to the device. + const [device] = await android.devices(); + console.log(`Model: ${device.model()}`); + console.log(`Serial: ${device.serial()}`); + { + // --------------------- Browser ----------------------- + // Launch Chrome browser. + await device.shell('am force-stop com.android.chrome'); + const context = await device.launchBrowser({command: '--incognito'}); + + // Use BrowserContext as usual. + const page = await context.newPage(); + this.page = page + page.on("load", this.onPageLoad) + await page.goto(RDV_URL); + // await this.fillFields(page) + console.log(await page.evaluate(() => window.location.href)); + //wait 10 mins + await delay(10 * 60 * 1000); + } + + // Close the device. + await device.close(); + } + + async chooseCountry(page) { + await page.locator(COUNTRY_ID).focus(); + await delay(getRandomWaitTime()) + await page.click(COUNTRY_ID); + await delay(getRandomWaitTime()) + await page.selectOption(COUNTRY_ID, 'FR'); + await delay(getRandomWaitTime()) + await page.click(COUNTRY_ID); + } + + async fillEmail(page) { + await page.locator(EMAIL_ID).focus(); + await delay(getRandomWaitTime()) + await page.locator(EMAIL_ID).fill(this.contact.mail); + } + + async inputPhoneNumber(page) { + await page.locator(PHONE_NUMBER).focus() + await page.locator(PHONE_NUMBER).fill("0" + this.contact.phoneNumber) + } + + async inputName(page) { + await page.locator(LAST_NAME).focus() + await delay(getRandomWaitTime()) + await page.locator(LAST_NAME).fill(this.contact.lastName) + await page.locator(FIRST_NAME).focus() + await delay(getRandomWaitTime()) + await page.locator(FIRST_NAME).fill(this.contact.firstName) + } + + async inputPassportId(page) { + await page.locator(PASSPORT_ID).focus() + await delay(getRandomWaitTime()) + await page.locator(PASSPORT_ID).fill(this.contact.passportNumber.toString()) + } + + async checkCGU(page) { + await page.locator(CGU_ID).focus() + await page.locator(CGU_ID).click() + await delay(getRandomWaitTime()) + await page.locator(PROCESSING_ID).focus() + await page.locator(PROCESSING_ID).click() + } + + async chooseStore(page) { + await page.locator(PREFER_STORE).focus() + await delay(1000) + await page.click(PREFER_STORE); + await page.selectOption(PREFER_STORE, "faubourg"); + await page.click(PREFER_STORE); + } + + + async fillFields(page) { + await this.chooseStore(page) + await this.inputName(page) + await this.chooseCountry(page); + await this.inputPhoneNumber(page) + await this.fillEmail(page) + await this.inputPhoneNumber(page) + await this.inputPassportId(page) + await this.checkCGU(page) + await this.resolveCaptcha(page) + await delay(100 * 1000) + } + + async clickValid(page) { + await delay(getRandomWaitTime()) + try { + page.evaluate(() => { + document.getElementsByClassName("btn")[0].focus(); + }) + await delay(getRandomWaitTime()) + page.evaluate(() => { + document.getElementsByClassName("btn")[0].click(); + }) + } catch (e) { + console.log(e) + } + } + + async resolveCaptcha(page) { + this.captchaSolver = new SolveCaptcha(page); + await this.captchaSolver.start((solution) => { + console.log("solution is: " + solution); + page.evaluate((solution) => { + document.getElementById("g-recaptcha-response").innerHTML = solution; + }, solution) + this.clickValid() + }) + } + + async onPageLoad() { + let content = await this.page.content(); + let captcha_url = "geo.captcha-delivery.com/captcha" + + if (content.toString().includes(captcha_url)) { + console.log("we are blockeds") + } else { + if (this.page.url() === RDV_URL) { + await this.fillFields() + } else { + if (content.includes(MESSAGE_URL_VALIDATION_FR)) { + console.log("successful") + this.push_message_to_queue(PublishType.SUCCESS) + } + } + } + } + + push_message_to_queue(publishType) { + let url = this.page.url() + if (url === "https://rendezvousparis.hermes.com/client/welcome") { + return + } + + } +} + +module.exports = CommandorPage \ No newline at end of file diff --git a/src/workers/SolveCaptcha.js b/src/workers/SolveCaptcha.js new file mode 100644 index 0000000..0b73c82 --- /dev/null +++ b/src/workers/SolveCaptcha.js @@ -0,0 +1,65 @@ +const axios = require("axios"); +const CAPCHA_NOT_READY = "CAPCHA_NOT_READY"; +const REGEX_DATA_SITE_KEY = "data-sitekey=[\"a-z0-9A-Z]+"; +const API_KEY = "d66aaf490d8aa424a5175e1fbd1aadea"; +const SITE_KEY = "6LdUViwUAAAAAOBJjtMsmKc9C7200Djd31w2mCs7"; + +function delay(delayInms) { + return new Promise(resolve => { + setTimeout(() => { + resolve(2); + }, delayInms); + }); +} + +class SolveCaptcha { + + constructor(page) { + this.page = page; + } + + async start(handle_solution_received) { + await this.solve_captcha(SITE_KEY, handle_solution_received) + } + + async solve_captcha(site_key, handle_solution_received) { + console.log("solve_captcha(), for " + this.page.url()) + let url_get = `http://2captcha.com/in.php?key=${API_KEY}&method=userrecaptcha&googlekey=${site_key}&pageurl=${this.page.url()}`; + + let res = await axios.get(url_get) + console.log(`statusCode: ${res.status}`); + console.log(res); + let results = res.data.split("|"); + this.captcha_id = results[1]; + let solution = CAPCHA_NOT_READY; + let status_code = 1; + await delay(15 * 1000) + while (solution === CAPCHA_NOT_READY || status_code !== 200) { + await this.get_solution(this.captcha_id, (status, sol) => { + status_code = status; + solution = sol + }) + await delay(5 * 1000) + } + handle_solution_received(solution) + } + + async get_solution(catcha_id, onSolutionFound) { + console.log("get_solution() called") + let url_response = `http://2captcha.com/res.php?key=${API_KEY}&action=get&id=${catcha_id}`; + let res = await axios.get(url_response) + console.log(`statusCode: ${res.status}`); + console.log(res); + let results = res.data.split("|"); + let solution + if (results.length > 1) + solution = results[1]; + else { + solution = results[0] + } + onSolutionFound(res.status, solution) + await delay(5 * 1000) + } +} + +module.exports = SolveCaptcha \ No newline at end of file diff --git a/src/workers/mongo_manager.js b/src/workers/mongo_manager.js new file mode 100644 index 0000000..4faba7a --- /dev/null +++ b/src/workers/mongo_manager.js @@ -0,0 +1,65 @@ +const MONGO_DB_URL = "mongo.lpaconsulting.fr" +const CAPTCHA_ERROR_COLLECTION_PREFIX = "CAPTCHA_ERROR_" +const BLACK_LIST = "BLACK_LIST" +const DB_NAME = "appointment" +const COLLECTION_NAME = "appointment" +const ACCEPTED_APPOINTMENT_LIST = "ACCEPTED_APPOINTMENT_LIST" +const EMAIL_LIST = "EMAIL_LIST" +const DESTINATION_EMAIL_LIST = "DESTINATION_EMAIL_LIST" + + +const mongoose = require("mongoose"); +mongoose.Promise = global.Promise; +mongoose.connect(`mongodb://${MONGO_DB_URL}:27017/appointment`); + +const {MongoClient} = require('mongodb'); +const ReserveResultPojo = require("../models/ReserveResultPojo"); +const ContactPojo = require("../models/ContactPojo"); + +function formatDate(date) { + let d = new Date(date), + month = '' + (d.getMonth() + 1), + day = '' + d.getDate(), + year = d.getFullYear(); + + if (month.length < 2) + month = '0' + month; + if (day.length < 2) + day = '0' + day; + + return [year, month, day].join('-'); +} + +class MongoManager { + constructor() { + //init mongoDb + let uri = `mongodb://appointment:Rdv%402022@${MONGO_DB_URL}/appointment` + this.client = new MongoClient(uri) + } + + async connect() { + await this.client.connect() + this.db = this.client.db("appointment") + } + + async getAllSuccessfulItemsForDay(day) { + return await this.db.collection(day).find().toArray() + } + + async saveReserveToDb(reservePojo) { + let collectionName = formatDate(new Date()) + return await this.db.collection(collectionName).replaceOne({'_id': reservePojo.id,}, reservePojo, {upsert: true}) + } +} + +let manag = new MongoManager(); +(async () => { + await manag.connect() + // console.log(await manag.getAllSuccessfulItemsForDay('2022-09-06')) + // let reserv = new ReserveResultPojo('U4S4RN', '753426925', '84838026', "gnautaurasa@hotmail.com", 'jingyi', 'DU', 1, 'https://rendezvousparis.hermes.com/client/register/U4S4RN'); + let contact = new ContactPojo('753426925', '84838026', 'DU', 'jingyi', + "gnautaurasa@hotmail.com" + ); + let reserv = ReserveResultPojo.create_from_contact(contact, 'U4S4RN', 'https://rendezvousparis.hermes.com/client/register/U4S4RN', 1) + await manag.saveReserveToDb(reserv.to_mongo_dict()); +})() diff --git a/yarn.lock b/yarn.lock index 0753901..e4fb968 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,242 @@ # yarn lockfile v1 +"@types/node@*": + version "18.7.15" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.15.tgz#20ae1ec80c57ee844b469f968a1cd511d4088b29" + integrity sha512-XnjpaI8Bgc3eBag2Aw4t2Uj/49lLBSStHWfqKvIuXD7FIrZyMLWp8KuAFHAqxMZYTF9l08N1ctUn9YNybZJVmQ== + +"@types/webidl-conversions@*": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz#2b8e60e33906459219aa587e9d1a612ae994cfe7" + integrity sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog== + +"@types/whatwg-url@^8.2.1": + version "8.2.2" + resolved "https://registry.yarnpkg.com/@types/whatwg-url/-/whatwg-url-8.2.2.tgz#749d5b3873e845897ada99be4448041d4cc39e63" + integrity sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA== + dependencies: + "@types/node" "*" + "@types/webidl-conversions" "*" + +adler-32@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/adler-32/-/adler-32-1.2.0.tgz#6a3e6bf0a63900ba15652808cb15c6813d1a5f25" + integrity sha512-/vUqU/UY4MVeFsg+SsK6c+/05RZXIHZMGJA+PX5JyWI0ZRcBpupnRuPLU/NXXoFwMYCPCoxIfElM2eS+DUXCqQ== + dependencies: + exit-on-epipe "~1.0.1" + printj "~1.1.0" + +adler-32@~1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/adler-32/-/adler-32-1.3.1.tgz#1dbf0b36dda0012189a32b3679061932df1821e2" + integrity sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +axios@^0.27.2: + version "0.27.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972" + integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== + dependencies: + follow-redirects "^1.14.9" + form-data "^4.0.0" + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +bson@^4.6.5, bson@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/bson/-/bson-4.7.0.tgz#7874a60091ffc7a45c5dd2973b5cad7cded9718a" + integrity sha512-VrlEE4vuiO1WTpfof4VmaVolCVYkYTgB9iWgYNOrVlnifpME/06fhFRmONgBhClD5pFC1t9ZWqFUQEQAzY43bA== + dependencies: + buffer "^5.6.0" + +buffer@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +cfb@^1.1.4: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cfb/-/cfb-1.2.2.tgz#94e687628c700e5155436dac05f74e08df23bc44" + integrity sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA== + dependencies: + adler-32 "~1.3.0" + crc-32 "~1.2.0" + +codepage@~1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/codepage/-/codepage-1.15.0.tgz#2e00519024b39424ec66eeb3ec07227e692618ab" + integrity sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +crc-32@~1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" + integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== + +debug@4.x: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +denque@^2.0.1, denque@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/denque/-/denque-2.1.0.tgz#e93e1a6569fb5e66f16a3c2a2964617d349d6ab1" + integrity sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw== + +exit-on-epipe@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz#0bdd92e87d5285d267daa8171d0eb06159689692" + integrity sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw== + +follow-redirects@^1.14.9: + version "1.15.1" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5" + integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA== + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +frac@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/frac/-/frac-1.1.2.tgz#3d74f7f6478c88a1b5020306d747dc6313c74d0b" + integrity sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA== + +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +ip@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" + integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== + +kareem@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.4.1.tgz#7d81ec518204a48c1cb16554af126806c3cd82b0" + integrity sha512-aJ9opVoXroQUPfovYP5kaj2lM7Jn02Gw13bL0lg9v0V7SaUc0qavPs0Eue7d2DcC3NjqI6QAUElXNsuZSeM+EA== + +memory-pager@^1.0.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" + integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg== + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mongodb-connection-string-url@^2.5.2, mongodb-connection-string-url@^2.5.3: + version "2.5.3" + resolved "https://registry.yarnpkg.com/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.3.tgz#c0c572b71570e58be2bd52b33dffd1330cfb6990" + integrity sha512-f+/WsED+xF4B74l3k9V/XkTVj5/fxFH2o5ToKXd8Iyi5UhM+sO9u0Ape17Mvl/GkZaFtM0HQnzAG5OTmhKw+tQ== + dependencies: + "@types/whatwg-url" "^8.2.1" + whatwg-url "^11.0.0" + +mongodb@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-4.8.1.tgz#596de88ff4519128266d9254dbe5b781c4005796" + integrity sha512-/NyiM3Ox9AwP5zrfT9TXjRKDJbXlLaUDQ9Rg//2lbg8D2A8GXV0VidYYnA/gfdK6uwbnL4FnAflH7FbGw3TS7w== + dependencies: + bson "^4.6.5" + denque "^2.0.1" + mongodb-connection-string-url "^2.5.2" + socks "^2.6.2" + optionalDependencies: + saslprep "^1.0.3" + +mongodb@^4.9.1: + version "4.9.1" + resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-4.9.1.tgz#0c769448228bcf9a6aa7d16daa3625b48312479e" + integrity sha512-ZhgI/qBf84fD7sI4waZBoLBNJYPQN5IOC++SBCiPiyhzpNKOxN/fi0tBHvH2dEC42HXtNEbFB0zmNz4+oVtorQ== + dependencies: + bson "^4.7.0" + denque "^2.1.0" + mongodb-connection-string-url "^2.5.3" + socks "^2.7.0" + optionalDependencies: + saslprep "^1.0.3" + +mongoose@^6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-6.5.4.tgz#05c57c569d919fb55e656df1e49735a931fdc647" + integrity sha512-8hKV+9baDa7fyWRADQcSN/c0/QQbnewA2D0xOqdFb7f1UGYAHk4YSMNu9Hu2bdRUfQbK/daFuqlcmI17j6/8eg== + dependencies: + bson "^4.6.5" + kareem "2.4.1" + mongodb "4.8.1" + mpath "0.9.0" + mquery "4.0.3" + ms "2.1.3" + sift "16.0.0" + +mpath@0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.9.0.tgz#0c122fe107846e31fc58c75b09c35514b3871904" + integrity sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew== + +mquery@4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/mquery/-/mquery-4.0.3.tgz#4d15f938e6247d773a942c912d9748bd1965f89d" + integrity sha512-J5heI+P08I6VJ2Ky3+33IpCdAvlYGTSUjwTPxkAr8i8EoduPMBX2OY/wa3IKZIQl7MU4SbFk8ndgSKyB/cl1zA== + dependencies: + debug "4.x" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +node-xlsx@^0.21.0: + version "0.21.0" + resolved "https://registry.yarnpkg.com/node-xlsx/-/node-xlsx-0.21.0.tgz#085d69869d7fa7ed1e6d2a13eee6aa6dce7867a1" + integrity sha512-MB+KcNCuRzwjgr17scpKiVTPd4Vbj3V+7QwKpqACGyJzhvC67xCQUbw2vYEIKtNfMfcLxgB2q2kEuRS8rmak9g== + dependencies: + xlsx "^0.17.4" + playwright-core@1.23.0: version "1.23.0" resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.23.0.tgz#51e24121b3a5bbe759d79738d8eff7a63156293c" @@ -13,3 +249,95 @@ playwright@1.23.0: integrity sha512-rfZfuLueBPGV3UdEqPQxS8Uw7TgVMATWSPb3O0oV8SZBmVAhOndkOU9MPP8dxJoQI68r94yevuObPr14PhW9Xg== dependencies: playwright-core "1.23.0" + +printj@~1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222" + integrity sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ== + +punycode@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +saslprep@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226" + integrity sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag== + dependencies: + sparse-bitfield "^3.0.3" + +sift@16.0.0: + version "16.0.0" + resolved "https://registry.yarnpkg.com/sift/-/sift-16.0.0.tgz#447991577db61f1a8fab727a8a98a6db57a23eb8" + integrity sha512-ILTjdP2Mv9V1kIxWMXeMTIRbOBrqKc4JAXmFMnFq3fKeyQ2Qwa3Dw1ubcye3vR+Y6ofA0b9gNDr/y2t6eUeIzQ== + +smart-buffer@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== + +socks@^2.6.2, socks@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.7.0.tgz#f9225acdb841e874dca25f870e9130990f3913d0" + integrity sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA== + dependencies: + ip "^2.0.0" + smart-buffer "^4.2.0" + +sparse-bitfield@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11" + integrity sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ== + dependencies: + memory-pager "^1.0.2" + +ssf@~0.11.2: + version "0.11.2" + resolved "https://registry.yarnpkg.com/ssf/-/ssf-0.11.2.tgz#0b99698b237548d088fc43cdf2b70c1a7512c06c" + integrity sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g== + dependencies: + frac "~1.1.2" + +tr46@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-3.0.0.tgz#555c4e297a950617e8eeddef633c87d4d9d6cbf9" + integrity sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA== + dependencies: + punycode "^2.1.1" + +webidl-conversions@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" + integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== + +whatwg-url@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-11.0.0.tgz#0a849eebb5faf2119b901bb76fd795c2848d4018" + integrity sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ== + dependencies: + tr46 "^3.0.0" + webidl-conversions "^7.0.0" + +wmf@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wmf/-/wmf-1.0.2.tgz#7d19d621071a08c2bdc6b7e688a9c435298cc2da" + integrity sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw== + +word@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/word/-/word-0.3.0.tgz#8542157e4f8e849f4a363a288992d47612db9961" + integrity sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA== + +xlsx@^0.17.4: + version "0.17.5" + resolved "https://registry.yarnpkg.com/xlsx/-/xlsx-0.17.5.tgz#78b788fcfc0773d126cdcd7ea069cb7527c1ce81" + integrity sha512-lXNU0TuYsvElzvtI6O7WIVb9Zar1XYw7Xb3VAx2wn8N/n0whBYrCnHMxtFyIiUU1Wjf09WzmLALDfBO5PqTb1g== + dependencies: + adler-32 "~1.2.0" + cfb "^1.1.4" + codepage "~1.15.0" + crc-32 "~1.2.0" + ssf "~0.11.2" + wmf "~1.0.1" + word "~0.3.0"