feat(#3): simplify code

This commit is contained in:
Juan Sebastián Montoya 2024-07-14 02:24:26 -05:00
parent 6c1e0019f7
commit 80292d6cce
26 changed files with 1251 additions and 1672 deletions

4
.gitignore vendored
View file

@ -1,5 +1 @@
node_modules/
dist/
.DS_Store
*.log
deploy

View file

@ -4,13 +4,14 @@ A WIP game for learning purpouses
## Libraries Used
- None at the moment, just rollup
- None at the moment, just serve
## Credits
- Created by Juan Sebastián Montoya
- Assets by:
- [ArMM1998](https://opengameart.org/content/zelda-like-tilesets-and-sprites)
- [ArMM1998](https://opengameart.org/content/zelda-like-tilesets-and-sprites)
## License
This project is licensed under the [MIT License](https://opensource.org/licenses/MIT).

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

21
index.css Normal file
View file

@ -0,0 +1,21 @@
body {
margin: 0;
height: 100%;
width: 100%;
}
#container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
width: 100%;
}
#game {
border: 1px solid black;
image-rendering: crisp-edges;
image-rendering: pixelated;
}
#resources {
display: none;
}

View file

@ -1,48 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Evolver</title>
<style>
html,
body {
margin: 0;
height: 100%;
width: 100%;
}
<html lang="en">
#game {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100%;
width: 100%;
}
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Baena</title>
<link rel="stylesheet" href="index.css">
</head>
canvas {
background-color: #fbf7f3;
border: 1px solid black;
image-rendering: pixelated;
image-rendering: crisp-edges;
}
<body>
<div id="resources">
<img id="overworld" src="resources/overworld.png">
</div>
<div id="container">
<button id="debug">Debug</button>
<button id="level1">Level 1</button>
<button id="level2">Level 2</button>
<canvas id="game"></canvas>
</div>
<script type="module" src="index.js"></script>
</body>
button {
margin: 5px;
}
</style>
</head>
<body>
<div id="game">
<div id="controls">
<button id="debug">Debug</button>
</div>
<canvas></canvas>
</div>
<script
type="module"
src="src/index.js"
></script>
</body>
</html>

71
index.js Normal file
View file

@ -0,0 +1,71 @@
import { CanvasResizer } from "./modules/canvas-resizer.js";
import { getLevel } from "./modules/utils.js";
const TILE_SIZE = 16;
const canvasResizer = new CanvasResizer({
canvas: document.getElementById("game"),
width: 320,
height: 240,
percentage: 0.9
});
const cols = canvasResizer.width / TILE_SIZE;
const rows = canvasResizer.height / TILE_SIZE;
const ctx = canvasResizer.canvas.getContext("2d");
let debug = false;
async function drawLevel({ levelName, imageName }) {
const levelImage = document.getElementById(imageName);
const level = await getLevel(levelName);
const layer = level.layers[0];
const data = layer.data;
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
if (debug) {
ctx.strokeRect(col * TILE_SIZE, row * TILE_SIZE, TILE_SIZE, TILE_SIZE)
}
const tile = data[row * cols + col]
ctx.drawImage(
levelImage,
((tile - 1) * TILE_SIZE) % levelImage.width,
Math.floor((tile - 1) * TILE_SIZE / levelImage.width) * TILE_SIZE,
TILE_SIZE,
TILE_SIZE,
col * TILE_SIZE,
row * TILE_SIZE,
TILE_SIZE,
TILE_SIZE
)
}
}
}
async function run() {
await canvasResizer.load()
let selectedLevel = { levelName: "overworld", imageName: "overworld" };
const debugButton = document.getElementById("debug");
debugButton.addEventListener("click", async () => {
debug = !debug;
await drawLevel(selectedLevel);
});
const level1Button = document.getElementById("level1");
level1Button.addEventListener("click", async () => {
selectedLevel = { levelName: "overworld", imageName: "overworld" }
await drawLevel(selectedLevel);
});
const level2Button = document.getElementById("level2");
level2Button.addEventListener("click", async () => {
selectedLevel = { levelName: "ocean", imageName: "overworld" }
await drawLevel(selectedLevel);
});
await drawLevel(selectedLevel);
}
run();

41
modules/canvas-resizer.js Normal file
View file

