🚀 refactor demo

This commit is contained in:
platane
2020-10-02 18:00:04 +02:00
committed by Platane
parent 9b92697ef9
commit 64f0b872aa
25 changed files with 561 additions and 605 deletions

View File

@@ -1,14 +1,15 @@
import { getGithubUserContribution, Cell } from "@snk/github-user-contribution";
import { setColor, createEmptyGrid } from "@snk/compute/grid";
import { setColor, createEmptyGrid, Color } from "@snk/compute/grid";
import { createGif } from "@snk/gif-creator";
import { getBestRoute } from "@snk/compute/getBestRoute";
import { createSnake } from "@snk/compute/snake";
export const userContributionToGrid = (cells: Cell[]) => {
const width = Math.max(0, ...cells.map((c) => c.x)) + 1;
const height = Math.max(0, ...cells.map((c) => c.y)) + 1;
const grid = createEmptyGrid(width, height);
for (const c of cells) setColor(grid, c.x, c.y, c.k === 0 ? null : c.k);
for (const c of cells) if (c.k) setColor(grid, c.x, c.y, c.k as Color);
return grid;
};
@@ -18,13 +19,13 @@ export const generateContributionSnake = async (userName: string) => {
const grid0 = userContributionToGrid(cells);
const snake0 = [
const snake0 = createSnake([
{ x: 4, y: -1 },
{ x: 3, y: -1 },
{ x: 2, y: -1 },
{ x: 1, y: -1 },
{ x: 0, y: -1 },
];
]);
const drawOptions = {
sizeBorderRadius: 2,
@@ -36,23 +37,11 @@ export const generateContributionSnake = async (userName: string) => {
colorSnake: "purple",
};
const gameOptions = {
maxSnakeLength: 5,
colors: Array.from({ length: colorScheme.length - 1 }, (_, i) => i + 1),
};
const gifOptions = { delay: 3 };
const commands = getBestRoute(grid0, snake0, gameOptions, 600);
const chain = getBestRoute(grid0, snake0)!;
const buffer = await createGif(
grid0,
snake0,
commands,
drawOptions,
gameOptions,
gifOptions
);
const buffer = await createGif(grid0, chain, drawOptions, gifOptions);
return buffer;
};

View File

@@ -0,0 +1,33 @@
// @ts-ignore
import * as ParkMiller from "park-miller";
import { Color, createEmptyGrid, setColor } from "@snk/compute/grid";
import { fillRandomGrid } from "../generateGrid";
const colors = [1, 2, 3] as Color[];
// empty small grid
export const empty = createEmptyGrid(5, 5);
// empty small grid with a unique color at the middle
export const simple = createEmptyGrid(5, 5);
setColor(simple, 2, 2, 1 as Color);
// empty small grid with color at each corner
export const corner = createEmptyGrid(5, 5);
setColor(corner, 0, 4, 1 as Color);
setColor(corner, 4, 0, 1 as Color);
setColor(corner, 4, 4, 1 as Color);
setColor(corner, 0, 0, 1 as Color);
const create = (width: number, height: number, emptyP: number) => {
const grid = createEmptyGrid(width, height);
const random = new ParkMiller(10);
const rand = (a: number, b: number) => random.integerInRange(a, b - 1);
fillRandomGrid(grid, { colors, emptyP }, rand);
return grid;
};
// small realistic
export const small = create(10, 7, 3);
export const smallPacked = create(10, 7, 1);
export const smallFull = create(10, 7, 0);

View File

@@ -0,0 +1,9 @@
// @ts-ignore
import { createSnake } from "../snake";
const create = (length: number) =>
createSnake(Array.from({ length }, (_, i) => ({ x: i, y: -1 })));
export const snake1 = create(1);
export const snake3 = create(3);
export const snake7 = create(7);

View File

@@ -0,0 +1,19 @@
import { getBestRoute } from "../getBestRoute";
import { Color, createEmptyGrid, setColor } from "../grid";
import { createSnake, snakeToCells } from "../snake";
it("should find best route", () => {
const snk0 = [
{ x: 0, y: 0 },
{ x: 1, y: 0 },
];
const grid = createEmptyGrid(5, 5);
setColor(grid, 3, 3, 1 as Color);
const chain = getBestRoute(grid, createSnake(snk0))!;
expect(snakeToCells(chain[0])[1]).toEqual({ x: 0, y: 0 });
expect(snakeToCells(chain[chain.length - 1])[0]).toEqual({ x: 3, y: 3 });
});

View File

@@ -1,11 +1,11 @@
import { createEmptyGrid, setColor, getColor, isInside } from "../grid";
import { createEmptyGrid, setColor, getColor, isInside, Color } from "../grid";
it("should set / get cell", () => {
const grid = createEmptyGrid(2, 3);
expect(getColor(grid, 0, 1)).toBe(0);
setColor(grid, 0, 1, 1);
setColor(grid, 0, 1, 1 as Color);
expect(getColor(grid, 0, 1)).toBe(1);
});

View File

@@ -1,25 +1,21 @@
import { Grid, Color, setColor, createEmptyGrid } from "./grid";
import { Grid, Color, setColor, setColorEmpty } from "./grid";
const defaultRand = (a: number, b: number) =>
Math.floor(Math.random() * (b - a)) + a;
export const generateRandomGrid = (
width: number,
height: number,
options: { colors: Color[]; emptyP: number } = {
colors: [1, 2, 3],
emptyP: 2,
},
export const fillRandomGrid = (
grid: Grid,
{
colors = [1, 2, 3] as Color[],
emptyP = 2,
}: { colors?: Color[]; emptyP?: number } = {},
rand = defaultRand
): Grid => {
const grid = createEmptyGrid(width, height);
) => {
for (let x = grid.width; x--; )
for (let y = grid.height; y--; ) {
const k = rand(-emptyP, colors.length);
for (let x = width; x--; )
for (let y = height; y--; ) {
const k = rand(-options.emptyP, options.colors.length);
if (k >= 0) setColor(grid, x, y, options.colors[k]);
if (k >= 0) setColor(grid, x, y, colors[k]);
else setColorEmpty(grid, x, y);
}
return grid;
};

View File

@@ -1,4 +1,11 @@
import { Grid, isInsideLarge, getColor, isInside, Color } from "./grid";
import {
Grid,
isInsideLarge,
getColor,
isInside,
Color,
isEmpty,
} from "./grid";
import { around4 } from "./point";
import {
getHeadX,
@@ -41,12 +48,11 @@ export const getAvailableRoutes = (
if (!closeList.some((s) => snakeEquals(nsnake, s))) {
const color = isInside(grid, nx, ny) && getColor(grid, nx, ny);
const chain = [nsnake, ...c];
if (color) {
if (onSolution(chain, color)) return;
if (color && !isEmpty(color)) {
if (onSolution([nsnake, ...c.slice(0, -1)], color)) return;
} else {
if (!openList.some(([s]) => snakeEquals(nsnake, s))) {
const chain = [nsnake, ...c];
openList.push(chain);
openList.sort((a, b) => a.length - b.length);
}
@@ -57,7 +63,7 @@ export const getAvailableRoutes = (
}
};
export const getInterestingAvailableRoutes = (
export const getAvailableInterestingRoutes = (
grid: Grid,
snake0: Snake,
onSolution: (snakes: Snake[], color: Color) => boolean,

View File

@@ -1,152 +1,183 @@
import { Grid, Color, copyGrid, getColor, setColor } from "./grid";
import { Point } from "./point";
import { Snake } from "./snake";
import { getAvailableRoutes } from "./getAvailableRoutes";
import { getAvailableInterestingRoutes } from "./getAvailableRoutes";
import {
Color,
copyGrid,
getColor,
Grid,
gridEquals,
isEmpty,
setColorEmpty,
} from "./grid";
import { copySnake, getHeadX, getHeadY, Snake, snakeEquals } from "./snake";
const isGridEmpty = (grid: Grid) => grid.data.every((x) => x === null);
const createComputeHeuristic = (
grid0: Grid,
_snake0: Snake,
colors: Color[]
) => {
const colorCount: Record<Color, number> = {};
const createHeuristic = (grid0: Grid) => {
const colorCount: Record<Color, number> = [];
for (let x = grid0.width; x--; )
for (let y = grid0.height; y--; ) {
const c = getColor(grid0, x, y);
if (c !== null) colorCount[c] = 1 + (colorCount[c] || 0);
const color = getColor(grid0, x, y);
if (!isEmpty(color))
// @ts-ignore
colorCount[color] = (0 | colorCount[color]) + 1;
}
const values = colors
.map((k) => Array.from({ length: colorCount[k] }, () => k))
const target = Object.entries(colorCount)
.sort(([a], [b]) => +a - +b)
.map(([color, length]: any) => Array.from({ length }, () => +color))
.flat();
return (_grid: Grid, _snake: Snake, stack: Color[]) => {
let score = 0;
const getHeuristic = (_grid: Grid, _snake: Snake, stack: Color[]) =>
stack.reduce((s, x, i) => s + (target[i] === x ? 1 : 0), 0);
for (let i = 0; i < stack.length; i++) {
if (stack[i] === values[i]) {
score += 52;
} else {
const u = Math.abs(stack[i] - values[i]);
const getNextColorHeuristic = (
_grid: Grid,
_snake: Snake,
stack: Color[]
) => {
const x = target[stack.length];
score += 5 - u;
}
}
return score;
return (c: Color) => (x === c ? 1 : 0);
};
const isEnd = (_grid: Grid, _snake: Snake, stack: Color[]) =>
stack.length === target.length;
return { isEnd, getHeuristic, getNextColorHeuristic };
};
const computeKey = (grid: Grid, snake: Snake, stack: Color[]) =>
grid.data.map((x) => x || 0).join("") +
"|" +
snake.map((p) => p.x + "." + p.y).join(",") +
"|" +
stack.join("");
type I = {
h: number;
f: number;
w: number;
key: string;
snake: Snake;
type OpenListItem = {
grid: Grid;
snake: Snake;
chain: Snake[];
stack: Color[];
parent: I | null;
directions: Point[];
weight: number;
heuristic: number;
parent: OpenListItem | null;
};
export const getBestRoute = (
grid0: Grid,
snake0: Snake,
options: { maxSnakeLength: number; colors: Color[] },
maxIterations = 500
) => {
const computeHeuristic = createComputeHeuristic(
grid0,
snake0,
options.colors
);
const unroll = (o: OpenListItem | null): Snake[] =>
!o ? [] : [...unroll(o.parent), ...o.chain.slice().reverse()];
const closeList: Record<string, I> = {};
const openList: I[] = [];
const itemEquals = (
a: { grid: Grid; snake: Snake },
b: { grid: Grid; snake: Snake }
) => snakeEquals(a.snake, b.snake) && gridEquals(a.grid, b.grid);
{
const h = computeHeuristic(grid0, snake0, []);
const w = 0;
const f = h + w;
openList.push({
key: computeKey(grid0, snake0, []),
export const getBestRoute = (grid0: Grid, snake0: Snake) => {
const { isEnd, getNextColorHeuristic } = createHeuristic(grid0);
let grid = copyGrid(grid0);
let snake = copySnake(snake0);
let stack: Color[] = [];
const fullChain: Snake[] = [];
while (!isEnd(grid, snake, stack)) {
const getColorHeuristic = getNextColorHeuristic(grid, snake, stack);
let solution: {
heuristic: number;
chain: Snake[];
color: Color;
} | null = null;
getAvailableInterestingRoutes(
grid,
snake,
(chain: Snake[], color: Color) => {
const heuristic = getColorHeuristic(color);
if (!solution || solution.heuristic < heuristic)
solution = { heuristic, chain, color };
return solution.heuristic === 1;
},
2
);
if (!solution) return null;
const { chain, color } = solution!;
snake = chain[0];
const x = getHeadX(snake);
const y = getHeadY(snake);
setColorEmpty(grid, x, y);
stack.push(color);
for (let i = chain.length; i--; ) fullChain.push(chain[i]);
}
return fullChain;
};
export const getBestRoute2 = (grid0: Grid, snake0: Snake) => {
const { isEnd, getHeuristic, getNextColorHeuristic } = createHeuristic(grid0);
const closeList: { grid: Grid; snake: Snake }[] = [];
const openList: OpenListItem[] = [
{
grid: grid0,
snake: snake0,
stack: [],
snake: snake0,
parent: null,
f,
h,
w,
directions: [],
});
}
weight: 0,
heuristic: getHeuristic(grid0, snake0, []),
chain: [],
},
];
let best = openList[0];
while (openList.length) {
const parent = openList.shift()!;
while (openList.length && maxIterations-- > 0) {
openList.sort((a, b) => a.f - b.f);
const c = openList.shift()!;
if (isEnd(parent.grid, parent.snake, parent.stack)) return unroll(parent);
closeList[c.key] = c;
const solutions: { snake: Snake; chain: Snake[]; color: Color }[] = [];
const getColorHeuristic = getNextColorHeuristic(
parent.grid,
parent.snake,
parent.stack
);
if (c.f < best.f) best = c;
getAvailableInterestingRoutes(
parent.grid,
parent.snake,
(chain: Snake[], color: Color) => {
if (
!solutions[0] ||
getColorHeuristic(solutions[0].color) <= getColorHeuristic(color)
)
solutions.unshift({ snake: chain[0], chain, color });
if (!isGridEmpty(c.grid)) {
const availableRoutes = getAvailableRoutes(
c.grid,
c.snake,
options,
30,
1,
20,
500
);
return solutions.length >= 3;
},
2
);
for (const route of availableRoutes) {
const stack = c.stack.slice();
const grid = copyGrid(c.grid);
const snake = route.snakeN;
for (const { snake, chain, color } of solutions) {
const x = getHeadX(snake);
const y = getHeadY(snake);
const { x, y } = route.snakeN[0];
const grid = copyGrid(parent.grid);
setColorEmpty(grid, x, y);
stack.push(getColor(grid, x, y)!);
setColor(grid, x, y, null);
const stack = [...parent.stack, color];
const key = computeKey(grid, snake, stack);
const weight = parent.weight + chain.length;
const heuristic = getHeuristic(grid, snake, stack);
if (!closeList[key] && !openList.some((s) => s.key === key)) {
const h = computeHeuristic(grid, snake, stack);
const w = c.w + route.directions.length;
const f = w - h;
const item = { grid, stack, snake, chain, weight, heuristic, parent };
openList.push({
key,
grid,
snake,
stack,
parent: c,
h,
w,
f,
directions: route.directions,
});
}
}
if (!closeList.some((c) => itemEquals(c, item))) {
closeList.push(item);
openList.push(item);
} else console.log("hit");
}
openList.sort((a, b) => a.heuristic - b.heuristic);
}
return unwrap(best);
};
const unwrap = (o: I | null): Point[] => {
if (!o) return [];
return [...unwrap(o.parent), ...o.directions];
return null;
};

View File

@@ -1,4 +1,5 @@
export type Color = number;
export type Color = (1 | 2 | 3 | 4 | 5 | 6) & { _tag: "__Color__" };
export type Empty = 0 & { _tag: "__Empty__" };
export type Grid = {
width: number;
@@ -15,24 +16,48 @@ export const isInside = (grid: Grid, x: number, y: number) =>
export const isInsideLarge = (grid: Grid, m: number, x: number, y: number) =>
x >= -m && y >= -m && x < grid.width + m && y < grid.height + m;
export const getColor = (grid: Grid, x: number, y: number) =>
grid.data[getIndex(grid, x, y)];
export const copyGrid = ({ width, height, data }: Grid) => ({
width,
height,
data: Uint8Array.from(data),
});
export const getColor = (grid: Grid, x: number, y: number) =>
grid.data[getIndex(grid, x, y)] as Color | Empty;
export const isEmpty = (color: Color | Empty): color is Empty => color === 0;
export const setColor = (
grid: Grid,
x: number,
y: number,
color: Color | null
color: Color | Empty
) => {
grid.data[getIndex(grid, x, y)] = color || 0;
};
export const setColorEmpty = (grid: Grid, x: number, y: number) => {
setColor(grid, x, y, 0 as Empty);
};
export const isGridEmpty = (grid: Grid) => grid.data.every((x) => x === 0);
export const gridEquals = (a: Grid, b: Grid) =>
a.data.every((_, i) => a.data[i] === b.data[i]);
export const getGridKey = ({ data }: Grid) => {
let key = "";
const n = 5;
const radius = 1 << n;
for (let k = 0; k < data.length; k += n) {
let u = 0;
for (let i = n; i--; ) u += (1 << i) * +!!data[k + i];
key += u.toString(radius);
}
return key;
};
export const createEmptyGrid = (width: number, height: number) => ({
width,
height,

View File

@@ -42,3 +42,5 @@ export const createSnake = (points: Point[]) => {
}
return snake as Snake;
};
export const copySnake = (snake: Snake) => snake.slice() as Snake;

View File

@@ -1,48 +1,20 @@
import { Grid, Color, getColor, isInside, setColor } from "./grid";
import { Point } from "./point";
import {
Color,
getColor,
Grid,
isEmpty,
isInside,
setColorEmpty,
} from "./grid";
import { getHeadX, getHeadY, Snake } from "./snake";
export const moveSnake = (snake: Point[], headx: number, heady: number) => {
for (let k = snake.length - 1; k > 0; k--) {
snake[k].x = snake[k - 1].x;
snake[k].y = snake[k - 1].y;
}
snake[0].x = headx;
snake[0].y = heady;
};
export const step = (grid: Grid, stack: Color[], snake: Snake) => {
const x = getHeadX(snake);
const y = getHeadY(snake);
const color = getColor(grid, x, y);
export const stepSnake = (
snake: Point[],
direction: Point,
options: { maxSnakeLength: number }
) => {
const headx = snake[0].x + direction.x;
const heady = snake[0].y + direction.y;
if (snake.length === options.maxSnakeLength) {
moveSnake(snake, headx, heady);
} else {
snake.unshift({ x: headx, y: heady });
if (isInside(grid, x, y) && !isEmpty(color)) {
stack.push(color);
setColorEmpty(grid, x, y);
}
};
export const stepPicking = (grid: Grid, snake: Point[], stack: Color[]) => {
if (isInside(grid, snake[0].x, snake[0].y)) {
const c = getColor(grid, snake[0].x, snake[0].y);
if (c) {
setColor(grid, snake[0].x, snake[0].y, null);
stack.push(c);
}
}
};
export const step = (
grid: Grid,
snake: Point[],
stack: Color[],
direction: Point,
options: { maxSnakeLength: number }
) => {
stepSnake(snake, direction, options);
stepPicking(grid, snake, stack);
};

View File

@@ -1,33 +1,19 @@
import { createCanvas } from "./canvas";
import { samples } from "./samples";
import { getInterestingAvailableRoutes } from "@snk/compute/getAvailableRoutes";
import { createSnake, Snake, snakeToCells } from "@snk/compute/snake";
import { Snake, snakeToCells } from "@snk/compute/snake";
import { GUI } from "dat.gui";
import { Point } from "@snk/compute/point";
//
// init
const label = new URLSearchParams(window.location.search).get("sample");
const { grid: grid0 } = samples.find((s) => s.label === label) || samples[0];
import { grid, snake } from "./sample";
import { getAvailableInterestingRoutes } from "@snk/compute/getAvailableRoutes";
import type { Point } from "@snk/compute/point";
//
// compute
const snake0 = createSnake([
//
{ x: -1, y: -1 },
{ x: -1, y: 0 },
{ x: -1, y: 1 },
{ x: -1, y: 2 },
{ x: -1, y: 3 },
]);
const routes: Snake[][] = [];
getInterestingAvailableRoutes(
grid0,
snake0,
(snakes) => {
routes.push(snakes);
getAvailableInterestingRoutes(
grid,
snake,
(chain) => {
routes.push(chain);
return routes.length > 10;
},
2
@@ -38,10 +24,10 @@ const config = { routeN: 0, routeK: 0 };
//
// draw
const { canvas, ctx, draw } = createCanvas(grid0);
const { canvas, ctx, draw } = createCanvas(grid);
document.body.appendChild(canvas);
draw(grid0, snake0, []);
draw(grid, snake, []);
let cancel: number;
@@ -53,9 +39,9 @@ const onChange = () => {
cancelAnimationFrame(cancel);
cancel = requestAnimationFrame(onChange);
const chain = routes[config.routeN] || [snake0];
const chain = routes[config.routeN] || [snake];
draw(grid0, chain[mod(-t, chain.length)], []);
draw(grid, chain[mod(-t, chain.length)], []);
const cells: Point[] = [];
chain.forEach((s) => cells.push(...snakeToCells(s)));

View File

@@ -1,48 +1,45 @@
import { copyGrid } from "@snk/compute/grid";
import { copySnake } from "@snk/compute/snake";
import { createCanvas } from "./canvas";
import { getBestRoute } from "../compute/getBestRoute";
import { Color, copyGrid } from "../compute/grid";
import { grid, snake } from "./sample";
import { step } from "@snk/compute/step";
import { getBestRoute } from "@snk/compute/getBestRoute";
import { samples } from "./samples";
//
// init
const label = new URLSearchParams(window.location.search).get("sample");
const { grid: grid0, snake: snake0, gameOptions } =
samples.find((s) => s.label === label) || samples[0];
//
// compute
const s0 = Date.now();
const bestRoute = getBestRoute(grid0, snake0, gameOptions);
console.log(`computed in ${Date.now() - s0}ms`);
const chain = [snake, ...getBestRoute(grid, snake)!];
//
// draw
const { draw } = createCanvas(grid0);
let k = 0;
//
// controls
const { canvas, draw } = createCanvas(grid);
document.body.appendChild(canvas);
const inputK: any = document.createElement("input");
inputK.type = "range";
inputK.style.width = "100%";
inputK.min = 0;
inputK.max = bestRoute.length;
inputK.step = 1;
inputK.value = 0;
inputK.addEventListener("input", () => {
const snake = copySnake(snake0);
const grid = copyGrid(grid0);
const stack: any[] = [];
const onChange = () => {
debugger;
for (let i = 0; i < +inputK.value; i++)
step(grid, snake, stack, bestRoute[i], gameOptions);
const grid0 = copyGrid(grid);
const stack0: Color[] = [];
let snake0 = snake;
chain.slice(0, k).forEach((s) => {
snake0 = s;
step(grid0, stack0, snake0);
});
draw(grid, snake, stack);
draw(grid0, snake0, stack0);
};
onChange();
const input = document.createElement("input") as any;
input.type = "range";
input.value = 0;
input.step = 1;
input.min = 0;
input.max = chain.length;
input.style.width = "90%";
input.addEventListener("input", () => {
k = +input.value;
onChange();
});
document.body.appendChild(inputK);
draw(grid0, snake0, []);
document.body.append(input);
document.body.addEventListener("click", () => input.focus());

View File

@@ -1,48 +0,0 @@
import { copyGrid } from "@snk/compute/grid";
import { copySnake } from "@snk/compute/snake";
import { createCanvas } from "./canvas";
import { step } from "@snk/compute/step";
import { getBestRoute } from "@snk/compute/getBestRoute";
import { samples } from "./samples";
//
// init
const label = "realistic";
const { grid: grid0, snake: snake0, gameOptions } = samples.find(
(s) => s.label === label
);
//
// compute
const s0 = performance.now();
const bestRoute = getBestRoute(grid0, snake0, gameOptions, 120);
console.log(performance.now() - s0);
//
// draw
const { draw } = createCanvas(grid0);
//
// controls
const inputK: any = document.createElement("input");
inputK.type = "range";
inputK.style.width = "100%";
inputK.min = 0;
inputK.max = bestRoute.length;
inputK.step = 1;
inputK.value = 0;
inputK.addEventListener("input", () => {
const snake = copySnake(snake0);
const grid = copyGrid(grid0);
const stack: any[] = [];
for (let i = 0; i < +inputK.value; i++)
step(grid, snake, stack, bestRoute[i], gameOptions);
draw(grid, snake, stack);
});
document.body.appendChild(inputK);
draw(grid0, snake0, []);

14
packages/demo/sample.ts Normal file
View File

@@ -0,0 +1,14 @@
import { Grid } from "@snk/compute/grid";
import { Snake } from "@snk/compute/snake";
import * as grids from "@snk/compute/__fixtures__/grid";
import * as snakes from "@snk/compute/__fixtures__/snake";
const sp = new URLSearchParams(window.location.search);
const gLabel = sp.get("grid") || "simple";
const sLabel = sp.get("snake") || "snake3";
//@ts-ignore
export const grid: Grid = grids[gLabel] || grids.simple;
//@ts-ignore
export const snake: Snake = snakes[sLabel] || snakes.snake3;

View File

@@ -1,85 +0,0 @@
// @ts-ignore
import * as ParkMiller from "park-miller";
import { generateRandomGrid } from "@snk/compute/generateGrid";
import { createEmptyGrid, setColor } from "@snk/compute/grid";
export const samples: any[] = [];
{
const gameOptions = {
colors: [1, 2, 3],
maxSnakeLength: 1,
};
const snake = [{ x: 0, y: -1 }];
const grid = createEmptyGrid(6, 6);
samples.push({
label: "empty",
grid,
snake,
gameOptions,
});
}
{
const gameOptions = {
colors: [1, 2, 3],
maxSnakeLength: 1,
};
const snake = [{ x: 0, y: -1 }];
const grid = createEmptyGrid(6, 6);
setColor(grid, 2, 2, 2);
samples.push({
label: "small",
grid,
snake,
gameOptions,
});
}
{
const gameOptions = {
colors: [1, 2, 3],
maxSnakeLength: 5,
};
const random = new ParkMiller(10);
const rand = (a: number, b: number) => random.integerInRange(a, b - 1);
const grid = generateRandomGrid(52, 7, { ...gameOptions, emptyP: 2 }, rand);
const snake = [
{ x: 4, y: -1 },
{ x: 3, y: -1 },
{ x: 2, y: -1 },
{ x: 1, y: -1 },
{ x: 0, y: -1 },
];
samples.push({
label: "realistic",
grid,
snake,
gameOptions,
});
}
{
const gameOptions = {
colors: [1, 2, 3],
maxSnakeLength: 5,
};
const random = new ParkMiller(10);
const rand = (a: number, b: number) => random.integerInRange(a, b - 1);
const grid = generateRandomGrid(20, 7, { ...gameOptions, emptyP: 2 }, rand);
const snake = [
{ x: 4, y: -1 },
{ x: 3, y: -1 },
{ x: 2, y: -1 },
{ x: 1, y: -1 },
{ x: 0, y: -1 },
];
samples.push({
label: "realistic-small",
grid,
snake,
gameOptions,
});
}

View File

@@ -13,7 +13,6 @@ const config: Configuration = {
entry: {
"demo.getAvailableRoutes": "./demo.getAvailableRoutes",
"demo.getBestRoute": "./demo.getBestRoute",
"demo.index": "./demo.index",
},
resolve: { extensions: [".ts", ".js"] },
output: {
@@ -27,14 +26,16 @@ const config: Configuration = {
exclude: /node_modules/,
test: /\.(js|ts)$/,
loader: "ts-loader",
options: {
compilerOptions: {
lib: ["dom", "ES2020"],
target: "ES2020",
},
},
},
],
},
plugins: [
new HtmlWebpackPlugin({
filename: "index.html",
chunks: ["demo.index"],
}),
new HtmlWebpackPlugin({
filename: "demo-getAvailableRoutes.html",
chunks: ["demo.getAvailableRoutes"],

View File

@@ -69,6 +69,8 @@ export const drawCircleStack = (
x * o.sizeCell + (o.sizeCell - o.sizeDot) / 2,
y * o.sizeCell + (o.sizeCell - o.sizeDot) / 2
);
//@ts-ignore
ctx.fillStyle = o.colorDots[stack[i]];
ctx.strokeStyle = o.colorBorder;
ctx.lineWidth = 1;

View File

@@ -33,6 +33,7 @@ export const drawWorld = (
ctx.save();
ctx.translate(o.sizeCell, (grid.height + 4) * o.sizeCell);
for (let i = 0; i < stack.length; i++) {
// @ts-ignore
ctx.fillStyle = o.colorDots[stack[i]];
ctx.fillRect(i * m, 0, m, 10);
}

View File

@@ -1,6 +1,9 @@
import * as fs from "fs";
import * as path from "path";
import { createGif } from "..";
import { generateRandomGrid } from "@snk/compute/generateGrid";
import { getBestRoute } from "@snk/compute/getBestRoute";
import * as grids from "@snk/compute/__fixtures__/grid";
import { snake3 as snake } from "@snk/compute/__fixtures__/snake";
const drawOptions = {
sizeBorderRadius: 2,
@@ -12,31 +15,29 @@ const drawOptions = {
colorSnake: "purple",
};
const gameOptions = { maxSnakeLength: 5, colors: [1, 2, 3, 4] };
const gifOptions = { delay: 18 };
const gifOptions = { delay: 200 };
const dir = path.resolve(__dirname, "__snapshots__");
it("should generate gif", async () => {
const grid = generateRandomGrid(7, 7, { ...gameOptions, emptyP: 3 });
try {
fs.mkdirSync(dir);
} catch (err) {}
const snake = [
{ x: 4, y: -1 },
{ x: 3, y: -1 },
{ x: 2, y: -1 },
{ x: 1, y: -1 },
{ x: 0, y: -1 },
];
for (const key of [
"empty",
"simple",
"corner",
"small",
"smallPacked",
] as const)
it(`should generate ${key} gif`, async () => {
const grid = grids[key];
const commands = getBestRoute(grid, snake, gameOptions, 50).slice(0, 9);
const chain = [snake, ...getBestRoute(grid, snake)!];
const gif = await createGif(
grid,
snake,
commands,
drawOptions,
gameOptions,
gifOptions
);
const gif = await createGif(grid, chain, drawOptions, gifOptions);
expect(gif).toBeDefined();
});
expect(gif).toBeDefined();
fs.writeFileSync(path.resolve(dir, key + ".gif"), gif);
});

View File

@@ -1,35 +0,0 @@
import { createGif } from "..";
import { generateRandomGrid } from "@snk/compute/generateGrid";
import { getBestRoute } from "@snk/compute/getBestRoute";
const drawOptions = {
sizeBorderRadius: 2,
sizeCell: 16,
sizeDot: 12,
colorBorder: "#1b1f230a",
colorDots: { 1: "#9be9a8", 2: "#40c463", 3: "#30a14e", 4: "#216e39" },
colorEmpty: "#ebedf0",
colorSnake: "purple",
};
const gameOptions = { maxSnakeLength: 5, colors: [1, 2, 3, 4] };
const gifOptions = { delay: 20 };
const grid = generateRandomGrid(14, 7, { ...gameOptions, emptyP: 3 });
const snake = [
{ x: 4, y: -1 },
{ x: 3, y: -1 },
{ x: 2, y: -1 },
{ x: 1, y: -1 },
{ x: 0, y: -1 },
];
const commands = getBestRoute(grid, snake, gameOptions, 50);
createGif(grid, snake, commands, drawOptions, gameOptions, gifOptions).then(
(buffer) => {
process.stdout.write(buffer);
}
);

View File

@@ -2,8 +2,7 @@ import * as fs from "fs";
import * as path from "path";
import { createCanvas } from "canvas";
import { Grid, copyGrid, Color } from "@snk/compute/grid";
import { Point } from "@snk/compute/point";
import { copySnake } from "@snk/compute/snake";
import { Snake } from "@snk/compute/snake";
import { drawWorld } from "@snk/draw/drawWorld";
import { step } from "@snk/compute/step";
import * as tmp from "tmp";
@@ -11,17 +10,15 @@ import * as execa from "execa";
export const createGif = async (
grid0: Grid,
snake0: Point[],
commands: Point[],
chain: Snake[],
drawOptions: Parameters<typeof drawWorld>[4],
gameOptions: Parameters<typeof step>[4],
gifOptions: { delay: number }
) => {
let snake = chain[0];
const grid = copyGrid(grid0);
const snake = copySnake(snake0);
const stack: Color[] = [];
const width = drawOptions.sizeCell * (grid.width + 4);
const width = drawOptions.sizeCell * (grid.width + 2);
const height = drawOptions.sizeCell * (grid.height + 4) + 100;
const { name: dir, removeCallback: cleanUp } = tmp.dirSync({
@@ -48,11 +45,11 @@ export const createGif = async (
};
try {
writeImage(0);
for (let i = 0; i < chain.length; i++) {
snake = chain[i];
for (let i = 0; i < commands.length; i++) {
step(grid, snake, stack, commands[i], gameOptions);
writeImage(i + 1);
step(grid, stack, snake);
writeImage(i);
}
const outFileName = path.join(dir, "out.gif");

View File

@@ -10,10 +10,6 @@
},
"devDependencies": {
"@types/execa": "2.0.0",
"@types/tmp": "0.2.0",
"@zeit/ncc": "0.22.3"
},
"scripts": {
"dev": "ncc run __tests__/dev.ts --quiet | tail -n +2 > out.gif "
"@types/tmp": "0.2.0"
}
}

View File

@@ -1,7 +1,6 @@
{
"compilerOptions": {
"lib": ["dom", "ES2020"],
"target": "ES2020",
"strict": true,
"skipLibCheck": true,
"noUnusedLocals": true,

290
yarn.lock
View File

@@ -554,9 +554,9 @@
"@types/node" "*"
"@types/html-minifier-terser@^5.0.0":
version "5.1.0"
resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.0.tgz#551a4589b6ee2cc9c1dff08056128aec29b94880"
integrity sha512-iYCgjm1dGPRuo12+BStjd1HiVQqhlRhWDOQigNxn023HcjnhsiFz9pc6CzJj4HwDCSQca9bxTL4PxJDbkdm3PA==
version "5.1.1"
resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz#3c9ee980f1a10d6021ae6632ca3e79ca2ec4fb50"
integrity sha512-giAlZwstKbmvMk1OO7WXSj4OZ0keXAcl2TQq4LWHiiPH2ByaH7WeUzng+Qej8UPxxv+8lRTuouo0iaNDBuzIBA==
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
version "2.0.3"
@@ -646,25 +646,25 @@
integrity sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==
"@types/uglify-js@*":
version "3.9.3"
resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.9.3.tgz#d94ed608e295bc5424c9600e6b8565407b6b4b6b"
integrity sha512-KswB5C7Kwduwjj04Ykz+AjvPcfgv/37Za24O2EDzYNbwyzOo8+ydtvzUfZ5UMguiVu29Gx44l1A6VsPPcmYu9w==
version "3.11.0"
resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.11.0.tgz#2868d405cc45cd9dc3069179052103032c33afbc"
integrity sha512-I0Yd8TUELTbgRHq2K65j8rnDPAzAP+DiaF/syLem7yXwYLsHZhPd+AM2iXsWmf9P2F2NlFCgl5erZPQx9IbM9Q==
dependencies:
source-map "^0.6.1"
"@types/webpack-sources@*":
version "1.4.0"
resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-1.4.0.tgz#e58f1f05f87d39a5c64cf85705bdbdbb94d4d57e"
integrity sha512-c88dKrpSle9BtTqR6ifdaxu1Lvjsl3C5OsfvuUbUwdXymshv1TkufUAXBajCCUM/f/TmnkZC/Esb03MinzSiXQ==
version "2.0.0"
resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-2.0.0.tgz#08216ab9be2be2e1499beaebc4d469cec81e82a7"
integrity sha512-a5kPx98CNFRKQ+wqawroFunvFqv7GHm/3KOI52NY9xWADgc8smu4R6prt4EU/M4QfVjvgBkMqU4fBhw3QfMVkg==
dependencies:
"@types/node" "*"
"@types/source-list-map" "*"
source-map "^0.7.3"
"@types/webpack@^4.41.8":
version "4.41.21"
resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.21.tgz#cc685b332c33f153bb2f5fc1fa3ac8adeb592dee"
integrity sha512-2j9WVnNrr/8PLAB5csW44xzQSJwS26aOnICsP3pSGCEdsu6KYtfQ6QJsVUKHWRnm1bL7HziJsfh5fHqth87yKA==
version "4.41.22"
resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.22.tgz#ff9758a17c6bd499e459b91e78539848c32d0731"
integrity sha512-JQDJK6pj8OMV9gWOnN1dcLCyU9Hzs6lux0wBO4lr1+gyEhIBR9U3FMrz12t2GPkg110XAxEAw2WHF6g7nZIbRQ==
dependencies:
"@types/anymatch" "*"
"@types/node" "*"
@@ -892,11 +892,21 @@ ajv-errors@^1.0.0:
integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==
ajv-keywords@^3.1.0, ajv-keywords@^3.4.1:
version "3.5.1"
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.1.tgz#b83ca89c5d42d69031f424cad49aada0236c6957"
integrity sha512-KWcq3xN8fDjSB+IMoh2VaXVhRI0BBGxoYp3rx7Pkb6z0cFjYR9Q9l4yZqqals0/zsioCmocC5H6UvsGD4MoIBA==
version "3.5.2"
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
ajv@^6.1.0, ajv@^6.10.2, ajv@^6.5.5:
ajv@^6.1.0, ajv@^6.10.2:
version "6.12.5"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.5.tgz#19b0e8bae8f476e5ba666300387775fb1a00a4da"
integrity sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==
dependencies:
fast-deep-equal "^3.1.1"
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
ajv@^6.5.5:
version "6.12.3"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.3.tgz#18c5af38a111ddeb4f2697bd78d68abc1cabd706"
integrity sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==
@@ -1036,14 +1046,15 @@ array-unique@^0.3.2:
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
asn1.js@^4.0.0:
version "4.10.1"
resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0"
integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==
asn1.js@^5.2.0:
version "5.4.1"
resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07"
integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==
dependencies:
bn.js "^4.0.0"
inherits "^2.0.1"
minimalistic-assert "^1.0.0"
safer-buffer "^2.1.0"
asn1@~0.2.3:
version "0.2.4"
@@ -1235,9 +1246,9 @@ bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.4.0:
integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==
bn.js@^5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.2.tgz#c9686902d3c9a27729f43ab10f9d79c2004da7b0"
integrity sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA==
version "5.1.3"
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.3.tgz#beca005408f642ebebea80b042b4d18d2ac0ee6b"
integrity sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==
body-parser@1.19.0:
version "1.19.0"
@@ -1353,15 +1364,15 @@ browserify-rsa@^4.0.0, browserify-rsa@^4.0.1:
randombytes "^2.0.1"
browserify-sign@^4.0.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.0.tgz#545d0b1b07e6b2c99211082bf1b12cce7a0b0e11"
integrity sha512-hEZC1KEeYuoHRqhGhTy6gWrpJA3ZDjFWv0DE61643ZnOXAKJb3u7yWcrU0mMc9SwAqK1n7myPGndkp0dFG7NFA==
version "4.2.1"
resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3"
integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==
dependencies:
bn.js "^5.1.1"
browserify-rsa "^4.0.1"
create-hash "^1.2.0"
create-hmac "^1.1.7"
elliptic "^6.5.2"
elliptic "^6.5.3"
inherits "^2.0.4"
parse-asn1 "^5.1.5"
readable-stream "^3.6.0"
@@ -1556,10 +1567,10 @@ chokidar@^2.1.8:
optionalDependencies:
fsevents "^1.2.7"
chokidar@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.0.tgz#b30611423ce376357c765b9b8f904b9fba3c0be8"
integrity sha512-aXAaho2VJtisB/1fg1+3nlLJqGOuewTzQpd/Tz0yTg2R0e4IGtshYvtjowyEumcBv2z+y4+kc75Mz7j5xJskcQ==
chokidar@^3.4.1:
version "3.4.2"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.2.tgz#38dc8e658dec3809741eb3ef7bb0a47fe424232d"
integrity sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==
dependencies:
anymatch "~3.1.1"
braces "~3.0.2"
@@ -1812,12 +1823,12 @@ core-util-is@1.0.2, core-util-is@~1.0.0:
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
create-ecdh@^4.0.0:
version "4.0.3"
resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff"
integrity sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==
version "4.0.4"
resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e"
integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==
dependencies:
bn.js "^4.1.0"
elliptic "^6.0.0"
elliptic "^6.5.3"
create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0:
version "1.2.0"
@@ -2170,9 +2181,9 @@ domelementtype@1, domelementtype@^1.3.1:
integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==
domelementtype@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.0.1.tgz#1f8bdfe91f5a78063274e803b4bdcedf6e94f94d"
integrity sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==
version "2.0.2"
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.0.2.tgz#f3b6e549201e46f588b59463dd77187131fe6971"
integrity sha512-wFwTwCVebUrMgGeAwRL/NhZtHAUyT9n9yg4IMDwf10+6iCMxSkVq9MGCVEH+QZWo1nNidy8kNvwmv4zWHDTqvA==
domexception@^2.0.1:
version "2.0.1"
@@ -2235,7 +2246,7 @@ ee-first@1.1.1:
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
elliptic@^6.0.0, elliptic@^6.5.2:
elliptic@^6.5.3:
version "6.5.3"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6"
integrity sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==
@@ -2309,19 +2320,37 @@ error-ex@^1.3.1:
is-arrayish "^0.2.1"
es-abstract@^1.17.0-next.1, es-abstract@^1.17.5:
version "1.17.6"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.6.tgz#9142071707857b2cacc7b89ecb670316c3e2d52a"
integrity sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==
version "1.17.7"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.7.tgz#a4de61b2f66989fc7421676c1cb9787573ace54c"
integrity sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==
dependencies:
es-to-primitive "^1.2.1"
function-bind "^1.1.1"
has "^1.0.3"
has-symbols "^1.0.1"
is-callable "^1.2.0"
is-regex "^1.1.0"
object-inspect "^1.7.0"
is-callable "^1.2.2"
is-regex "^1.1.1"
object-inspect "^1.8.0"
object-keys "^1.1.1"
object.assign "^4.1.0"
object.assign "^4.1.1"
string.prototype.trimend "^1.0.1"
string.prototype.trimstart "^1.0.1"
es-abstract@^1.18.0-next.0, es-abstract@^1.18.0-next.1:
version "1.18.0-next.1"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.1.tgz#6e3a0a4bda717e5023ab3b8e90bec36108d22c68"
integrity sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==
dependencies:
es-to-primitive "^1.2.1"
function-bind "^1.1.1"
has "^1.0.3"
has-symbols "^1.0.1"
is-callable "^1.2.2"
is-negative-zero "^2.0.0"
is-regex "^1.1.1"
object-inspect "^1.8.0"
object-keys "^1.1.1"
object.assign "^4.1.1"
string.prototype.trimend "^1.0.1"
string.prototype.trimstart "^1.0.1"
@@ -2375,17 +2404,22 @@ esprima@^4.0.0, esprima@^4.0.1:
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
esrecurse@^4.1.0:
version "4.2.1"
resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf"
integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==
version "4.3.0"
resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
dependencies:
estraverse "^4.1.0"
estraverse "^5.2.0"
estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0:
estraverse@^4.1.1, estraverse@^4.2.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
estraverse@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880"
integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==
esutils@^2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
@@ -2397,14 +2431,14 @@ etag@~1.8.1:
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
eventemitter3@^4.0.0:
version "4.0.4"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384"
integrity sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==
version "4.0.7"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
events@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/events/-/events-3.1.0.tgz#84279af1b34cb75aa88bf5ff291f6d0bd9b31a59"
integrity sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg==
version "3.2.0"
resolved "https://registry.yarnpkg.com/events/-/events-3.2.0.tgz#93b87c18f8efcd4202a461aec4dfc0556b639379"
integrity sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==
eventsource@^1.0.7:
version "1.0.7"
@@ -2690,9 +2724,9 @@ flush-write-stream@^1.0.0:
readable-stream "^2.3.6"
follow-redirects@^1.0.0:
version "1.12.1"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.12.1.tgz#de54a6205311b93d60398ebc01cf7015682312b6"
integrity sha512-tmRv0AVuR7ZyouUHLeNSiO6pqulF7dYa3s19c6t+wz9LD69/uSzdMxJ2S91nTI9U3rt/IldxpzMOFejp6f0hjg==
version "1.13.0"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db"
integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==
for-in@^1.0.2:
version "1.0.2"
@@ -2950,7 +2984,7 @@ has-flag@^4.0.0:
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
has-symbols@^1.0.0, has-symbols@^1.0.1:
has-symbols@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
@@ -3342,10 +3376,10 @@ is-buffer@^1.1.5:
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
is-callable@^1.1.4, is-callable@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.0.tgz#83336560b54a38e35e3a2df7afd0454d691468bb"
integrity sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==
is-callable@^1.1.4, is-callable@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9"
integrity sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==
is-ci@^2.0.0:
version "2.0.0"
@@ -3449,6 +3483,11 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1:
dependencies:
is-extglob "^2.1.1"
is-negative-zero@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.0.tgz#9553b121b0fac28869da9ed459e20c7543788461"
integrity sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=
is-number@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
@@ -3492,10 +3531,10 @@ is-potential-custom-element-name@^1.0.0:
resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz#0c52e54bcca391bb2c494b21e8626d7336c6e397"
integrity sha1-DFLlS8yjkbssSUsh6GJtczbG45c=
is-regex@^1.0.4, is-regex@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.0.tgz#ece38e389e490df0dc21caea2bd596f987f767ff"
integrity sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==
is-regex@^1.0.4, is-regex@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9"
integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==
dependencies:
has-symbols "^1.0.1"
@@ -4176,15 +4215,20 @@ lodash.sortby@^4.7.0:
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15:
lodash@^4.17.11, lodash@^4.17.14:
version "4.17.20"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
lodash@^4.17.13, lodash@^4.17.15:
version "4.17.19"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==
loglevel@^1.6.8:
version "1.6.8"
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.8.tgz#8a25fb75d092230ecd4457270d80b54e28011171"
integrity sha512-bsU7+gc9AJ2SqpzxwU3+1fedl8zAntbtC5XYlt3s2j1hJcn2PsXSmgN8TaLG/J1/2mod4+cE/3vNL70/c1RNCA==
version "1.7.0"
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.0.tgz#728166855a740d59d38db01cf46f042caa041bb0"
integrity sha512-i2sY04nal5jDcagM3FMfG++T69GEEM8CYuOfeOIvmXzOIcwE9a/CJPR0MFM97pYMj/u10lzz7/zd7+qwhrBTqQ==
lower-case@^2.0.1:
version "2.0.1"
@@ -4319,11 +4363,16 @@ miller-rabin@^4.0.0:
bn.js "^4.0.0"
brorand "^1.0.1"
mime-db@1.44.0, "mime-db@>= 1.43.0 < 2":
mime-db@1.44.0:
version "1.44.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92"
integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==
"mime-db@>= 1.43.0 < 2":
version "1.45.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.45.0.tgz#cceeda21ccd7c3a745eba2decd55d4b73e7879ea"
integrity sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==
mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24:
version "2.1.27"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f"
@@ -4417,7 +4466,7 @@ mkdirp@1.x:
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3:
mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5:
version "0.5.5"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
@@ -4523,10 +4572,10 @@ no-case@^3.0.3:
lower-case "^2.0.1"
tslib "^1.10.0"
node-forge@0.9.0:
version "0.9.0"
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579"
integrity sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==
node-forge@^0.10.0:
version "0.10.0"
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3"
integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==
node-int64@^0.4.0:
version "0.4.0"
@@ -4706,20 +4755,20 @@ object-copy@^0.1.0:
define-property "^0.2.5"
kind-of "^3.0.3"
object-inspect@^1.7.0:
object-inspect@^1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0"
integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==
object-is@^1.0.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.2.tgz#c5d2e87ff9e119f78b7a088441519e2eec1573b6"
integrity sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==
version "1.1.3"
resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.3.tgz#2e3b9e65560137455ee3bd62aec4d90a2ea1cc81"
integrity sha512-teyqLvFWzLkq5B9ki8FVWA902UER2qkxmdA4nLf+wjOLAWgxzCWZNCxpDq9MvE8MmhWNr+I8w3BN49Vx36Y6Xg==
dependencies:
define-properties "^1.1.3"
es-abstract "^1.17.5"
es-abstract "^1.18.0-next.1"
object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1:
object-keys@^1.0.12, object-keys@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
@@ -4731,15 +4780,15 @@ object-visit@^1.0.0:
dependencies:
isobject "^3.0.0"
object.assign@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da"
integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==
object.assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.1.tgz#303867a666cdd41936ecdedfb1f8f3e32a478cdd"
integrity sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==
dependencies:
define-properties "^1.1.2"
function-bind "^1.1.1"
has-symbols "^1.0.0"
object-keys "^1.0.11"
define-properties "^1.1.3"
es-abstract "^1.18.0-next.0"
has-symbols "^1.0.1"
object-keys "^1.1.1"
object.getownpropertydescriptors@^2.0.3:
version "2.1.0"
@@ -4912,13 +4961,12 @@ park-miller@1.1.0:
integrity sha512-6mLXc2jkM9dcavPoxDHfof2QM/baCsrgK51iHbJDHl94AwymJv2Z/iGKQVwJMWUAXFiIV6FzY9UskjU3+KvLuA==
parse-asn1@^5.0.0, parse-asn1@^5.1.5:
version "5.1.5"
resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.5.tgz#003271343da58dc94cace494faef3d2147ecea0e"
integrity sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==
version "5.1.6"
resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4"
integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==
dependencies:
asn1.js "^4.0.0"
asn1.js "^5.2.0"
browserify-aes "^1.0.0"
create-hash "^1.1.0"
evp_bytestokey "^1.0.0"
pbkdf2 "^3.0.3"
safe-buffer "^5.1.1"
@@ -5076,13 +5124,13 @@ pkg-dir@^4.2.0:
find-up "^4.0.0"
portfinder@^1.0.26:
version "1.0.26"
resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.26.tgz#475658d56ca30bed72ac7f1378ed350bd1b64e70"
integrity sha512-Xi7mKxJHHMI3rIUrnm/jjUgwhbYMkp/XKEcZX3aG4BrumLpq3nmoQMX+ClYnDZnZ/New7IatC1no5RX0zo1vXQ==
version "1.0.28"
resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778"
integrity sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==
dependencies:
async "^2.6.2"
debug "^3.1.1"
mkdirp "^0.5.1"
mkdirp "^0.5.5"
posix-character-classes@^0.1.0:
version "0.1.1"
@@ -5241,9 +5289,9 @@ querystring@0.2.0:
integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=
querystringify@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e"
integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==
version "2.2.0"
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6"
integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0:
version "2.1.0"
@@ -5603,11 +5651,11 @@ select-hose@^2.0.0:
integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=
selfsigned@^1.10.7:
version "1.10.7"
resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.7.tgz#da5819fd049d5574f28e88a9bcc6dbc6e6f3906b"
integrity sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA==
version "1.10.8"
resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.8.tgz#0d17208b7d12c33f8eac85c41835f27fc3d81a30"
integrity sha512-2P4PtieJeEwVgTU9QEcwIRDQ/mXJLX8/+I3ur+Pg16nS8oNbrGxEso9NyYWy8NAmXiNl4dlAp5MwoNeCWzON4w==
dependencies:
node-forge "0.9.0"
node-forge "^0.10.0"
"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0:
version "5.7.1"
@@ -5643,10 +5691,10 @@ send@0.17.1:
range-parser "~1.2.1"
statuses "~1.5.0"
serialize-javascript@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-3.1.0.tgz#8bf3a9170712664ef2561b44b691eafe399214ea"
integrity sha512-JIJT1DGiWmIKhzRsG91aS6Ze4sFUrYbltlkg2onR5OrnNM02Kl/hnY/T4FN2omvyeBbQmMJv+K4cPOpGzOTFBg==
serialize-javascript@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa"
integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==
dependencies:
randombytes "^2.1.0"
@@ -6186,15 +6234,15 @@ terminal-link@^2.0.0:
supports-hyperlinks "^2.0.0"
terser-webpack-plugin@^1.4.3:
version "1.4.4"
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.4.tgz#2c63544347324baafa9a56baaddf1634c8abfc2f"
integrity sha512-U4mACBHIegmfoEe5fdongHESNJWqsGU+W0S/9+BmYGVQDw1+c2Ow05TpMhxjPK1sRb7cuYq1BPl1e5YHJMTCqA==
version "1.4.5"
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz#a217aefaea330e734ffacb6120ec1fa312d6040b"
integrity sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==
dependencies:
cacache "^12.0.2"
find-cache-dir "^2.1.0"
is-wsl "^1.1.0"
schema-utils "^1.0.0"
serialize-javascript "^3.1.0"
serialize-javascript "^4.0.0"
source-map "^0.6.1"
terser "^4.1.2"
webpack-sources "^1.4.0"
@@ -6619,14 +6667,14 @@ watchpack-chokidar2@^2.0.0:
chokidar "^2.1.8"
watchpack@^1.6.1:
version "1.7.2"
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.7.2.tgz#c02e4d4d49913c3e7e122c3325365af9d331e9aa"
integrity sha512-ymVbbQP40MFTp+cNMvpyBpBtygHnPzPkHqoIwRRj/0B8KhqQwV8LaKjtbaxF2lK4vl8zN9wCxS46IFCU5K4W0g==
version "1.7.4"
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.7.4.tgz#6e9da53b3c80bb2d6508188f5b200410866cd30b"
integrity sha512-aWAgTW4MoSJzZPAicljkO1hsi1oKj/RRq/OJQh2PKI2UKL04c2Bs+MBOB+BBABHTXJpf9mCwHN7ANCvYsvY2sg==
dependencies:
graceful-fs "^4.1.2"
neo-async "^2.5.0"
optionalDependencies:
chokidar "^3.4.0"
chokidar "^3.4.1"
watchpack-chokidar2 "^2.0.0"
wbuf@^1.1.0, wbuf@^1.7.3: