Update v1.0.1

Took 1 hour 27 minutes
This commit is contained in:
Tobias Hopp 2022-11-23 23:56:46 +01:00
parent 6446896565
commit 1b8376644e
63 changed files with 146 additions and 50 deletions

6
ToDo.md Normal file
View File

@ -0,0 +1,6 @@
# ToDo
- [ ] Behälter unten rechts anzeigen
- [ ] Status für Netzwerk oben neben Uhrzeit
- [ ] Fix Fehler wenn keine Getränke hinzugefügt worden sind
-

View File

@ -1,6 +1,6 @@
{ {
"name": "itender", "name": "itender",
"version": "0.0.1", "version": "1.0.1",
"private": true, "private": true,
"author": "Tobias Hopp <tobi@gaminggeneration.de>", "author": "Tobias Hopp <tobi@gaminggeneration.de>",
"license": "UNLICENSED", "license": "UNLICENSED",
@ -23,6 +23,7 @@
"@types/rpi-gpio": "^2.1.1", "@types/rpi-gpio": "^2.1.1",
"@types/rpi-ws281x-native": "^1.0.0", "@types/rpi-ws281x-native": "^1.0.0",
"axios": "^1.2.0", "axios": "^1.2.0",
"buffer": "^6.0.3",
"cookie-parser": "^1.4.6", "cookie-parser": "^1.4.6",
"debug": "^4.3.4", "debug": "^4.3.4",
"express": "~4.16.1", "express": "~4.16.1",

Binary file not shown.

After

Width:  |  Height:  |  Size: 1020 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 611 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 611 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 817 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 640 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 921 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 938 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 706 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 688 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 640 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 817 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 938 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 688 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 706 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 921 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

View File

@ -12,6 +12,19 @@
} }
.btn-blendout {
animation: 1s blendOut forwards;
}
@keyframes blendOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.inputGroup { .inputGroup {
margin-bottom: 1.5%; margin-bottom: 1.5%;
} }
@ -107,6 +120,7 @@ label {
margin-right: 1%; margin-right: 1%;
margin-bottom: 2%; margin-bottom: 2%;
border: 0; border: 0;
background-color: #e9e9ed;
border-radius: 3px; border-radius: 3px;
} }

View File

@ -88,7 +88,7 @@ body {
top: -90%; top: -90%;
left: -50%; left: -50%;
border-radius: 40%; border-radius: 40%;
animation: animWater 8s linear infinite, animFillIn var(--fillTime) linear forwards; animation: animWater 7s linear infinite, animFillIn var(--fillTime) linear forwards;
} }
.water::after { .water::after {
@ -100,7 +100,7 @@ body {
top: -100%; top: -100%;
left: -52%; left: -52%;
border-radius: 40%; border-radius: 40%;
animation: animWater 8s linear infinite, animFillIn var(--fillTime) linear forwards; animation: animWater 7s linear infinite, animFillIn var(--fillTime) linear forwards;
animation-delay: 0.4s; animation-delay: 0.4s;
} }
@ -109,6 +109,11 @@ body {
transition: background-color 1s; transition: background-color 1s;
} }
.waterFinished {
background-color: green;
transition: background-color 2s;
}
@keyframes animFillIn { @keyframes animFillIn {
0% { 0% {
top: -100%; top: -100%;

View File

@ -63,12 +63,12 @@
.modalBlendIn { .modalBlendIn {
animation: modalBlendIn 0.5s ease; animation: modalBlendIn 0.5s forwards;
} }
.modalBlendOut { .modalBlendOut {
animation: modalBlendOut 0.8s ease; animation: modalBlendOut 0.8s forwards;
} }

View File

@ -23,7 +23,7 @@ html * {
-webkit-user-select: none; /* Safari */ -webkit-user-select: none; /* Safari */
-ms-user-select: none; /* IE 10 and IE 11 */ -ms-user-select: none; /* IE 10 and IE 11 */
user-select: none; /* Standard syntax */ user-select: none; /* Standard syntax */
cursor: none;
} }
@ -55,6 +55,12 @@ h1 {
} }
h2 {
font-size: 1.45em;
font-weight: 500;
margin-bottom: 2%;
}
#overlay { #overlay {
color: white; color: white;

View File

@ -43,4 +43,9 @@ export class Utils {
fs.unlinkSync("./public/images/" + id + ".png"); fs.unlinkSync("./public/images/" + id + ".png");
} }
static checkForImage( id )
{
return fs.existsSync("./public/images/" + id + ".png");
}
} }