@ -0,0 +1,41 @@
export class CanvasResizer {
/**
* Creates a new instance of `CanvasResizer` class.
* @param {Object} config - The configuration options for the class.
* @param {HTMLCanvasElement} config.canvas - The canvas element to resize.
* @param {number} config.width - The native width.
* @param {number} config.height - The native height.
* @param {number} config.percentage - The percentage of the screen size to use for the canvas.
*/
constructor({ canvas, width, height, percentage }) {
this.canvas = canvas;
this.width = width;
this.height = height;
this.percentage = percentage;
this.canvas.width = this.width;
this.canvas.height = this.height;
}
load() {
return new Promise((resolve) => {
["load", "resize"].map(item => window.addEventListener(item, () => {
this._resize();
if (item === "load") {
resolve();
}
}));
})
}
_resize() {
let canvasWidth = Math.floor(window.innerWidth * this.percentage);
let canvasHeight = Math.floor(canvasWidth / (this.width / this.height));
if (canvasHeight >= window.innerHeight * this.percentage) {
canvasHeight = Math.floor(window.innerHeight * this.percentage);
canvasWidth = Math.floor(canvasHeight / (this.height / this.width))
}
this.canvas.style.width = canvasWidth + 'px';
this.canvas.style.height = canvasHeight + 'px';
}
}

4
modules/utils.js Normal file
View file

@ -0,0 +1,4 @@
export async function getLevel(name) {
const level = await fetch("/resources/" + name + ".json")
return await level.json()
}

View file

@ -3,25 +3,13 @@
"version": "1.0.0",
"main": "src/index.js",
"scripts": {
"clean": "del-cli dist",
"build": "yarn clean && rollup -c",
"serve": "yarn clean && rollup -c --watch"
"serve": "serve ."
},
"repository": "git@git.jusemon.com:jusemon/evolver.git",
"author": "Jusemon <juansmm@outlook.com>",
"license": "MIT",
"dependencies": {},
"devDependencies": {
"@rollup/plugin-commonjs": "^26.0.1",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-terser": "^0.4.4",
"@web/rollup-plugin-html": "^2.3.0",
"chalk": "^5.2.0",
"del-cli": "^5.1.0",
"rollup": "^4.18.0",
"rollup-plugin-copy2": "^0.4.0",
"rollup-plugin-serve": "^1.1.1",
"rollup-plugin-zip": "^1.0.3"
"serve": "^14.2.3"
}
}

345
resources/ocean.json Normal file
View file

@ -0,0 +1,345 @@
{
"compressionlevel": -1,
"height": 15,
"infinite": false,
"layers": [
{
"data": [
259,
259,
259,
259,
259,
259,
259,
259,
259,
259,
259,
259,
259,
259,
259,
259,
259,
259,
259,
259,
299,
299,
299,
299,
299,
299,
299,
299,
299,
299,
299,
299,
299,
299,
299,
299,
299,
299,
299,
299,
339,
339,
339,
339,
339,
339,
339,
339,
339,
339,
339,
339,
339,
339,
339,
339,
339,
339,
339,
339,
379,
379,
379,
379,
379,
379,
379,
379,
379,
379,
379,
379,
379,
379,
379,
379,
379,
379,
379,
379,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
125,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
125,
284,
284,
284,
284,
284,
125,
284,
284,
284,
284,
284,
284,
284,
125,
284,
284,
284,
284,
284,
284,
284,
284,
284,
124,
284,
284,
284,
165,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
166,
284,
284,
284,
284,
125,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
125,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
125,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
125,
284,
284,
284,
284,
284,
284,
284,
125,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
125,
284,
284,
284,
284,
284,
284,
125,
284,
284,
284,
284,
284,
284,
125,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284,
284
],
"height": 15,
"id": 1,
"name": "Tile Layer 1",
"opacity": 1,
"type": "tilelayer",
"visible": true,
"width": 20,
"x": 0,
"y": 0
}
],
"nextlayerid": 2,
"nextobjectid": 1,
"orientation": "orthogonal",
"renderorder": "right-down",
"tiledversion": "1.11.0",
"tileheight": 16,
"tilesets": [
{
"columns": 40,
"firstgid": 1,
"image": "overworld.png",
"imageheight": 576,
"imagewidth": 640,
"margin": 0,
"name": "overworld",
"spacing": 0,
"tilecount": 1440,
"tileheight": 16,
"tilewidth": 16
}
],
"tilewidth": 16,
"type": "map",
"version": "1.10",
"width": 20
}

345
resources/overworld.json Normal file
View file

