commit 4bf61e4ecbeb0e8d25546adbf0c9a102723ef340 Author: Martin Minka Date: Sat Jun 18 14:55:04 2022 +0200 add person-as-list diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1fe1b00 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea/ +node_modules/ diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..4d21f34 --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +nodejs 18.4.0 diff --git a/README.md b/README.md new file mode 100644 index 0000000..1edc27d --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +Git clone and install packages with `yarn`. + +Populate database: + +``` +# show command line parameters +node bin/populate-vikunja.js + +# only 100 lists - that works fine +node bin/populate-vikunja.js person-as-list -s /tmp/GoLand/___go_build_code_vikunja_io_api --delete-db + +# generate 10.000 lists - this is problem to handle by UI +node bin/populate-vikunja.js person-as-list -s /tmp/GoLand/___go_build_code_vikunja_io_api --delete-db -c 10000 +``` diff --git a/bin/populate-vikunja.js b/bin/populate-vikunja.js new file mode 100644 index 0000000..33415a7 --- /dev/null +++ b/bin/populate-vikunja.js @@ -0,0 +1,74 @@ +import yargs from 'yargs' +import { hideBin } from 'yargs/helpers' +import { startVikunja, initClient } from '../src/vikunja.js' +import personAsList from '../src/person-as-list.js' +import { keypress } from '../src/utils.js' + +function addGlobal (yargs) { + yargs + .option('startVikunja', { + alias: 's', + description: 'Vikinja binary to be started before data are populated or Vikunja has to be started manually' + }) + .option('workDir', { + description: 'directory where Sqlite database will be created if startVikunja was provided, default is folder with Vikunja binary' + }) + .option('deleteDb', { + 'description': 'WARNING! Database will be delete before Vikunja will be started' + }) + .option('jwtsecret', { + default: 'C519352B2E9FFBADD92AE5BC63D26A42FC334418373150F8137618EC1F7459D3' + }) + .option('user', { + alias: 'u', + default: 'demo' + }) + .option('password', { + alias: 'P', + default: 'demo' + }) + .option('baseUrl', { + default: 'http://localhost:3456' + }) + + return yargs +} + +async function startVikunjaFromArgv (argv) { + if (argv.startVikunja) { + return startVikunja(argv.startVikunja, argv.jwtsecret, argv.workDir, argv.deleteDb).then(() => true) + } + + return false +} + +function initClientFromArgv (wasStarted, argv) { + return initClient(argv.baseUrl, argv.user, argv.password, wasStarted) +} + +yargs(hideBin(process.argv)) + .command( + '$0 person-as-list', + 'will populate Vikunja tasks with persons as lists', + yargs => { + addGlobal(yargs) + .option('count', { + alias: 'c', + default: 100 + }) + }, + async argv => { + const wasStarted = await startVikunjaFromArgv(argv) + await personAsList(await initClientFromArgv(wasStarted, argv), argv.count) + + if (wasStarted) { + console.log('population done, press any key to quit') + await keypress() + process.exit() + } + } + ) + .demandCommand(1) + .help() + .parse() + diff --git a/package.json b/package.json new file mode 100644 index 0000000..10eff1c --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "populate-db", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "type": "module", + "dependencies": { + "@faker-js/faker": "^7.2.0", + "axios": "^0.27.2", + "fs-extra": "^10.1.0", + "moment": "^2.29.3", + "swedish-ssn-generator": "^1.0.1", + "weighted-random-distribution": "^1.2.2", + "yargs": "^17.5.1" + } +} diff --git a/src/person-as-list.js b/src/person-as-list.js new file mode 100644 index 0000000..7552908 --- /dev/null +++ b/src/person-as-list.js @@ -0,0 +1,183 @@ +import { faker } from '@faker-js/faker/locale/sk' +import SwedishSSN from 'swedish-ssn-generator' +import { inPlaceUnsorted } from 'weighted-random-distribution' +import moment from 'moment' +import { between } from './utils.js' + +async function populate (client, personCount) { + function createRandomPerson () { + const gender = between(0, 1) ? 'male' : 'female' + const p = { + // userId: faker.datatype.uuid(), + // username: faker.internet.userName(), + // email: faker.internet.email(), + // avatar: faker.image.avatar(), + // password: faker.internet.password(), + birthdate: faker.date.birthdate(), + name: faker.name.findName(undefined, undefined, gender) + // registeredAt: faker.date.past() + } + p.rc = SwedishSSN.generateSSNWithParameters(p.birthdate, gender).replace('-', '') + return p + } + + async function insertLabel (title) { + try { + const d = (await client.put( + `/labels`, + { + title + } + )).data + + return d.id + } catch (ex) { + console.log(ex) + process.exit() + return false + } + } + + function createTask (date, past = false) { + const t = { + start_date: date, + title: faker.hacker.phrase() // faker.lorem.sentence() + } + + if (inPlaceUnsorted({ + 0: 95, + 1: 5 + }) * 1) { + // priority + t.priority = 4 + } + + if (inPlaceUnsorted({ + 0: 95, + 1: 5 + }) * 1) { + // reminder + t.reminder_dates = [moment(date).add(-3, 'day')] + } + + // label + const label = inPlaceUnsorted(MY_LABELS) + if (label) { + console.log(label) + t.labels = [{ id: label * 1 }] + if (label * 1 === 1) { // recept + if (1 * inPlaceUnsorted({ + 0: 30, + 1: 70 + })) { + // repeat + t.title = 'REPEAT: ' + t.title + t.repeat_after = 60 * 60 * 24 * 30 * 3 + t.repeat_mode = 0 + } + } + } + + if ((past && 1 * inPlaceUnsorted({ + 0: 30, + 1: 70 + })) || 1 * inPlaceUnsorted({ + 0: 95, + 1: 5 + })) { + // done + t.done = true + } + + if (1 * inPlaceUnsorted({ + 0: 5, + 1: 95 + })) { + // due + t.due_date = date + } + + return t + } + + async function insertTask (listId, task) { + try { + let labels + if (task.labels) { + // BUG this is workarround because create task with labels will not insert the labels + labels = task.labels + delete task.labels + } + + const d = (await client.put( + `/lists/${listId}`, + task + )).data + + if (labels) { + await client.post( + `/tasks/${d.id}/labels/bulk`, + { labels } + ) + } + + return d.id + } catch (ex) { + console.log(ex) + process.exit() + return false + } + } + + async function insertPerson (person) { + // const d = (await client.get(`/namespaces/${namespace}/lists`)).data + // console.log(d) + try { + const d = (await client.put( + `/namespaces/${namespace}/lists`, + { + title: person.name, + identifier: person.rc + } + )).data + + return d.id + } catch (ex) { + console.log(ex) + return false + } + } + + const namespace = 1 + + // prepare labels + const MY_LABELS = { '': 20 } + MY_LABELS[await insertLabel('recept')] = 45 + MY_LABELS[await insertLabel('kontrola')] = 20 + MY_LABELS[await insertLabel('krv')] = 10 + MY_LABELS[await insertLabel('FOB')] = 5 + + for (let i = 0; i < personCount; i++) { + const person = createRandomPerson() + const pId = await insertPerson(person) + if (pId === false) continue + + // lists, sqlite_sequence, tasks + + // past dates + for (let c = 0; c < between(0, 20); c++) { + await insertTask(pId, createTask(faker.date.past(), true)) + } + + // future dates + for (let c = 0; c < between(0, 5); c++) { + const soon = 1 * inPlaceUnsorted({ + 0: 70, + 1: 30 + }) + await insertTask(pId, createTask(soon ? faker.date.soon(5) : faker.date.future())) + } + } +} + +export default populate diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..b8b7604 --- /dev/null +++ b/src/utils.js @@ -0,0 +1,13 @@ +export async function keypress () { + process.stdin.setRawMode(true) + return new Promise(resolve => process.stdin.once('data', () => { + process.stdin.setRawMode(false) + resolve() + })) +} + +export function between (min, max) { + return Math.floor( + Math.random() * (max - min + 1) + min + ) +} diff --git a/src/vikunja.js b/src/vikunja.js new file mode 100644 index 0000000..7d17919 --- /dev/null +++ b/src/vikunja.js @@ -0,0 +1,78 @@ +import axios from 'axios' +import path from 'path' +import fs from 'fs-extra' +import { spawn } from 'child_process' + +export function startVikunja (bin, jwtSecret, workDir = false, deleteDb = false) { + if (!workDir) { + workDir = path.dirname(bin) + } + + if (deleteDb) { + // clear the database + try { + fs.unlinkSync(path.join(workDir, 'vikunja.db')) + } catch (_) { + // ignore error + } + } + + return new Promise(resolve => { + const vikunja = spawn( + bin, + [], + { + cwd: workDir, + env: { + VIKUNJA_SERVICE_JWTSECRET: jwtSecret + } + } + ) + vikunja.stdout.on('data', (data) => { + data = data.toString() + console.log(data) + if (data.indexOf(' cmd/func25') !== -1) { + console.log('Vikunja started, will proceed with data population...') + setTimeout(() => resolve(), 1000) + } + }) + }) +} + +export async function initClient (baseURL, username, password, registerUser) { + if (registerUser) { + await axios.post( + baseURL + '/api/v1/register', + { + username, + password, + email: 'demo@example.com' + }, + { + headers: { + 'Content-Type': 'application/json' + } + } + ) + } + + // login + const bearer = (await axios.post( + baseURL + '/api/v1/login', + { + username, + password + }, + { + headers: { + 'Content-Type': 'application/json' + } + } + )).data.token + +// prepare client + return axios.create({ + baseURL: baseURL + '/api/v1/', + headers: { 'Authorization': 'Bearer ' + bearer } + }) +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..2e5e321 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,227 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@faker-js/faker@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@faker-js/faker/-/faker-7.2.0.tgz#c5fe4c34f3a3664ac64fe1a21bac2004ea5faa22" + integrity sha512-dzjQ0LFT+bPLWg0yyV3MpxaLJp/+VW4a0SnjNSWJ4YpJ928LXDOZAN+kB2/JPPisI3Ra0w2BxbD4M9J7o0jcpw== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +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" + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +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" + +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== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +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" + +fs-extra@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" + integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +graceful-fs@^4.1.6, graceful-fs@^4.2.0: + version "4.2.10" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonschema@^1.2.6: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.4.1.tgz#cc4c3f0077fb4542982973d8a083b6b34f482dab" + integrity sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ== + +lodash.findkey@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.findkey/-/lodash.findkey-4.6.0.tgz#83058e903b51cbb759d09ccf546dea3ea39c4718" + integrity sha512-Y+f2R8KsUDJVqdfeai01P5A1IQeMWsMG1p0rghzdhIl7TIap47Y2Z5UJK8x4pstixNL56KVHFRE1IW9jvRwy4g== + +lodash.reduce@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b" + integrity sha512-6raRe2vxCYBhpBu+B+TtNGUzah+hQjVdu3E17wfusjyrXBka2nBS8OH/gjVZ5PvHOhWmIZTYri09Z6n/QfnNMw== + +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" + +moment@^2.29.3: + version "2.29.3" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.3.tgz#edd47411c322413999f7a5940d526de183c031f3" + integrity sha512-c6YRvhEo//6T2Jz/vVtYzqBzwvPT95JBQ+smCytzf7c50oMZRsR/a4w88aD34I+/QVSfnoAnSBFPJHItlOMJVw== + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + 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" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +swedish-ssn-generator@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/swedish-ssn-generator/-/swedish-ssn-generator-1.0.1.tgz#3cb4aa13752f0a7e45fbd357620dffc1df2e6f18" + integrity sha512-1erBS/U3l0o+59OP/j1TgUTuZTZaERanbBvunWWAw6HwhOyR7TBSeycQg9TQyDTbzcDwd87Az7UyXI8SxtGo9Q== + +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + +weighted-random-distribution@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/weighted-random-distribution/-/weighted-random-distribution-1.2.2.tgz#b0348672a900362cfc1875069f745e31120d80d3" + integrity sha512-HQnugvf7e26AAWcVPbUEci8eEgRJk9oMbuhHP7IRWftFTF5uX16jXbFtu6Vkmt7rBHTjePgZKturt3jtbgG09w== + dependencies: + jsonschema "^1.2.6" + lodash.findkey "^4.6.0" + lodash.reduce "^4.6.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yargs-parser@^21.0.0: + version "21.0.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.1.tgz#0267f286c877a4f0f728fceb6f8a3e4cb95c6e35" + integrity sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg== + +yargs@^17.5.1: + version "17.5.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e" + integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA== + 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"