update: worker pool for concurrency and new spec

This commit is contained in:
Mohamed Sohail 2022-03-31 13:02:53 +03:00
parent fe61ad7fac
commit 67b9242196
Signed by: kamikazechaser
GPG Key ID: 7DD45520C01CD85D
15 changed files with 244 additions and 255 deletions

4
.taprc
View File

@ -1,4 +0,0 @@
reporter: spec
comments: false
coverage: false
check-coverage: false

View File

@ -12,6 +12,7 @@
},
"dependencies": {
"phin": "^3.6.1",
"piscina": "^3.2.0",
"rangi": "^1.0.2"
}
}

View File

@ -1,113 +0,0 @@
const test = require("tap").test;
const rangi = require("rangi");
const lib = require("../../lib");
const conf = require("../../config");
test("Reset Pin", async (t) => {
t.before((t) => {
if (!process.env.CURRENT_PIN || !process.env.NEW_PIN) {
t.bailout("ENV not set");
}
});
const sessionId = lib.newSession();
const currentPin = process.env.CURRENT_PIN;
const newPin = process.env.NEW_PIN;
t.test("Display menu and Sarafu balance", async (t) => {
await lib.wait(conf.test.waitNextMenu);
const r = await lib.ussdClient(conf.user.ussdPhone, sessionId);
console.log(rangi.cyan(r.text));
t.equal(r.code, "CON");
t.match(r.text, /Balance/g);
t.end();
});
t.test("Go to My Accont menu", async (t) => {
await lib.wait(conf.test.waitNextMenu);
const r = await lib.ussdClient(conf.user.ussdPhone, sessionId, "3");
console.log(rangi.cyan(r.text));
t.equal(r.code, "CON");
t.match(r.text, /PIN options/g);
t.end();
});
t.test("Go to Pin options", async (t) => {
await lib.wait(conf.test.waitNextMenu);
const r = await lib.ussdClient(conf.user.ussdPhone, sessionId, "3*5");
console.log(rangi.cyan(r.text));
t.equal(r.code, "CON");
t.match(r.text, /Change my PIN/g);
t.end();
});
t.test("Start Pin Change", async (t) => {
await lib.wait(conf.test.waitNextMenu);
const r = await lib.ussdClient(conf.user.ussdPhone, sessionId, "3*5*1");
console.log(rangi.cyan(r.text));
t.equal(r.code, "CON");
t.match(r.text, /Enter current PIN/g);
t.end();
});
t.test("Enter current Pin", async (t) => {
await lib.wait(conf.test.waitNextMenu);
const r = await lib.ussdClient(
conf.user.ussdPhone,
sessionId,
`3*5*1*${currentPin}`
);
console.log(rangi.cyan(r.text));
t.equal(r.code, "CON");
t.match(r.text, /new four number PIN/g);
t.end();
});
t.test("Enter new Pin", async (t) => {
await lib.wait(conf.test.waitNextMenu);
const r = await lib.ussdClient(
conf.user.ussdPhone,
sessionId,
`3*5*1*${currentPin}*${newPin}`
);
console.log(rangi.cyan(r.text));
t.equal(r.code, "CON");
t.match(r.text, /new four number PIN again/g);
t.end();
});
t.test("Enter new Pin agin", async (t) => {
await lib.wait(conf.test.waitNextMenu);
const r = await lib.ussdClient(
conf.user.ussdPhone,
sessionId,
`3*5*1*${currentPin}*${newPin}*${newPin}`
);
console.log(rangi.cyan(r.text));
t.equal(r.code, "CON");
t.match(r.text, /Your request has been sent/g);
t.end();
});
t.test("Exit", async (t) => {
await lib.wait(conf.test.waitNextMenu);
const r = await lib.ussdClient(
conf.user.ussdPhone,
sessionId,
`3*5*1*${currentPin}*${newPin}*${newPin}*99`
);
console.log(rangi.cyan(r.text));
t.equal(r.code, "END");
t.match(r.text, /Thank/g);
t.end();
});
});

View File