@ -0,0 +1,345 @@
{
"compressionlevel": -1,
"height": 15,
"infinite": false,
"layers": [
{
"data": [
1,
366,
366,
366,
366,
366,
366,
366,
366,
366,
1,
1179,
445,
446,
446,
446,
690,
259,
260,
261,
1,
406,
406,
406,
406,
406,
406,
406,
406,
406,
1,
1179,
485,
486,
486,
486,
730,
299,
300,
301,
121,
122,
122,
122,
122,
122,
122,
122,
123,
1,
1,
1179,
525,
526,
526,
526,
770,
339,
340,
341,
161,
162,
162,
162,
162,
162,
162,
162,
163,
1,
1,
1219,
565,
566,
567,
567,
810,
379,
379,
379,
201,
202,
202,
202,
202,
202,
202,
202,
203,
243,
244,
245,
366,
366,
366,
366,
850,
284,
284,
284,
243,
244,
244,
244,
244,
244,
244,
244,
245,
283,
284,
285,
406,
366,
366,
366,
366,
324,
324,
324,
283,
284,
284,
284,
284,
284,
284,
284,
285,
323,
324,
325,
366,
366,
366,
366,
366,
366,
366,
366,
283,
363,
364,
363,
364,
363,
364,
284,
285,
366,
1175,
1176,
1177,
366,
1175,
1176,
1177,
366,
366,
366,
283,
403,
404,
403,
404,
403,
404,
284,
285,
406,
1215,
1216,
1217,
366,
1215,
1216,
1217,
366,
366,
366,
283,
363,
364,
284,
284,
363,
364,
284,
285,
366,
1255,
1256,
1257,
366,
1255,
1256,
1257,
366,
406,
406,
283,
403,
404,
284,
284,
403,
404,
284,
285,
366,
366,
366,
366,
366,
366,
366,
366,
366,
366,
366,
283,
284,
284,
363,
364,
284,
284,
284,
285,
366,
1175,
1176,
1177,
406,
1175,
1176,
1177,
406,
406,
406,
283,
284,
284,
403,
404,
284,
284,
284,
285,
406,
1215,
1216,
1217,
366,
1215,
1216,
1217,
366,
366,
366,
283,
284,
284,
284,
284,
284,
284,
284,
285,
366,
1255,
1256,
1257,
366,
1255,
1256,
1257,
366,
366,
366,
323,
324,
324,
324,
324,
324,
324,
324,
325,
406,
406,
406,
406,
406,
406,
406,
406,
406,
406,
406
],
"height": 15,
"id": 1,
"name": "Tile Layer 1",
"opacity": 1,
"type": "tilelayer",
"visible": true,
"width": 20,
"x": 0,
"y": 0
}
],
"nextlayerid": 2,
"nextobjectid": 1,
"orientation": "orthogonal",
"renderorder": "right-down",
"tiledversion": "1.11.0",
"tileheight": 16,
"tilesets": [
{
"columns": 40,
"firstgid": 1,
"image": "overworld.png",
"imageheight": 576,
"imagewidth": 640,
"margin": 0,
"name": "overworld",
"spacing": 0,
"tilecount": 1440,
"tileheight": 16,
"tilewidth": 16
}
],
"tilewidth": 16,
"type": "map",
"version": "1.10",
"width": 20
}

View file

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 98 KiB

28
resources/overworld.tmx Normal file
View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="20" height="15" tilewidth="16" tileheight="16" infinite="0" nextlayerid="2" nextobjectid="1">
<editorsettings>
<export target="ocean.tmj" format="json"/>
</editorsettings>
<tileset firstgid="1" name="overworld" tilewidth="16" tileheight="16" tilecount="1440" columns="40">
<image source="overworld.png" width="640" height="576"/>
</tileset>
<layer id="1" name="Tile Layer 1" width="20" height="15">
<data encoding="csv">
259,259,259,259,259,259,259,259,259,259,259,259,259,259,259,259,259,259,259,259,
299,299,299,299,299,299,299,299,299,299,299,299,299,299,299,299,299,299,299,299,
339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,
379,379,379,379,379,379,379,379,379,379,379,379,379,379,379,379,379,379,379,379,
284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,
284,284,284,284,284,284,284,284,284,284,125,284,284,284,284,284,284,284,284,284,
284,125,284,284,284,284,284,125,284,284,284,284,284,284,284,125,284,284,284,284,
284,284,284,284,284,124,284,284,284,165,284,284,284,284,284,284,284,284,284,284,
284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,166,284,284,
284,284,125,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,
284,284,284,284,284,284,284,284,284,284,125,284,284,284,284,284,284,284,284,284,
284,284,284,125,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,
284,284,284,284,284,284,125,284,284,284,284,284,284,284,125,284,284,284,284,284,
284,284,284,284,284,284,284,284,284,284,284,125,284,284,284,284,284,284,125,284,
284,284,284,284,284,125,284,284,284,284,284,284,284,284,284,284,284,284,284,284
</data>
</layer>
</map>