View File

@ -1,4 +1,5 @@
import {WebSocketEvent} from "./WebSocketEvent"; import {WebSocketEvent} from "./WebSocketEvent";
import {Buffer} from "buffer";
export class WebSocketPayload { export class WebSocketPayload {
set event(value: WebSocketEvent) { set event(value: WebSocketEvent) {
@ -37,7 +38,8 @@ export class WebSocketPayload {
} }
public static parseFromBase64Json(json: string): WebSocketPayload | null { public static parseFromBase64Json(json: string): WebSocketPayload | null {
json = (typeof window != 'undefined') ? atob(json) : Buffer.from(json, "base64").toString(); //json = (typeof window != 'undefined') ? atob(json).toString() : Buffer.from(json, "base64").toString("utf-8");
json = Buffer.from(json, "base64").toString("utf-8");
let rawPayload: { event: string, error: boolean, data: any }; let rawPayload: { event: string, error: boolean, data: any };
try { try {
rawPayload = JSON.parse(json); rawPayload = JSON.parse(json);
@ -55,6 +57,7 @@ export class WebSocketPayload {
*/ */
public toString(): string { public toString(): string {
let json = JSON.stringify({"event": this._event, status: this._error, data: this._data}); let json = JSON.stringify({"event": this._event, status: this._error, data: this._data});
json = ((typeof window != 'undefined') ? btoa(json) : Buffer.from(json).toString("base64")); json = ((typeof window != 'undefined') ? btoa(json) : Buffer.from(json).toString("base64"));
return json; return json;
} }

View File

@ -18,7 +18,6 @@ import Ingredient from "./database/Ingredient";
import {clearInterval} from "timers"; import {clearInterval} from "timers";
import {RejectReason} from "./RejectReason"; import {RejectReason} from "./RejectReason";
import {Settings} from "./Settings"; import {Settings} from "./Settings";
import GPIO from "rpi-gpio";
import axios from "axios"; import axios from "axios";
const log = debug("itender:station"); const log = debug("itender:station");
@ -76,12 +75,14 @@ export class iTender {
const job = new Job(); const job = new Job();
let amounts: { ingredient: IIngredient, amount: number, container?: IContainer }[] = []; let amounts: { ingredient: IIngredient, amount: number, container?: IContainer }[] = [];
job.completeAmount = 0;
if (data.amounts) { if (data.amounts) {
for (let x of data.amounts) { for (let x of data.amounts) {
let ingredient = await Ingredient.findById(x.ingredient); let ingredient = await Ingredient.findById(x.ingredient);
if (!ingredient) continue; if (!ingredient) continue;
amounts.push({ingredient: ingredient, amount: x.amount}); amounts.push({ingredient: ingredient, amount: x.amount});
job.completeAmount+= x.amount;
} }
} else if (data.amount) { } else if (data.amount) {
let sum = 0; let sum = 0;
@ -93,17 +94,19 @@ export class iTender {
for (let x of (drink.ingredients as { type: IIngredient, amount: number }[])) { for (let x of (drink.ingredients as { type: IIngredient, amount: number }[])) {
amounts.push({ingredient: x.type, amount: x.amount * factor}) amounts.push({ingredient: x.type, amount: x.amount * factor})
job.completeAmount+= x.amount;
} }
} else { } else {
for (let x of (drink.ingredients as { type: IIngredient, amount: number }[])) { for (let x of (drink.ingredients as { type: IIngredient, amount: number }[])) {
amounts.push({ingredient: x.type, amount: x.amount}); amounts.push({ingredient: x.type, amount: x.amount});
job.completeAmount+= x.amount;
} }
} }
job.estimatedTime = 0; job.estimatedTime = 0;
let tolerance = 5; let tolerance = 3;
for (let x of amounts) { for (let x of amounts) {
let c = await Container.findOne({$and: [{enabled: true}, {filled: {$gt: x.amount + tolerance}}]}); let c = await Container.findOne({$and: [{enabled: true}, {filled: {$gt: x.amount + tolerance}}]});
if (!c) { if (!c) {
@ -140,15 +143,15 @@ export class iTender {
let timers: NodeJS.Timeout[] = []; let timers: NodeJS.Timeout[] = [];
for (let x of job.amounts) { for (let x of job.amounts) {
// Start pump here // Start pump here
await GPIO.setup(x.container.pumpPin, GPIO.DIR_OUT); //await GPIO.setup(x.container.pumpPin, GPIO.DIR_OUT);
await GPIO.write(x.container.pumpPin, true); //await GPIO.write(x.container.pumpPin, true);
let waitTime = (Settings.get("secondsPer100ml") as number) / 100 * x.amount * 1000; let waitTime = (Settings.get("secondsPer100ml") as number) / 100 * x.amount * 1000;
mixLog(`Starting output of pump ${x.container.pumpPin}`); mixLog(`Starting output of pump ${x.container.pumpPin}`);
//mixLog(x.ingredient + " takes " + (waitTime / 1000) + "s for " + x.amount + "ml"); //mixLog(x.ingredient + " takes " + (waitTime / 1000) + "s for " + x.amount + "ml");
let timer = setTimeout(() => { let timer = setTimeout(() => {
// Stop pump here // Stop pump here
GPIO.write(x.container.pumpPin, false); //GPIO.write(x.container.pumpPin, false);
// Remove from list of timers // Remove from list of timers
let arr: NodeJS.Timer[] = []; let arr: NodeJS.Timer[] = [];
@ -178,7 +181,7 @@ export class iTender {
} }
static cancelFill() { static cancelFill() {
if (!this._currentJob) if (!this._currentJob || this.status != iTenderStatus.FILLING)
return; return;
clearInterval(this._jobCheckInterval); clearInterval(this._jobCheckInterval);
this._currentJob.successful = false; this._currentJob.successful = false;
@ -189,7 +192,7 @@ export class iTender {
for (let x of this._currentJob.amounts) { for (let x of this._currentJob.amounts) {
// stop pump pin // stop pump pin
//x.container.pumpPin //x.container.pumpPin
GPIO.write(x.container.pumpPin, false); //GPIO.write(x.container.pumpPin, false);
} }
iTender.setStatus(iTenderStatus.READY); iTender.setStatus(iTenderStatus.READY);
@ -235,7 +238,6 @@ export class iTender {
} }
static refreshDrinks(): Promise<void> { static refreshDrinks(): Promise<void> {
this.setStatus(iTenderStatus.REFRESHING);
log("Refreshing drinks..."); log("Refreshing drinks...");
return new Promise(async resolve => { return new Promise(async resolve => {
this._drinks = []; this._drinks = [];
@ -256,7 +258,6 @@ export class iTender {
} }
log("Drinks refreshed!"); log("Drinks refreshed!");
iTender.setStatus(iTenderStatus.READY);
await WebSocketHandler.sendDrinks(); await WebSocketHandler.sendDrinks();
resolve(); resolve();
@ -305,11 +306,9 @@ export class iTender {
} }
} }
if (!found) if (!found) {
{
await Ingredient.deleteOne({"_id": local._id}); await Ingredient.deleteOne({"_id": local._id});
for( let c of (await Container.find( {content: local._id } )) ) for (let c of (await Container.find({content: local._id}))) {
{
c.content = undefined; c.content = undefined;
c.save(); c.save();
} }
@ -319,16 +318,16 @@ export class iTender {
for (let remote of serverIngredients) { for (let remote of serverIngredients) {
let ingredient = await Ingredient.findOne({name: remote.name}); let ingredient = await Ingredient.findById(remote._id);
if (!ingredient) if (!ingredient)
ingredient = new Ingredient(); ingredient = new Ingredient();
ingredient._id = remote._id;
ingredient.name = remote.name; ingredient.name = remote.name;
await ingredient.save(); await ingredient.save();
} }
const requestDrinks = await axios.get("https://itender.iif.li/api/drinks"); const requestDrinks = await axios.get("https://itender.iif.li/api/drinks");
let serverDrinks = requestDrinks.data as IDrink[]; let serverDrinks = requestDrinks.data as IDrink[];
log("Got " + serverDrinks.length + " drinks from server"); log("Got " + serverDrinks.length + " drinks from server");
@ -344,8 +343,7 @@ export class iTender {
} }
} }
if (!found) if (!found) {
{
Utils.deleteImage(local._id); Utils.deleteImage(local._id);
await Drink.deleteOne({"_id": local._id}); await Drink.deleteOne({"_id": local._id});
} }
@ -354,10 +352,11 @@ export class iTender {
for (let remote of serverDrinks) { for (let remote of serverDrinks) {
let drink = await Drink.findOne({name: remote.name}); let drink = await Drink.findById(remote._id);
if (!drink) if (!drink)
drink = new Drink(); drink = new Drink();
drink._id = remote._id;
drink.name = remote.name; drink.name = remote.name;
drink.ingredients = remote.ingredients; drink.ingredients = remote.ingredients;
@ -365,11 +364,14 @@ export class iTender {
// Download thumbnail // Download thumbnail
Utils.downloadImage("https://itender.iif.li/images/" + remote._id + ".png", "./public/images/" + drink._id + ".png").then(filepath => { if (!Utils.checkForImage(remote._id)) {
log("Drink " + remote.name + "'s Thumbnail downloaded to " + filepath); try {
}).catch(e => { await Utils.downloadImage("https://itender.iif.li/images/" + remote._id + ".png", "./public/images/" + drink._id + ".png")
log("Drink " + remote.name + " failed to download thumbnail!\n" + e); log("Drink " + remote.name + "'s Thumbnail downloaded");
}); } catch (e) {
log("Drink " + remote.name + " failed to download thumbnail!\n" + e);
}
}
} }

View File

@ -58,7 +58,6 @@ const wsApp = new WebsocketApp();
function init(): Promise<void> { function init(): Promise<void> {
log("Initializing..."); log("Initializing...");
return new Promise(async resolve => { return new Promise(async resolve => {
iTender.setStatus(iTenderStatus.STARTING);
setTimeout( async () => { setTimeout( async () => {
// Network // Network

View File

@ -40,7 +40,7 @@ export class WebHandler {
drinkEle.append(drinkName); drinkEle.append(drinkName);
drinkImg.alt = "Foto von " + drink.name; drinkImg.alt = "Foto von " + drink.name;
drinkImg.src = "/images/" + drink.name + ".png"; drinkImg.src = "/images/" + drink._id + ".png";
drinkName.innerText = drink.name; drinkName.innerText = drink.name;

View File

@ -7,7 +7,6 @@ import {WebHandler} from "./WebHandler";
import {Setup} from "./Setup"; import {Setup} from "./Setup";
import {Pane} from "./Pane"; import {Pane} from "./Pane";
import {RequestType} from "../RequestType"; import {RequestType} from "../RequestType";
import {IDrink} from "../database/IDrink";
import {IJob} from "../database/IJob"; import {IJob} from "../database/IJob";
export class WebWebSocketHandler { export class WebWebSocketHandler {
@ -64,8 +63,9 @@ export class WebWebSocketHandler {
case iTenderStatus.READY: { case iTenderStatus.READY: {
Modal.close("start"); Modal.close("start");
Modal.close("setup"); Modal.close("setup");
Modal.close("fill"); //Modal.close("fill");
if( WebHandler.currentPane != Pane.MENU ) Modal.close("download");
if (WebHandler.currentPane != Pane.MENU)
WebHandler.openPane(Pane.MAIN); WebHandler.openPane(Pane.MAIN);
(document.getElementById("menuBtn") as HTMLButtonElement).disabled = false; (document.getElementById("menuBtn") as HTMLButtonElement).disabled = false;
break; break;
@ -79,6 +79,15 @@ export class WebWebSocketHandler {
modal.open(); modal.open();
break; break;
} }
case iTenderStatus.DOWNLOADING: {
let modal = new Modal("download", "Aktualisieren");
let txt = document.createElement("p");
txt.innerHTML = `Einen Augenblick bitte<br>iTender aktualisiert die Getränke vom Server.`;
modal.addContent(txt);
modal.loader = true;
modal.open();
break;
}
case iTenderStatus.REFRESHING: { case iTenderStatus.REFRESHING: {
/* let modal = new Modal("refreshing", "Aktualisieren..."); /* let modal = new Modal("refreshing", "Aktualisieren...");
let txt = document.createElement("p"); let txt = document.createElement("p");
@ -111,10 +120,19 @@ export class WebWebSocketHandler {
modal.addContent(waterAnimDiv); modal.addContent(waterAnimDiv);
let seconds = document.createElement("p"); let seconds = document.createElement("span");
seconds.innerText = "60s"; seconds.innerText = "60s";
seconds.style.marginRight = "3%";
modal.addContent(seconds); modal.addContent(seconds);
let ml = document.createElement("span");
ml.innerText = "200ml";
modal.addContent(ml);
modal.addContent(document.createElement("br"));
modal.addContent(document.createElement("br"));
let cancelBtn = document.createElement("button"); let cancelBtn = document.createElement("button");
cancelBtn.classList.add("btn", "btn-danger"); cancelBtn.classList.add("btn", "btn-danger");
@ -132,28 +150,53 @@ export class WebWebSocketHandler {
}; };
modal.addContent(cancelBtn); modal.addContent(cancelBtn);
function riseSlowlyUp(lastNumber:number, number: number) {
for (let i = lastNumber; i < number; i++) {
setTimeout(() => {
ml.innerText = i + "ml";
}, (number-lastNumber/1000)+i*4);
}
}
modal.open().then(() => {
modal.open().then( () => {
WebWebSocketHandler.request(RequestType.JOB).then((payload) => { WebWebSocketHandler.request(RequestType.JOB).then((payload) => {
let minus = 0;
let job = payload.data.content as IJob; let job = payload.data.content as IJob;
ml.innerText = Math.floor((job.completeAmount / job.estimatedTime) * minus) + "ml";
waterAnimDiv.style.setProperty("--fillTime", job.estimatedTime + "s"); waterAnimDiv.style.setProperty("--fillTime", job.estimatedTime + "s");
waterAnimDiv.style.backgroundImage = `url("/images/${job.drink.name}.png")`; waterAnimDiv.style.backgroundImage = `url("/images/${job.drink._id}.png")`;
header.innerText = job.drink.name; header.innerText = job.drink.name;
seconds.innerText = job.estimatedTime + "s"; seconds.innerText = job.estimatedTime + "s";
let minus = 0;
let interval = setInterval( () => { let last = 0;
let interval = setInterval(() => {
minus++; minus++;
if( minus+1 > (job.estimatedTime as number) ) if (minus + 1 > (job.estimatedTime as number)) {
{
clearInterval(interval); clearInterval(interval);
} }
seconds.innerText = (job.estimatedTime as number - minus) + "s"; seconds.innerText = (Math.floor(job.estimatedTime as number - minus)) + "s";
}, 1000 ) let calc = Math.floor((job.completeAmount / job.estimatedTime) * minus);
riseSlowlyUp(last, calc)
last = calc;
//ml.innerText = + "ml";
}, 1000);
setTimeout(() => {
txt.innerHTML = "Bitte entnehme den Cocktail!";
/*cancelBtn.classList.add("btn-primary");
cancelBtn.classList.remove("btn-danger");
cancelBtn.innerText = "Schließen";*/
cancelBtn.classList.add("btn-blendout");
waterAnimDiv.classList.add("waterFinished");
cancelBtn.onclick = () => {
modal.close();
}
setTimeout(() => modal.close(), 1000 * 4.5);
}, job.estimatedTime * 1000);
}); });
} ); });
break; break;
} }
@ -250,7 +293,7 @@ export class WebWebSocketHandler {
* @param type * @param type
* @param content * @param content
*/ */
public static request(type: RequestType, content: any = null ): Promise<WebSocketPayload> { public static request(type: RequestType, content: any = null): Promise<WebSocketPayload> {
console.log("Request to " + type) console.log("Request to " + type)
return new Promise(resolve => { return new Promise(resolve => {
WebWebSocketHandler.registerForEvent(WebSocketEvent.RESPONSE, (payload) => { WebWebSocketHandler.registerForEvent(WebSocketEvent.RESPONSE, (payload) => {
@ -258,7 +301,10 @@ export class WebWebSocketHandler {
resolve(payload); resolve(payload);
} }
}); });
WebWebSocketHandler.send(new WebSocketPayload(WebSocketEvent.REQUEST, false, {type: type, content: content})); WebWebSocketHandler.send(new WebSocketPayload(WebSocketEvent.REQUEST, false, {
type: type,
content: content
}));
}); });
} }

View File

@ -51,6 +51,7 @@ block menu
block settings block settings
// Settings // Settings
button.btn.btn-primary#settings_refreshDrinks Getränke herunterladen
block main block main
// Main is build dynamically // Main is build dynamically

View File

@ -1384,6 +1384,14 @@ buffer@^5.6.0:
base64-js "^1.3.1" base64-js "^1.3.1"
ieee754 "^1.1.13" ieee754 "^1.1.13"
buffer@^6.0.3:
version "6.0.3"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6"
integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==
dependencies:
base64-js "^1.3.1"
ieee754 "^1.2.1"
bytes@3.0.0: bytes@3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
@ -1960,7 +1968,7 @@ iconv-lite@0.4.23:
dependencies: dependencies:
safer-buffer ">= 2.1.2 < 3" safer-buffer ">= 2.1.2 < 3"
ieee754@^1.1.13: ieee754@^1.1.13, ieee754@^1.2.1:
version "1.2.1" version "1.2.1"
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==