@ -1,41 +0,0 @@
const test = require("tap").test;
const rangi = require("rangi");
const lib = require("../../lib");
const conf = require("../../config");
test("Display Sarafu", async (t) => {
const sessionId = lib.newSession();
t.plan(3);
t.test("Display menu and Sarafu balance", async (t) => {
await lib.wait(conf.test.waitNextMenu);
const r = await lib.ussdClient(conf.user.ussdPhone, sessionId);
console.log(rangi.cyan(r.text));
t.equal(r.code, "CON");
t.match(r.text, /Balance/g);
t.end();
});
t.test("Go to My Sarafu menu", async (t) => {
await lib.wait(conf.test.waitNextMenu);
const r = await lib.ussdClient(conf.user.ussdPhone, sessionId, "2");
console.log(rangi.cyan(r.text));
t.equal(r.code, "CON");
t.match(r.text, /SRF/g);
t.end();
});
t.test("Exit", async (t) => {
await lib.wait(conf.test.waitNextMenu);
const r = await lib.ussdClient(conf.user.ussdPhone, sessionId, "2*00");
console.log(rangi.cyan(r.text));
t.equal(r.code, "END");
t.match(r.text, /Thank/g);
t.end();
});
});

View File

@ -1,41 +0,0 @@
const test = require("tap").test;
const rangi = require("rangi");
const lib = require("../../lib");
const conf = require("../../config");
test("Initial Menu", async (t) => {
const sessionId = lib.newSession();
t.plan(3);
t.test("Display menu and Sarafu balance", async (t) => {
await lib.wait(conf.test.waitNextMenu);
const r = await lib.ussdClient(conf.user.ussdPhone, sessionId);
console.log(rangi.cyan(r.text));
t.equal(r.code, "CON");
t.match(r.text, /Balance/g);
t.end();
});
t.test("Go to help menu", async (t) => {
await lib.wait(conf.test.waitNextMenu);
const r = await lib.ussdClient(conf.user.ussdPhone, sessionId, "4");
console.log(rangi.cyan(r.text));
t.equal(r.code, "CON");
t.match(r.text, /assistance/g);
t.end();
});
t.test("Exit", async (t) => {
await lib.wait(conf.test.waitNextMenu);
const r = await lib.ussdClient(conf.user.ussdPhone, sessionId, "4*99");
console.log(rangi.cyan(r.text));
t.equal(r.code, "END");
t.match(r.text, /Thank/g);
t.end();
});
});

View File

@ -4,10 +4,5 @@ module.exports = {
endpoint: "https://ussd.grassecon.net",
timeout: 3000,
},
test: {
waitNextMenu: 3000,
},
user: {
ussdPhone: "254711777734",
},
defaultWaitNextMenu: 3000,
};

30
src/jobAllocator.js Normal file
View File

@ -0,0 +1,30 @@
const path = require("path");
const rangi = require("rangi");
const Piscina = require("piscina");
const parser = require("./specParser").parser;
const piscina = new Piscina({
filename: path.resolve(__dirname, "worker.js"),
});
(async function () {
const workload = parser();
console.log(
rangi.red(`number of piscina workers to be allocated: ${workload.length}`)
);
const parallelExecutor = [];
for (let i = 0; i < workload.length; i++) {
parallelExecutor.push(
piscina.run({
jobId: i,
tasks: workload[i],
})
);
}
await Promise.all(parallelExecutor);
})();

View File

@ -1,25 +0,0 @@
const setTimeout = require("timers/promises").setTimeout;
const readFile = require("fs").readFile;
const parseScenario = require("./builder").parseScenario;
const request = require("./request").request;
readFile(process.argv[2], "utf8", (err, data) => {
if (err) {
return console.log(err);
}
execute(data);
});
async function execute(input) {
const parsedScenarioFile = input.split("\n");
for (const work of parsedScenarioFile) {
const parsedWork = parseScenario(work);
for (const requestJob of parsedWork) {
await request(requestJob);
await setTimeout(requestJob.test.waitNextMenu);
}
}
}

View File

@ -1,4 +1,15 @@
# 254711777734
wait 5
reset_pin current_pin=2222,new_pin=3333
reset_pin current_pin=3333,new_pin=2222
send_tx to=0727806655,amount=1,pin=2222
send_tx to=0706533739,amount=1,pin=2222
send_tx to=0706533739,amount=1,pin=2222
send_tx to=0706533739,amount=0.55,pin=2222
# 254722741115
wait 2
reset_pin current_pin=2222,new_pin=3333
reset_pin current_pin=3333,new_pin=4444
# 254750123123
wait 15
send_tx to=0706533739,amount=1,pin=2222
wait 1
# END