View file

@ -1,62 +0,0 @@
import path from "path";
import fs from "fs";
import chalk from "chalk";
export default function bundleSize({ file, maxSize = 13 }) {
return {
name: "rollup-plugin-bundle-size",
writeBundle: {
secuential: true,
order: "post",
async handler(options, bundle) {
let uncompressedSize = 0;
console.log(
chalk.green("Filename".padEnd(30, " ") + "\t Size (bytes).")
);
for (const file in bundle) {
const { modules } = bundle[file];
if (bundle[file].type === 'chunk') {
for (const moduleName in modules) {
const module = modules[moduleName];
const name = path.basename(moduleName);
uncompressedSize += module.renderedLength;
console.log(
`${chalk.cyan(name.padEnd(30, " "))}\t ${chalk.cyan(
module.renderedLength
)}`
);
}
} else if (bundle[file].type === 'asset') {
const { size } = fs.statSync(file);
uncompressedSize += size;
console.log(
`${chalk.cyan(file.padEnd(30, " "))}\t ${chalk.cyan(
size
)}`
);
}
}
console.log(
chalk.green(
"Total before compression " +
chalk.bold(chalk.green(uncompressedSize))
)
);
const asset = path.join(options.dir, file);
const { size } = fs.statSync(asset);
const percent = parseInt((size / (maxSize * 1024)) * 100, 10);
const color =
percent < 50 ? chalk.green : percent < 80 ? chalk.yellow : chalk.red;
console.log(
`Created bundle ${chalk.cyan(asset)}: ${chalk.bold(
chalk.cyan(size)
)} bytes, ${color(percent + "%")} of total game size used.`
);
},
},
};
};

View file

@ -1,41 +0,0 @@
import json from "@rollup/plugin-json";
import terser from "@rollup/plugin-terser";
import { rollupPluginHTML as html } from "@web/rollup-plugin-html";
import zip from "rollup-plugin-zip";
import serve from "rollup-plugin-serve";
import { nodeResolve } from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import copy from "rollup-plugin-copy2";
import bundleSize from "./rollup-plugins/bundle-size.mjs";
const zipPlug = zip({ file: "game.zip" });
zipPlug.writeBundle.sequential = true;
/**
* @type {import('rollup').RollupOptions}
*/
export default {
input: "index.html",
output: [
{
inlineDynamicImports: true,
dir: "dist",
format: "iife",
},
{
inlineDynamicImports: true,
dir: "dist/min",
format: "iife",
name: "version",
plugins: [terser(), zipPlug, bundleSize({ file: "game.zip", maxSize: 13 })],
},
],
plugins: [
html({ minify: true }),
json(),
nodeResolve(),
commonjs(),
copy({ assets: ["assets/*"] }),
serve({ contentBase: "dist", port: 9000, verbose: true }),
],
};

View file

