Added tfjs and ml model for grid detection

This commit is contained in:
Mitchell McCaffrey 2020-10-14 09:53:32 +11:00
parent 0747e1c38f
commit f21fa8fb02
8 changed files with 323 additions and 35 deletions

View File

@ -7,6 +7,7 @@
"@babylonjs/loaders": "^4.1.0",
"@msgpack/msgpack": "^1.12.1",
"@stripe/stripe-js": "^1.3.2",
"@tensorflow/tfjs": "^2.6.0",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",

View File

@ -1,3 +1,5 @@
import GridSizeModel from "../ml/gridSize/GridSizeModel";
export function getMapDefaultInset(width, height, gridX, gridY) {
// Max the width
const gridScale = width / gridX;
@ -33,33 +35,98 @@ function dividers(a, b) {
const gridSizeMean = { x: 31.567792, y: 32.597987 };
const gridSizeStd = { x: 14.438842, y: 15.582376 };
// Most grid sizes are above 10 and below 100
// Most grid sizes are above 10 and below 200
const minGridSize = 10;
const maxGridSize = 200;
function gridSizeVaild(x, y) {
return x > 10 && y > 10 && x < 100 && y < 100;
return (
x > minGridSize && y > minGridSize && x < maxGridSize && y < maxGridSize
);
}
export function gridSizeHeuristic(width, height) {
const div = dividers(width, height);
if (div.length > 0) {
// Find the best division by comparing the absolute z-scores of each axis
let bestX = 1;
let bestY = 1;
let bestScore = Number.MAX_VALUE;
for (let scale of div) {
const x = Math.floor(width / scale);
const y = Math.floor(height / scale);
const xScore = Math.abs((x - gridSizeMean.x) / gridSizeStd.x);
const yScore = Math.abs((y - gridSizeMean.y) / gridSizeStd.y);
if (xScore < bestScore || yScore < bestScore) {
bestX = x;
bestY = y;
bestScore = Math.min(xScore, yScore);
}
}
if (gridSizeVaild(bestX, bestY)) {
return { x: bestX, y: bestY };
function gridSizeHeuristic(image, candidates) {
const width = image.width;
const height = image.height;
// Find the best candidate by comparing the absolute z-scores of each axis
let bestX = 1;
let bestY = 1;
let bestScore = Number.MAX_VALUE;
for (let scale of candidates) {
const x = Math.floor(width / scale);
const y = Math.floor(height / scale);
const xScore = Math.abs((x - gridSizeMean.x) / gridSizeStd.x);
const yScore = Math.abs((y - gridSizeMean.y) / gridSizeStd.y);
if (xScore < bestScore || yScore < bestScore) {
bestX = x;
bestY = y;
bestScore = Math.min(xScore, yScore);
}
}
return { x: 22, y: 22 };
if (gridSizeVaild(bestX, bestY)) {
return { x: bestX, y: bestY };
} else {
return null;
}
}
async function gridSizeML(image, candidates) {
const width = image.width;
const height = image.height;
const ratio = width / height;
let canvas = document.createElement("canvas");
let context = canvas.getContext("2d");
canvas.width = 2048;
canvas.height = 2048 / ratio;
context.drawImage(image, 0, 0, canvas.width, canvas.height);
let imageData = context.getImageData(0, canvas.height / 2 - 16, 2048, 32);
for (let i = 0; i < imageData.data.length; i += 4) {
const r = imageData.data[i];
const g = imageData.data[i + 1];
const b = imageData.data[i + 2];
// ITU-R 601-2 Luma Transform
const luma = (r * 299) / 1000 + (g * 587) / 1000 + (b * 114) / 1000;
imageData.data[i] = imageData.data[i + 1] = imageData.data[i + 2] = luma;
}
const model = new GridSizeModel();
const prediction = await model.predict(imageData);
// Find the candidate that is closest to the prediction
let bestScale = 1;
let bestScore = Number.MAX_VALUE;
for (let scale of candidates) {
const x = Math.floor(width / scale);
const score = Math.abs(x - prediction);
if (score < bestScore && x > minGridSize && x < maxGridSize) {
bestScale = scale;
bestScore = score;
}
}
const x = Math.floor(width / bestScale);
const y = Math.floor(height / bestScale);
if (gridSizeVaild(x, y)) {
return { x, y };
} else {
return null;
}
}
export async function getGridSize(image) {
const candidates = dividers(image.width, image.height);
let prediction = await gridSizeML(image, candidates);
if (!prediction) {
prediction = gridSizeHeuristic(image, candidates);
}
if (!prediction) {
prediction = { x: 22, y: 22 };
}
return prediction;
}

35
src/ml/Model.js Normal file
View File

@ -0,0 +1,35 @@
import blobToBuffer from "../helpers/blobToBuffer";
class Model {
constructor(config, weightsMapping) {
this.config = config;
this.weightsMapping = weightsMapping;
}
async load() {
// Load weights from the manifest then fetch them into an ArrayBuffer
let buffers = [];
const manifest = this.config.weightsManifest[0];
for (let path of manifest.paths) {
const url = this.weightsMapping[path];
const response = await fetch(url);
const buffer = await response.arrayBuffer();
buffers.push(buffer);
}
const merged = new Blob(buffers);
const weightData = await blobToBuffer(merged);
const weightSpecs = manifest.weights;
const modelArtifacts = {
modelTopology: this.config.modelTopology,
format: this.config.format,
generatedBy: this.config.generatedBy,
convertedBy: this.config.convertedBy,
weightData,
weightSpecs,
};
return modelArtifacts;
}
}
export default Model;

View File

@ -0,0 +1,29 @@
import * as tf from "@tensorflow/tfjs";
import Model from "../Model";
import config from "./model.json";
import weights from "./group1-shard1of1.bin";
class GridSizeModel extends Model {
model;
constructor() {
super(config, { "group1-shard1of1.bin": weights });
}
async predict(imageData) {
if (!this.model) {
this.model = await tf.loadLayersModel(this);
}
const prediction = tf.tidy(() => {
const image = tf.browser.fromPixels(imageData, 1).toFloat();
const normalized = image.div(tf.scalar(255.0));
const batched = tf.expandDims(normalized);
return this.model.predict(batched);
});
const data = await prediction.data();
return data[0];
}
}
export default GridSizeModel;

Binary file not shown.

1
src/ml/gridSize/model.json Executable file

File diff suppressed because one or more lines are too long

View File

@ -16,7 +16,7 @@ import blobToBuffer from "../helpers/blobToBuffer";
import useKeyboard from "../helpers/useKeyboard";
import { resizeImage } from "../helpers/image";
import { useSearch, useGroup, handleItemSelect } from "../helpers/select";
import { getMapDefaultInset, gridSizeHeuristic } from "../helpers/map";
import { getMapDefaultInset, getGridSize } from "../helpers/map";
import MapDataContext from "../contexts/MapDataContext";
import AuthContext from "../contexts/AuthContext";
@ -131,7 +131,7 @@ function SelectMapModal({
}
if (!gridSize) {
gridSize = gridSizeHeuristic(image.width, image.height);
gridSize = await getGridSize(image);
}
// Remove file extension

173
yarn.lock
View File

@ -1749,6 +1749,73 @@
"@svgr/plugin-svgo" "^4.3.1"
loader-utils "^1.2.3"
"@tensorflow/tfjs-backend-cpu@2.6.0":
version "2.6.0"
resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-backend-cpu/-/tfjs-backend-cpu-2.6.0.tgz#bd0923ca438e945c4c9347a76e301a4fb1890d33"
integrity sha512-essk82VoET77tuFX5Sa9zv9F8d/2DxjEQ2RavoU+ugs0l64DTbdTpv3WdQwUihv1gNN7/16fUjJ6cG80SnS8/g==
dependencies:
"@types/seedrandom" "2.4.27"
seedrandom "2.4.3"
"@tensorflow/tfjs-backend-webgl@2.6.0":
version "2.6.0"
resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-backend-webgl/-/tfjs-backend-webgl-2.6.0.tgz#3855c254a86daf28511530c36bb61938acf26740"
integrity sha512-j1eNYKIpO06CTSRXiIWdpZ2iPDBkx7PPl7K/1BtCEW/9FP7Q0q3doHKNmTdOPvuw7Dt1nNHEMnba0YB2lc5S7Q==
dependencies:
"@tensorflow/tfjs-backend-cpu" "2.6.0"
"@types/offscreencanvas" "~2019.3.0"
"@types/seedrandom" "2.4.27"
"@types/webgl-ext" "0.0.30"
"@types/webgl2" "0.0.4"
seedrandom "2.4.3"
"@tensorflow/tfjs-converter@2.6.0":
version "2.6.0"
resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-converter/-/tfjs-converter-2.6.0.tgz#0de5c4c014c25d695ad17ca19e3b654dbcb84cea"
integrity sha512-TzL4ULidZ26iVqfLmv5G6dfnJyJt5HttU1VZoBYCbxUcWQYk1Z4D9wqLVwfdcJz01XEKpmsECh8HBF0hwYlrkA==
"@tensorflow/tfjs-core@2.6.0":
version "2.6.0"
resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-core/-/tfjs-core-2.6.0.tgz#ab2f2c9e8f46990643076d7d5bdb912885282bd2"
integrity sha512-akUB1iz663UCUdOfEUu91XeHzGpdYtdtMPxjsGEdF0CwENzSAcvHzQrEVoPBRD+RKpxrVXvQBoOd7GYBxMIIKQ==
dependencies:
"@types/offscreencanvas" "~2019.3.0"
"@types/seedrandom" "2.4.27"
"@types/webgl-ext" "0.0.30"
"@types/webgl2" "0.0.4"
node-fetch "~2.6.1"
seedrandom "2.4.3"
"@tensorflow/tfjs-data@2.6.0":
version "2.6.0"
resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-data/-/tfjs-data-2.6.0.tgz#005fb204822322bc652ddd968c15a6b1a295652a"
integrity sha512-/x/j/A4Quiyc21xEYyBC82mqyssbFHRuHez7pYVJA/28TOesAfWPWo2I+wkeOTt91UerUeZMSq2FV3HOnPInhQ==
dependencies:
"@types/node-fetch" "^2.1.2"
node-fetch "~2.6.1"
"@tensorflow/tfjs-layers@2.6.0":
version "2.6.0"
resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-layers/-/tfjs-layers-2.6.0.tgz#fed57ff6514f3fbb78fbcd2d40a09e9bd8d52cfc"
integrity sha512-nU9WNSGpEU6GzKo5bvJBMa/OZRe1bR5Z2W6T0XiEY8CBiPNS+oJFJNm0NY8kQj/WnDS0Hfue38P46q7gV/9XMA==
"@tensorflow/tfjs@^2.6.0":
version "2.6.0"
resolved "https://registry.yarnpkg.com/@tensorflow/tfjs/-/tfjs-2.6.0.tgz#ddc420fbb0d9561f46d3d02ba3ba2d4c15861837"
integrity sha512-f70NAt480+/NH6ueAdKhwgN3BzeBWrvuAZ591pH44nuVlmUHtih7pSMVv2wREPOgA4ciAufops4FtTaqNamxZw==
dependencies:
"@tensorflow/tfjs-backend-cpu" "2.6.0"
"@tensorflow/tfjs-backend-webgl" "2.6.0"
"@tensorflow/tfjs-converter" "2.6.0"
"@tensorflow/tfjs-core" "2.6.0"
"@tensorflow/tfjs-data" "2.6.0"
"@tensorflow/tfjs-layers" "2.6.0"
argparse "^1.0.10"
chalk "^4.1.0"
core-js "3"
regenerator-runtime "^0.13.5"
yargs "^16.0.3"
"@testing-library/dom@*":
version "7.22.1"
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.22.1.tgz#b66861fb7751287bda63a55f5c72ca808c63043c"
@ -1943,11 +2010,24 @@
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
"@types/node-fetch@^2.1.2":
version "2.5.7"
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c"
integrity sha512-o2WVNf5UhWRkxlf6eq+jMZDu7kjgpgJfl4xVNlvryc95O/6F2ld8ztKX+qu+Rjyet93WAWm5LjeX9H5FGkODvw==
dependencies:
"@types/node" "*"
form-data "^3.0.0"
"@types/node@*":
version "14.0.27"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.27.tgz#a151873af5a5e851b51b3b065c9e63390a9e0eb1"
integrity sha512-kVrqXhbclHNHGu9ztnAwSncIgJv/FaxmzXJvGXNdcCpV1b8u1/Mi6z6m0vwy0LzKeXFTPLH0NzwmoJ3fNCIq0g==
"@types/offscreencanvas@~2019.3.0":
version "2019.3.0"
resolved "https://registry.yarnpkg.com/@types/offscreencanvas/-/offscreencanvas-2019.3.0.tgz#3336428ec7e9180cf4566dfea5da04eb586a6553"
integrity sha512-esIJx9bQg+QYF0ra8GnvfianIY8qWB0GBx54PK5Eps6m+xTj86KLavHv6qDhzKcu5UUOgNfJ2pWaIIV7TRUd9Q==
"@types/parse-json@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
@ -1978,6 +2058,11 @@
"@types/prop-types" "*"
csstype "^3.0.2"
"@types/seedrandom@2.4.27":
version "2.4.27"
resolved "https://registry.yarnpkg.com/@types/seedrandom/-/seedrandom-2.4.27.tgz#9db563937dd86915f69092bc43259d2f48578e41"
integrity sha1-nbVjk33YaRX2kJK8QyWdL0hXjkE=
"@types/stack-utils@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e"
@ -2006,6 +2091,16 @@
"@types/testing-library__dom" "*"
pretty-format "^25.1.0"
"@types/webgl-ext@0.0.30":
version "0.0.30"
resolved "https://registry.yarnpkg.com/@types/webgl-ext/-/webgl-ext-0.0.30.tgz#0ce498c16a41a23d15289e0b844d945b25f0fb9d"
integrity sha512-LKVgNmBxN0BbljJrVUwkxwRYqzsAEPcZOe6S2T6ZaBDIrFp0qu4FNlpc5sM1tGbXUYFgdVQIoeLk1Y1UoblyEg==
"@types/webgl2@0.0.4":
version "0.0.4"
resolved "https://registry.yarnpkg.com/@types/webgl2/-/webgl2-0.0.4.tgz#c3b0f9d6b465c66138e84e64cb3bdf8373c2c279"
integrity sha512-PACt1xdErJbMUOUweSrbVM7gSIYm1vTncW2hF6Os/EeWi6TXYAYMPp+8v6rzHmypE5gHrxaxZNXgMkJVIdZpHw==
"@types/yargs-parser@*":
version "15.0.0"
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d"
@ -2411,7 +2506,7 @@ aproba@^1.1.1:
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
argparse@^1.0.7:
argparse@^1.0.10, argparse@^1.0.7:
version "1.0.10"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
@ -3456,6 +3551,15 @@ cliui@^6.0.0:
strip-ansi "^6.0.0"
wrap-ansi "^6.2.0"
cliui@^7.0.0:
version "7.0.1"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.1.tgz#a4cb67aad45cd83d8d05128fc9f4d8fbb887e6b3"
integrity sha512-rcvHOWyGyid6I1WjT/3NatKj2kDt9OdSHSXpyLXaMWFbKpGACNW8pRhhdPUq9MWUOdwn8Rz9AVETjF4105rZZQ==
dependencies:
string-width "^4.2.0"
strip-ansi "^6.0.0"
wrap-ansi "^7.0.0"
clone-deep@^0.2.4:
version "0.2.4"
resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-0.2.4.tgz#4e73dd09e9fb971cc38670c5dced9c1896481cc6"
@ -3553,7 +3657,7 @@ colorette@^1.2.1:
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b"
integrity sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==
combined-stream@^1.0.6, combined-stream@~1.0.6:
combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
version "1.0.8"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
@ -3731,16 +3835,16 @@ core-js-pure@^3.0.0:
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.5.tgz#c79e75f5e38dbc85a662d91eea52b8256d53b813"
integrity sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==
core-js@3, core-js@^3.0.1, core-js@^3.5.0:
version "3.6.5"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a"
integrity sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==
core-js@^2.4.0, core-js@^2.5.3:
version "2.6.11"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c"
integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==
core-js@^3.0.1, core-js@^3.5.0:
version "3.6.5"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a"
integrity sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==
core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
@ -5328,6 +5432,15 @@ fork-ts-checker-webpack-plugin@3.1.1:
tapable "^1.0.0"
worker-rpc "^0.1.0"
form-data@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682"
integrity sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.8"
mime-types "^2.1.12"
form-data@~2.3.2:
version "2.3.3"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
@ -5459,7 +5572,7 @@ get-caller-file@^1.0.1:
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==
get-caller-file@^2.0.1:
get-caller-file@^2.0.1, 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==
@ -7824,6 +7937,11 @@ no-case@^3.0.3:
lower-case "^2.0.1"
tslib "^1.10.0"
node-fetch@~2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
node-forge@0.9.0:
version "0.9.0"
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579"
@ -9897,7 +10015,7 @@ regenerator-runtime@^0.11.0:
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.4:
regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.5:
version "0.13.7"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
@ -10340,6 +10458,11 @@ sdp@^2.12.0, sdp@^2.6.0:
resolved "https://registry.yarnpkg.com/sdp/-/sdp-2.12.0.tgz#338a106af7560c86e4523f858349680350d53b22"
integrity sha512-jhXqQAQVM+8Xj5EjJGVweuEzgtGWb3tmEEpl3CLP3cStInSbVHSg0QWOGQzNq8pSID4JkpeV2mPqlMDLrm0/Vw==
seedrandom@2.4.3:
version "2.4.3"
resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-2.4.3.tgz#2438504dad33917314bff18ac4d794f16d6aaecc"
integrity sha1-JDhQTa0zkXMUv/GKxNeU8W1qrsw=
select-hose@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
@ -12207,6 +12330,15 @@ wrap-ansi@^6.2.0:
string-width "^4.1.0"
strip-ansi "^6.0.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"
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
@ -12279,6 +12411,11 @@ xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
y18n@^5.0.1:
version "5.0.2"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.2.tgz#48218df5da2731b4403115c39a1af709c873f829"
integrity sha512-CkwaeZw6dQgqgPGeTWKMXCRmMcBgETFlTml1+ZOO+q7kGst8NREJ+eWwFNPVUQ4QGdAaklbqCZHH6Zuep1RjiA==
yallist@^3.0.2:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
@ -12318,6 +12455,11 @@ yargs-parser@^18.1.2:
camelcase "^5.0.0"
decamelize "^1.2.0"
yargs-parser@^20.0.0:
version "20.2.1"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.1.tgz#28f3773c546cdd8a69ddae68116b48a5da328e77"
integrity sha512-yYsjuSkjbLMBp16eaOt7/siKTjNVjMm3SoJnIg3sEh/JsvqVVDyjRKmaJV4cl+lNIgq6QEco2i3gDebJl7/vLA==
yargs@12.0.5:
version "12.0.5"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13"
@ -12369,6 +12511,19 @@ yargs@^15.3.1:
y18n "^4.0.0"
yargs-parser "^18.1.2"
yargs@^16.0.3:
version "16.0.3"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.0.3.tgz#7a919b9e43c90f80d4a142a89795e85399a7e54c"
integrity sha512-6+nLw8xa9uK1BOEOykaiYAJVh6/CjxWXK/q9b5FpRgNslt8s22F2xMBqVIKgCRjNgGvGPBy8Vog7WN7yh4amtA==
dependencies:
cliui "^7.0.0"
escalade "^3.0.2"
get-caller-file "^2.0.5"
require-directory "^2.1.1"
string-width "^4.2.0"
y18n "^5.0.1"
yargs-parser "^20.0.0"
yeast@0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"