46
src/scenarioBuilder.js Normal file
View File

@ -0,0 +1,46 @@
const crypto = require("crypto");
const scenario = require("./scenario");
const config = require("./config");
function builder(scenarioName, scenarioConfig, scenarioPhone) {
const scenes = [];
const builtScenario = scenario[scenarioName](scenarioConfig);
const sessionId = crypto.randomBytes(16).toString("hex");
for (const scene of builtScenario) {
scene.sessionId = sessionId;
scene.ussdPhone = scenarioPhone;
Object.assign(scene, config);
scenes.push(scene);
}
return scenes;
}
function parseScenario(scenarioPhone, scenarioString) {
const [scenarioName, scenarioConfig] = scenarioString.split(" ");
return builder(
scenarioName,
parseScenarioConfig(scenarioConfig),
scenarioPhone
);
}
function parseScenarioConfig(scenarioConfigString) {
const configs = scenarioConfigString.split(",");
const configObject = {};
for (const conf of configs) {
[key, value] = conf.split("=");
configObject[key] = value;
}
return configObject;
}
module.exports = { parseScenario };

42
src/specParser.js Normal file
View File

@ -0,0 +1,42 @@
const readFile = require("fs").readFileSync;
const parseScenario = require("./scenarioBuilder").parseScenario;
const CASE_DELIM = "#";
const SPECIAL_TIMEOUT = "wait";
function parser() {
const rawData = readFile("sample", "utf8");
const lines = rawData.split("\n");
const allScenarios = [];
let scenario = [];
for (var line = 0; line < lines.length; line++) {
const lineData = lines[line].split(" ");
var scenarioPhone;
if (lineData[0] === CASE_DELIM) {
scenarioPhone = lineData[1];
if (line > 0) {
allScenarios.push(scenario);
scenario = [];
}
} else if (lineData[0] === SPECIAL_TIMEOUT) {
scenario.push([
{
input: false,
timeout: true,
duration: lineData[1] * 1000,
},
]);
} else {
scenario.push(parseScenario(scenarioPhone, lines[line]));
}
}
return allScenarios;
}
module.exports = { parser };

26
src/worker.js Normal file
View File

@ -0,0 +1,26 @@
const setTimeout = require("timers/promises").setTimeout;
const rangi = require("rangi");
module.exports = async ({ jobId, tasks }) => {
for (const task of tasks) {
for (action of task) {
if (!action.input && action.timeout) {
console.log(
rangi.green(
`jobid ${jobId}: waiting ${action.duration}ms before carrying out next action`
)
);
await setTimeout(action.duration);
} else {
console.log(
rangi.cyan(
`jobid ${jobId}: session: ${action.sessionId}, input: ${action.input}`
)
);
await setTimeout(action.defaultWaitNextMenu);
}
}
}
return;
};

108
yarn.lock
View File