@ -1,113 +0,0 @@
/**
* Represents a canvas window that resizes to fit the screen while maintaining a native aspect ratio.
*/
export default class CanvasWindow {
/**
* Creates a new instance of the `CanvasWindow` class.
* @param {Object} config - The configuration options for the canvas window.
* @param {number} config.nativeWidth - The width of the native game size.
* @param {number} config.nativeHeight - The height of the native game size.
* @param {number} config.maxMultiplier - The maximum allowed size multiplier for the canvas window.
* @param {number} config.windowPercentage - The percentage of the screen size to use for the canvas window.
* @param {HTMLCanvasElement} config.canvas - The canvas element to resize.
*/
constructor(config) {
/**
* The width of the native game size.
*
* @member {number}
*/
this.nativeWidth = config.nativeWidth ?? 320;
/**
* The height of the native game size.
*
* @member {number}
*/
this.nativeHeight = config.nativeHeight ?? 240;
/**
* The max multiplier.
*
* @member {number}
*/
this.maxMultiplier = config.maxMultiplier ?? 1;
/**
* The percentage of the window size to use for the canvas size.
*
* @member {number}
*/
this.windowPercentage = config.windowPercentage ?? 1;
/**
* The canvas element to resize.
*
* @member {HTMLCanvasElement}
*/
this.canvas = config.canvas;
/**
* The maximum width of the canvas.
*
* @member {number}
*/
this.maxWidth = this.nativeWidth * this.maxMultiplier;
/**
* The maximum width of the canvas.
*
* @member {number}
*/
this.maxHeight = this.nativeHeight * this.maxMultiplier;
/**
* The maximum width of the canvas.
*
* @member {number}
*/
this.canvasWidth = this.nativeWidth;
/**
* The maximum width of the canvas.
*
* @member {number}
*/
this.canvasHeight = this.nativeHeight;
window.addEventListener("resize", () => this.resize());
}
async load() {
return new Promise((resolve) => {
window.addEventListener("load", () => {
this.canvas.width = this.canvasWidth;
this.canvas.height = this.canvasHeight;
this.resize();
resolve();
});
});
}
/**
* Resizes the canvas window to fit the screen while maintaining the native aspect ratio.
*/
resize() {
this.canvasWidth = window.innerWidth;
this.canvasHeight = window.innerHeight;
const nativeRatio = this.nativeWidth / this.nativeHeight;
const browserWindowRatio = this.canvasWidth / this.canvasHeight;
if (browserWindowRatio > nativeRatio) {
this.canvasHeight = Math.floor(this.canvasHeight * this.windowPercentage);
if (this.canvasHeight > this.maxHeight)
this.canvasHeight = this.maxHeight;
this.canvasWidth = Math.floor(this.canvasHeight * nativeRatio);
} else {
this.canvasWidth = Math.floor(this.canvasWidth * this.windowPercentage);
if (this.canvasWidth > this.maxWidth) this.canvasWidth = this.maxWidth;
this.canvasHeight = Math.floor(this.canvasWidth / nativeRatio);
}
this.canvas.style.width = `${this.canvasWidth}px`;
this.canvas.style.height = `${this.canvasHeight}px`;
}
}

View file

@ -1,53 +0,0 @@
import CanvasWindow from "./canvas-windows";
import LevelLoader from "./level-loader";
import overworldLevel from "./levels/overworld.json";
const canvasWindow = new CanvasWindow({
canvas: document.querySelector("canvas"),
maxMultiplier: 5,
windowPercentage: 0.9,
});
let debug = true;
const GAME_TILE = 16;
const ROWS = canvasWindow.nativeHeight / GAME_TILE;
const COLUMNS = canvasWindow.nativeWidth / GAME_TILE;
function drawLevel(ctx, level) {
const levelCols = level.image.width / GAME_TILE;
for (let row = 0; row < ROWS; row++) {
for (let col = 0; col < COLUMNS; col++) {
const tile = level.layer[row * COLUMNS + col];
if (tile !== 0) {
ctx.drawImage(
level.image,
((tile - 1) * GAME_TILE) % level.image.width,
Math.floor((tile - 1) / levelCols) * GAME_TILE,
GAME_TILE,
GAME_TILE,
col * GAME_TILE,
row * GAME_TILE,
GAME_TILE,
GAME_TILE
);
}
debug &&
ctx.strokeRect(col * GAME_TILE, row * GAME_TILE, GAME_TILE, GAME_TILE);
}
}
}
(async () => {
await canvasWindow.load();
const { canvas } = canvasWindow;
const ctx = canvas.getContext("2d");
const [overworld] = await Promise.all([overworldLevel].map(LevelLoader.load));
drawLevel(ctx, overworld);
document.getElementById("debug").addEventListener("click", () => {
debug = !debug;
drawLevel(ctx, overworld);
});
})();

View file

@ -1,22 +0,0 @@
class Level {
constructor({ image, layer }) {
this.image = image;
this.layer = layer;
}
}
export default class LevelLoader {
/**
* Loads a level on memory from the specified source and layer.
*
* @return {Promise<Level>} A Promise that resolves with the loaded level.
*/
static load({ source, layer }) {
return new Promise((resolve, reject) => {
const image = new Image();
image.src = source;
image.onload = () => resolve(new Level({ image, layer }));
image.onerror = reject;
});
}
}

View file

@ -1,19 +0,0 @@
{
"source": "assets/overworld.png",
"layer": [
243, 244, 244, 244, 245, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 283, 283,
284, 284, 284, 285, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 283, 283, 284,
284, 284, 285, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 283, 323, 324, 324,
324, 325, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 283, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 283, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 283, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 283, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 283,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 283, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 283, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 283, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ,
1, 1, 1, 1, 283, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
283, 245, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 283, 403,
244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244,
244, 244, 244, 404
]
}

1667
yarn.lock

File diff suppressed because it is too large Load diff