@ -9,6 +9,11 @@
dependencies:
"@jridgewell/trace-mapping" "^0.3.0"
"@assemblyscript/loader@^0.10.1":
version "0.10.1"
resolved "https://registry.yarnpkg.com/@assemblyscript/loader/-/loader-0.10.1.tgz#70e45678f06c72fa2e350e8553ec4a4d72b92e06"
integrity sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==
"@babel/code-frame@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789"
@ -254,7 +259,7 @@
"@babel/helper-validator-identifier" "^7.16.7"
to-fast-properties "^2.0.0"
"@isaacs/import-jsx@^4.0.1":
"@isaacs/import-jsx@*", "@isaacs/import-jsx@^4.0.1":
version "4.0.1"
resolved "https://registry.yarnpkg.com/@isaacs/import-jsx/-/import-jsx-4.0.1.tgz#493cab5fc543a0703dba7c3f5947d6499028a169"
integrity sha512-l34FEsEqpdYdGcQjRCxWy+7rHY6euUbOBz9FI+Mq6oQeVhNegHcXFSJxVxrJvOpO31NbnDjS74quKXDlPDearA==
@ -308,10 +313,10 @@
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11"
integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==
"@types/react@^17":
version "17.0.42"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.42.tgz#8242b9219bf8a911c47f248e327206fea3f4ee5a"
integrity sha512-nuab3x3CpJ7VFeNA+3HTUuEkvClYHXqWtWd7Ud6AZYW7Z3NH9WKtgU+tFB0ZLcHq+niB/HnzLcaZPqMJ95+k5Q==
"@types/react@*":
version "17.0.43"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.43.tgz#4adc142887dd4a2601ce730bc56c3436fdb07a55"
integrity sha512-8Q+LNpdxf057brvPu1lMtC5Vn7J119xrP1aq4qiaefNioQUYANF/CYeK4NsKorSZyUGJ66g0IM+4bbjwx45o2A==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
@ -418,6 +423,11 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
base64-js@^1.2.0:
version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
binary-extensions@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
@ -448,7 +458,7 @@ browserslist@^4.17.5:
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.2.tgz#567b41508757ecd904dab4d1c646c612cd3d4f88"
integrity sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA==
dependencies:
caniuse-lite "^1.0.config.test.waitNextMenu1317"
caniuse-lite "^1.0.30001317"
electron-to-chromium "^1.4.84"
escalade "^3.1.1"
node-releases "^2.0.2"
@ -493,10 +503,10 @@ camelcase@^5.0.0, camelcase@^5.3.1:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
caniuse-lite@^1.0.config.test.waitNextMenu1317:
version "1.0.config.test.waitNextMenu1320"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.config.test.waitNextMenu1320.tgz#8397391bec389b8ccce328636499b7284ee13285"
integrity sha512-MWPzG54AGdo3nWx7zHZTefseM5Y1ccM7hlQKHRqJkPozUaw3hNbBTMmLn16GG2FUzjR13Cr3NPfhIieX5PzXDA==
caniuse-lite@^1.0.30001317:
version "1.0.30001323"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001323.tgz#a451ff80dec7033016843f532efda18f02eec011"
integrity sha512-e4BF2RlCVELKx8+RmklSEIVub1TWrmdhvA5kEUueummz1XyySW0DVk+3x9HyhU9MuWTa2BhqLgEuEmUwASAdCA==
cardinal@^2.1.1:
version "2.1.1"
@ -696,9 +706,9 @@ diff@^4.0.1, diff@^4.0.2:
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
electron-to-chromium@^1.4.84:
version "1.4.92"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.92.tgz#88996e9aceb3a500710fd439abfa89b6cc1ac56c"
integrity sha512-YAVbvQIcDE/IJ/vzDMjD484/hsRbFPW2qXJPaYTfOhtligmfYEYOep+5QojpaEU9kq6bMvNeC2aG7arYvTHYsA==
version "1.4.103"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.103.tgz#abfe376a4d70fa1e1b4b353b95df5d6dfd05da3a"
integrity sha512-c/uKWR1Z/W30Wy/sx3dkZoj4BijbXX85QKWu9jJfjho3LBAXNEGAEW3oWiGb+dotA6C6BzCTxL2/aLes7jlUeg==
emoji-regex@^8.0.0:
version "8.0.0"
@ -730,6 +740,11 @@ esprima@^4.0.0, esprima@~4.0.0:
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
eventemitter-asyncresource@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz#734ff2e44bf448e627f7748f905d6bdd57bdb65b"
integrity sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==
events-to-array@^1.0.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/events-to-array/-/events-to-array-1.1.2.tgz#2d41f563e1fe400ed4962fe1a4d5c6a7539df7f6"
@ -859,6 +874,20 @@ hasha@^5.0.0:
is-stream "^2.0.0"
type-fest "^0.8.0"
hdr-histogram-js@^2.0.1:
version "2.0.3"
resolved "https://registry.yarnpkg.com/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz#0b860534655722b6e3f3e7dca7b78867cf43dcb5"
integrity sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==
dependencies:
"@assemblyscript/loader" "^0.10.1"
base64-js "^1.2.0"
pako "^1.0.3"
hdr-histogram-percentiles-obj@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz#9409f4de0c2dda78e61de2d9d78b1e9f3cba283c"
integrity sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==
html-escaper@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453"
@ -887,7 +916,7 @@ inherits@2:
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
ink@^3.2.0:
ink@*, ink@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/ink/-/ink-3.2.0.tgz#434793630dc57d611c8fe8fffa1db6b56f1a16bb"
integrity sha512-firNp1q3xxTzoItj/eOOSZQnYSlyrWks5llCTVX37nJ59K3eXbQ8PtzCguqo8YI19EELo5QxaKnJd4VxzhU8tg==
@ -1147,6 +1176,24 @@ ms@^2.1.2:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
nice-napi@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/nice-napi/-/nice-napi-1.0.2.tgz#dc0ab5a1eac20ce548802fc5686eaa6bc654927b"
integrity sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==
dependencies:
node-addon-api "^3.0.0"
node-gyp-build "^4.2.2"
node-addon-api@^3.0.0:
version "3.2.1"
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161"
integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==
node-gyp-build@^4.2.2:
version "4.3.0"
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3"
integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==
node-preload@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/node-preload/-/node-preload-0.2.1.tgz#c03043bb327f417a18fee7ab7ee57b408a144301"
@ -1269,6 +1316,11 @@ package-hash@^4.0.0:
lodash.flattendeep "^4.4.0"
release-zalgo "^1.0.0"
pako@^1.0.3:
version "1.0.11"
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
patch-console@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/patch-console/-/patch-console-1.0.0.tgz#19b9f028713feb8a3c023702a8cc8cb9f7466f9d"
@ -1306,6 +1358,17 @@ picomatch@^2.0.4, picomatch@^2.2.1:
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
piscina@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/piscina/-/piscina-3.2.0.tgz#f5a1dde0c05567775690cccefe59d9223924d154"
integrity sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==
dependencies:
eventemitter-asyncresource "^1.0.0"
hdr-histogram-js "^2.0.1"
hdr-histogram-percentiles-obj "^3.0.0"
optionalDependencies:
nice-napi "^1.0.2"
pkg-dir@^4.1.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
@ -1331,9 +1394,9 @@ rangi@^1.0.2:
integrity sha1-gJ9lLg1kboT25UbeFcL0ZpI+b6k=
react-devtools-core@^4.19.1:
version "4.24.2"
resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-4.24.2.tgz#ce10e3ea502559ce4299c13837d2374cf0d435a7"
integrity sha512-UC3rvQCG/dnC95NPNWBFrUEtdAEiFZ9xZe1tTHFOELVR5qfNLroZ3w9tC51NQvvK5E10G2ko3lQ5Vrh3p0bHrA==
version "4.24.3"
resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-4.24.3.tgz#371fef3f5c639db0dc59eeef334dd5e10ac61661"
integrity sha512-+htKZxLxDN14jhRG3+IXRiJqNSGHUiPYrMtv9e7qlZxcbKeJjVs+C/hd8kZF5rydp3faBwFN6ZpTaZnLA3/ZGA==
dependencies:
shell-quote "^1.6.1"
ws "^7"
@ -1347,13 +1410,12 @@ react-reconciler@^0.26.2:
object-assign "^4.1.1"
scheduler "^0.20.2"
react@^17.0.2:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==
react@*:
version "18.0.0"
resolved "https://registry.yarnpkg.com/react/-/react-18.0.0.tgz#b468736d1f4a5891f38585ba8e8fb29f91c3cb96"
integrity sha512-x+VL6wbT4JRVPm7EGxXhZ8w8LTROaxPXOqhlGyVSrv0sB1jkyFGgXxJ8LVoPRLvPR6/CIZGFmfzqUa2NYeMr2A==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
readdirp@~3.6.0:
version "3.6.0"
@ -1639,7 +1701,7 @@ to-regex-range@^5.0.1:
dependencies:
is-number "^7.0.0"
treport@^3.0.3:
treport@*:
version "3.0.3"
resolved "https://registry.yarnpkg.com/treport/-/treport-3.0.3.tgz#0666bb1b00b6ed6e2ba82ae76b79d77fb03c505a"
integrity sha512-pCg4Bc0Uv0ntAkYjYJAncA6h6Srv1eEFa5vcak8paahgU1TrJ2rZm0RPZ8E8uycz+P55quzsDnACw01jpWfk7Q==