CMU Coding Bootcamp

Compare changes

Choose any two refs to compare.

+1
.gitignore
··· 1 + node_modules
+11
.zed/settings.json
··· 1 + // Folder-specific settings 2 + // 3 + // For a full list of overridable settings, and general information on folder-specific settings, 4 + // see the documentation: https://zed.dev/docs/configuring-zed#settings-files 5 + { 6 + "languages": { 7 + "TypeScript": { 8 + "tab_size": 4 9 + } 10 + } 11 + }
+1
html/README.md
··· 1 + # A Basic HTML Page
+42
html/css/dino.css
··· 1 + body { 2 + margin: 0; 3 + padding: 0; 4 + display: flex; 5 + justify-content: center; 6 + align-items: center; 7 + min-height: 100vh; 8 + background-color: #f7f7f7; 9 + font-family: Arial, sans-serif; 10 + } 11 + 12 + .game-container { 13 + position: relative; 14 + } 15 + 16 + #gameCanvas { 17 + border: 2px solid #535353; 18 + background-color: #fff; 19 + display: block; 20 + } 21 + 22 + #score { 23 + position: absolute; 24 + top: 10px; 25 + right: 10px; 26 + font-size: 20px; 27 + font-weight: bold; 28 + color: #535353; 29 + } 30 + 31 + #gameOver { 32 + position: absolute; 33 + width: 100%; 34 + text-align: center; 35 + top: 50%; 36 + left: 50%; 37 + transform: translate(-50%, -50%); 38 + font-size: 24px; 39 + font-weight: bold; 40 + color: #535353; 41 + display: none; 42 + }
+85
html/css/form.css
··· 1 + .container { 2 + display: flex; 3 + flex-direction: column; 4 + align-items: center; 5 + justify-content: center; 6 + } 7 + 8 + form { 9 + display: flex; 10 + flex-direction: column; 11 + align-items: center; 12 + justify-content: center; 13 + gap: 0.5rem; 14 + width: 80%; 15 + } 16 + 17 + form > * { 18 + width: 100%; 19 + } 20 + 21 + form :nth-child(even) { 22 + margin-bottom: 1rem; 23 + } 24 + 25 + form > button { 26 + width: 100%; 27 + padding: 0.25rem; 28 + margin: 0.5rem; 29 + } 30 + 31 + @media (min-width: 769px) { 32 + form { 33 + gap: 1rem; 34 + width: 100%; 35 + max-width: 48rem; 36 + display: grid; 37 + column-gap: 1rem; 38 + grid-template-columns: repeat(2, minmax(0, 1fr)); 39 + } 40 + 41 + form > button { 42 + width: 100%; 43 + grid-column: span 2; 44 + padding: 0.25rem; 45 + margin: 0.5rem; 46 + } 47 + } 48 + 49 + nav { 50 + display: flex; 51 + padding: 0.5rem 0rem; 52 + background-color: #8aacdf; 53 + position: sticky; 54 + top: 0; 55 + left: 0; 56 + right: 0; 57 + margin-left: -0.5rem; 58 + margin-top: -0.5rem; 59 + justify-content: space-around; 60 + align-items: center; 61 + width: 100vw; 62 + margin-bottom: 4rem; 63 + } 64 + 65 + .navitem { 66 + padding: 0.5rem 4rem; 67 + border: 1px solid #000; 68 + border-radius: 0.5rem; 69 + } 70 + 71 + #footer { 72 + width: 100vw; 73 + height: 6rem; 74 + position: absolute; 75 + bottom: 0; 76 + left: 0; 77 + justify-content: space-around; 78 + align-items: center; 79 + background-color: #000; 80 + color: #fff; 81 + text-align: center; 82 + display: flex; 83 + vertical-align: center; 84 + font-size: 2rem; 85 + }
+70
html/css/styles.css
··· 1 + h1 { 2 + font-size: 48px; 3 + margin: 0; 4 + color: #8aadf4; 5 + } 6 + 7 + h2 { 8 + font-size: 36px; 9 + margin: 0; 10 + } 11 + 12 + .heading { 13 + color: #a5adcb; 14 + } 15 + 16 + * { 17 + font-family: 18 + system-ui, 19 + -apple-system, 20 + BlinkMacSystemFont, 21 + "Segoe UI", 22 + Roboto, 23 + Oxygen, 24 + Ubuntu, 25 + Cantarell, 26 + "Open Sans", 27 + "Helvetica Neue", 28 + sans-serif; 29 + color: #cad3f5; 30 + } 31 + 32 + body { 33 + background-color: #24273a; 34 + } 35 + 36 + main { 37 + margin: none; 38 + display: flex; 39 + flex-direction: column; 40 + gap: 5rem; 41 + align-items: center; 42 + } 43 + 44 + .hr { 45 + width: 80rem; 46 + border-top: 2px solid #6e738d; 47 + } 48 + 49 + .container { 50 + display: flex; 51 + width: 160rem; 52 + flex-direction: column; 53 + gap: 0.1rem; 54 + align-items: center; 55 + } 56 + 57 + .card { 58 + width: 15rem; 59 + height: 20rem; 60 + background-color: #363950; 61 + border-radius: 0.5rem; 62 + box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); 63 + transition: transform 0.15s ease-in-out; 64 + cursor: pointer; 65 + } 66 + 67 + .card:hover { 68 + transform: scale(1.05); 69 + transition: transform 0.15s ease-in-out; 70 + }
+19
html/dino.html
··· 1 + <!doctype html> 2 + <html lang="en"> 3 + <head> 4 + <meta charset="UTF-8" /> 5 + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 6 + <title>Dino Game</title> 7 + <link rel="stylesheet" href="css/dino.css" /> 8 + </head> 9 + <body> 10 + <div class="game-container"> 11 + <canvas id="gameCanvas" width="800" height="600"></canvas> 12 + <div id="score">Score: 0</div> 13 + <div id="gameOver"> 14 + Game Over! Press <kbd>Space</kbd> to Restart 15 + </div> 16 + </div> 17 + <script src="js/dino.js"></script> 18 + </body> 19 + </html>
+28
html/form.html
··· 1 + <!doctype html> 2 + <html lang="en"> 3 + <head> 4 + <meta charset="UTF-8" /> 5 + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 6 + <title>Form</title> 7 + <link rel="stylesheet" href="css/form.css" /> 8 + <script src="js/form.js"></script> 9 + </head> 10 + <body> 11 + <nav> 12 + <a class="navitem" href="/">Home</a> 13 + <a class="navitem" href="/dino.html">Dino</a> 14 + </nav> 15 + <div class="container"> 16 + <form> 17 + <label for="name">Name:</label> 18 + <input type="text" id="name" name="name" required /> 19 + <label for="email">Email:</label> 20 + <input type="email" id="email" name="email" required /> 21 + <label for="message">Message:</label> 22 + <textarea id="message" name="message" required></textarea> 23 + <button type="submit">Submit</button> 24 + </form> 25 + </div> 26 + <div id="footer">Totally good footer text</div> 27 + </body> 28 + </html>
+40
html/index.html
··· 1 + <html> 2 + <head> 3 + <title>HTML Page</title> 4 + <link rel="stylesheet" href="css/styles.css" /> 5 + <script src="js/script.js"></script> 6 + </head> 7 + <body style="margin: 0; padding: 8px"> 8 + <main> 9 + <h1>Samuel Shuert</h1> 10 + <div class="container"> 11 + <h2 class="heading">Projects</h2> 12 + <div class="hr"></div> 13 + <div 14 + style=" 15 + display: flex; 16 + flex-direction: row; 17 + justify-content: center; 18 + padding-top: 2rem; 19 + gap: 1rem; 20 + " 21 + > 22 + <div class="card" onclick="openProject('dino')">Dino</div> 23 + <div class="card" onclick="openProject('temp')"></div> 24 + <div class="card" onclick="openProject('temp')"></div> 25 + </div> 26 + </div> 27 + <div class="container"> 28 + <div class="hr" style="width: 20rem; margin-bottom: 2rem"></div> 29 + <h2 class="heading">Education</h2> 30 + <div class="hr"></div> 31 + </div> 32 + <div class="container"> 33 + <div class="hr" style="width: 20rem; margin-bottom: 2rem"></div> 34 + <h2 class="heading">Skills</h2> 35 + <div class="hr"></div> 36 + </div> 37 + <div class="hr" style="width: 20rem"></div> 38 + </main> 39 + </body> 40 + </html>
+246
html/js/dino.js
··· 1 + const canvas = document.getElementById("gameCanvas"); 2 + const ctx = canvas.getContext("2d"); 3 + const scoreElement = document.getElementById("score"); 4 + const gameOverElement = document.getElementById("gameOver"); 5 + 6 + let score = 0; 7 + let gameSpeed = 3; 8 + let isGameOver = false; 9 + let frameCount = 0; 10 + let nextObstacleFrame = 10; 11 + 12 + const dino = { 13 + x: 50, 14 + y: 150, 15 + width: 40, 16 + height: 50, 17 + dy: 0, 18 + gravity: 0.3, 19 + jumpPower: -8, 20 + isJumping: false, 21 + isDucking: false, 22 + 23 + draw() { 24 + ctx.fillStyle = "#8aacdf"; 25 + ctx.fillRect(this.x, this.y, this.width, this.height); 26 + }, 27 + 28 + update() { 29 + if (this.isDucking) { 30 + this.y = 170; 31 + this.height = 30; 32 + } else { 33 + this.height = 50; 34 + } 35 + 36 + if (this.isJumping) { 37 + this.dy += this.gravity; 38 + this.y += this.dy; 39 + 40 + if (this.y >= 150) { 41 + this.y = 150; 42 + this.isJumping = false; 43 + this.dy = 0; 44 + } 45 + } 46 + }, 47 + 48 + duck() { 49 + if (!this.isJumping && !isGameOver) { 50 + this.isDucking = true; 51 + } else if (this.isJumping && !isGameOver) { 52 + this.dy += this.gravity * 10; 53 + this.y += this.dy; 54 + } 55 + }, 56 + 57 + jump() { 58 + if (!this.isJumping && !isGameOver) { 59 + this.isJumping = true; 60 + this.dy = this.jumpPower; 61 + } 62 + }, 63 + }; 64 + 65 + const obstacles = []; 66 + 67 + class Obstacle { 68 + constructor() { 69 + this.x = canvas.width; 70 + const type = Math.random(); 71 + if (type < 0.5) { 72 + this.width = 20; 73 + this.height = 40; 74 + this.y = 160; 75 + } else if (type < 0.8) { 76 + this.width = 20; 77 + this.height = 25; 78 + this.y = 175; 79 + } else { 80 + this.width = 40; 81 + this.height = 32; 82 + this.y = 168; 83 + } 84 + } 85 + 86 + draw() { 87 + ctx.fillStyle = "#40a02b"; 88 + ctx.fillRect(this.x, this.y, this.width, this.height); 89 + } 90 + 91 + update() { 92 + this.x -= gameSpeed; 93 + } 94 + } 95 + 96 + class BirdObstacle { 97 + constructor() { 98 + this.x = canvas.width; 99 + this.width = 30; 100 + this.height = 20; 101 + const heightType = Math.floor(Math.random() * 3); 102 + if (heightType === 0) { 103 + this.y = 170; 104 + } else if (heightType === 1) { 105 + this.y = 150; 106 + } else { 107 + this.y = 130; 108 + } 109 + } 110 + 111 + draw() { 112 + ctx.fillStyle = "#dd7878"; 113 + ctx.fillRect(this.x, this.y, this.width, this.height); 114 + } 115 + 116 + update() { 117 + this.x -= gameSpeed; 118 + } 119 + } 120 + 121 + function checkCollision(dino, obstacle) { 122 + return ( 123 + dino.x < obstacle.x + obstacle.width && 124 + dino.x + dino.width > obstacle.x && 125 + dino.y < obstacle.y + obstacle.height && 126 + dino.y + dino.height > obstacle.y 127 + ); 128 + } 129 + 130 + function spawnObstacle() { 131 + if (frameCount >= nextObstacleFrame) { 132 + const type = Math.random(); 133 + if (type < 0.9) { 134 + obstacles.push(new Obstacle()); 135 + } else { 136 + obstacles.push(new BirdObstacle()); 137 + } 138 + 139 + const baseMin = 80; 140 + const baseMax = 140; 141 + 142 + const speedFactor = 3 / gameSpeed; 143 + 144 + const minInterval = Math.floor(baseMin * speedFactor); 145 + const maxInterval = Math.floor(baseMax * speedFactor); 146 + nextObstacleFrame = 147 + frameCount + 148 + Math.floor(Math.random() * (maxInterval - minInterval) + minInterval); 149 + } 150 + } 151 + 152 + function updateScore() { 153 + if (!isGameOver) { 154 + score++; 155 + scoreElement.textContent = `Score: ${Math.floor(score / 10)}`; 156 + 157 + // Increase difficulty 158 + if (score % 500 === 0) { 159 + gameSpeed += 0.5; 160 + } 161 + } 162 + } 163 + 164 + function gameLoop() { 165 + if (isGameOver) return; 166 + 167 + ctx.clearRect(0, 0, canvas.width, canvas.height); 168 + 169 + ctx.strokeStyle = "#535353"; 170 + ctx.beginPath(); 171 + ctx.moveTo(0, 200); 172 + ctx.lineTo(canvas.width, 200); 173 + ctx.stroke(); 174 + 175 + dino.update(); 176 + dino.draw(); 177 + 178 + spawnObstacle(); 179 + 180 + for (let i = obstacles.length - 1; i >= 0; i--) { 181 + obstacles[i].update(); 182 + obstacles[i].draw(); 183 + 184 + if (checkCollision(dino, obstacles[i])) { 185 + isGameOver = true; 186 + gameOverElement.style.display = "block"; 187 + } 188 + 189 + if (obstacles[i].x + obstacles[i].width < 0) { 190 + obstacles.splice(i, 1); 191 + } 192 + } 193 + 194 + updateScore(); 195 + frameCount++; 196 + 197 + requestAnimationFrame(gameLoop); 198 + } 199 + 200 + function resetGame() { 201 + score = 0; 202 + gameSpeed = 3; 203 + isGameOver = false; 204 + frameCount = 0; 205 + obstacles.length = 0; 206 + dino.y = 150; 207 + dino.dy = 0; 208 + dino.isJumping = false; 209 + gameOverElement.style.display = "none"; 210 + nextObstacleFrame = 10; 211 + gameLoop(); 212 + } 213 + 214 + document.addEventListener("keydown", (e) => { 215 + e.preventDefault(); 216 + switch (e.code) { 217 + case "ArrowUp": 218 + case "Space": { 219 + if (isGameOver) { 220 + resetGame(); 221 + } else { 222 + dino.jump(); 223 + } 224 + break; 225 + } 226 + case "ArrowDown": { 227 + dino.duck(); 228 + break; 229 + } 230 + default: 231 + } 232 + }); 233 + 234 + document.addEventListener("keyup", (e) => { 235 + switch (e.code) { 236 + case "ArrowDown": { 237 + e.preventDefault(); 238 + dino.isDucking = false; 239 + if (!dino.isJumping) { 240 + dino.y = 150; 241 + } 242 + } 243 + } 244 + }); 245 + 246 + gameLoop();
+11
html/js/script.js
··· 1 + const projects = { 2 + dino: "dino.html", 3 + }; 4 + 5 + const openProject = (project) => { 6 + if (Object.keys(projects).includes(project)) { 7 + window.location.href = projects[project]; 8 + } else { 9 + alert("Project not found"); 10 + } 11 + };
+70 -33
nilla.nix
··· 8 8 nilla = import pins.nilla; 9 9 in 10 10 nilla.create ( 11 - { config, lib }: 11 + { config }: 12 12 { 13 13 config = { 14 14 inputs = { 15 15 nixpkgs = { 16 16 src = pins.nixpkgs; 17 - }; 17 + }; 18 18 }; 19 19 packages.cmu-graphics = { 20 20 systems = [ "x86_64-linux" ]; 21 21 package = 22 - { 23 - pkgs, 24 - python313, 25 - fetchPypi 26 - }: 22 + { 23 + pkgs, 24 + python313, 25 + fetchPypi, 26 + }: 27 27 let 28 28 pname = "cmu_graphics"; 29 29 version = "1.1.43"; ··· 47 47 python313.pkgs.pycairo 48 48 python313.pkgs.pygame 49 49 ]; 50 - 50 + 51 51 build-system = [ 52 52 python313.pkgs.setuptools 53 53 python313.pkgs.wheel 54 54 pkgs.pre-commit 55 55 ]; 56 - 56 + 57 57 }; 58 58 }; 59 - shells.default = config.shells.python; 59 + shells.default = config.shells.html; 60 60 shells.python = { 61 61 # Declare what systems the shell can be used on. 62 62 systems = [ "x86_64-linux" ]; 63 - 63 + 64 64 # Define our shell environment. 65 65 shell = 66 66 { ··· 68 68 mkShell, 69 69 ... 70 70 }: 71 + let 72 + python3 = pkgs.python313.override { 73 + packageOverrides = pyfinal: pyprev: { 74 + cmu_graphics = config.packages.cmu-graphics.result.x86_64-linux; 75 + }; 76 + }; 77 + in 71 78 mkShell { 72 79 shellHook = '' 73 - export ZED_PREDICT_EDITS_URL=http://localhost:9000/predict_edits 80 + [ "$(hostname)" = "shorthair" ] && export ZED_PREDICT_EDITS_URL=http://localhost:9000/predict_edits 74 81 ''; 75 82 packages = [ 76 - pkgs.python314 83 + (python3.withPackages (ppkgs: [ 84 + ppkgs.pandas 85 + ppkgs.pandas-stubs 86 + ppkgs.matplotlib 87 + ppkgs.seaborn 88 + ppkgs.numpy 89 + ppkgs.requests 90 + ppkgs.geopy 91 + ppkgs.cmu_graphics 92 + ppkgs.pycairo 93 + ppkgs.pygame 94 + ppkgs.pillow 95 + ppkgs.numpy 96 + ])) 77 97 pkgs.black 78 98 ]; 79 99 }; 80 100 }; 81 - shells.cmu-graphics = { 101 + shells.ts = { 102 + systems = [ "x86_64-linux" ]; 103 + 104 + shell = 105 + { 106 + pkgs, 107 + mkShell, 108 + }: 109 + mkShell { 110 + packages = [ 111 + pkgs.bun 112 + pkgs.eslint_d 113 + pkgs.eslint 114 + pkgs.typescript 115 + pkgs.typescript-language-server 116 + pkgs.package-version-server 117 + pkgs.nixd 118 + pkgs.nil 119 + ]; 120 + }; 121 + }; 122 + shells.html = { 82 123 systems = [ "x86_64-linux" ]; 124 + 83 125 shell = 84 126 { 85 127 pkgs, 86 128 mkShell, 87 - ... 88 129 }: 89 - let 90 - python3 = pkgs.python313.override { 91 - packageOverrides = pyfinal: pyprev: { 92 - cmu_graphics = config.packages.cmu-graphics.result.x86_64-linux; 93 - }; 94 - }; 95 - in 96 - mkShell { 97 - packages = [ 98 - (python3.withPackages (ppkgs: [ 99 - ppkgs.cmu_graphics 100 - ppkgs.pycairo 101 - ppkgs.pygame 102 - ppkgs.pillow 103 - ppkgs.numpy 104 - ])) 105 - ]; 106 - }; 130 + mkShell { 131 + shellHook = '' 132 + serve() { 133 + live-server /home/coded/Programming/CMU/html --port 5000 134 + } 135 + export -f serve 136 + ''; 137 + packages = [ 138 + pkgs.emmet-language-server 139 + pkgs.nixd 140 + pkgs.nil 141 + pkgs.nodePackages.live-server 142 + ]; 143 + }; 107 144 }; 108 145 }; 109 146 }
+3 -3
python/oct10/Tables/main.py
··· 148 148 # so it will raise a custom exception. 149 149 error = None 150 150 try: 151 - col = table.getCol(3) 151 + _col = table.getCol(3) 152 152 except Exception as e: 153 153 error = str(e) 154 154 assert error == "Col 3 is out of range" ··· 186 186 # so it will raise a custom exception. 187 187 error = None 188 188 try: 189 - row = table.getRow(10) 189 + _row = table.getRow(10) 190 190 except Exception as e: 191 191 error = str(e) 192 192 assert error == "Row 10 is out of range" ··· 199 199 # there is no such header, so it will raise a custom exception. 200 200 error = None 201 201 try: 202 - i = table.getHeaderIndex("Missing") 202 + _i = table.getHeaderIndex("Missing") 203 203 except Exception as e: 204 204 error = str(e) 205 205 # assert(error == 'No such header: Missing')
+6 -4
python/oct14/level1/maxDigit.py
··· 1 1 def maxDigit(n: int) -> int: 2 2 n = abs(n) 3 - d = n % 10 4 - r = n // 10 5 - next = maxDigit(r) if r > 0 else 0 6 - return d if d > next else next 3 + if n == 0: 4 + return 0 5 + rest = n // 10 6 + ones = n % 10 7 + next = maxDigit(rest) 8 + return max(ones, next) 7 9 8 10 def testMaxDigit(): 9 11 print('Testing maxDigit()...', end='')
python/oct15/cats/Figure_1.png

This is a binary file and will not be displayed.

+6
python/oct15/cats/README.txt
··· 1 + Source: 2 + https://www.kaggle.com/datasets/waqi786/cats-dataset 3 + 4 + License: 5 + Apache 2.0 6 + https://www.apache.org/licenses/LICENSE-2.0
+1001
python/oct15/cats/cats_dataset.csv
··· 1 + Breed,Age (Years),Weight (kg),Color,Gender 2 + Russian Blue,19,7,Tortoiseshell,Female 3 + Norwegian Forest,19,9,Tortoiseshell,Female 4 + Chartreux,3,3,Brown,Female 5 + Persian,13,6,Sable,Female 6 + Ragdoll,10,8,Tabby,Male 7 + Ocicat,9,8,Blue,Female 8 + Ragdoll,6,5,Calico,Female 9 + Abyssinian,12,3,Tabby,Male 10 + Oriental,2,7,White,Male 11 + Egyptian Mau,12,3,White,Male 12 + Chartreux,16,4,White,Male 13 + American Shorthair,13,5,Black,Male 14 + Bengal,16,6,White,Male 15 + Cornish Rex,13,6,Pointed,Male 16 + British Shorthair,19,3,Red,Female 17 + Burmese,14,5,Pointed,Male 18 + Burmese,13,3,Pointed,Male 19 + Russian Blue,10,7,Black,Male 20 + Singapura,7,3,Blue,Female 21 + Maine Coon,5,6,Tricolor,Male 22 + British Shorthair,17,6,Cream,Female 23 + Abyssinian,9,3,Tabby,Male 24 + Cornish Rex,6,9,Pointed,Male 25 + Turkish Angora,16,6,Sable,Female 26 + Burmese,6,7,Calico,Female 27 + Himalayan,6,6,Tortoiseshell,Male 28 + Sphynx,18,4,Cream,Male 29 + Manx,1,4,Blue,Male 30 + Siberian,17,2,Calico,Male 31 + Birman,17,7,Pointed,Female 32 + Oriental,1,2,Tortoiseshell,Female 33 + Balinese,11,9,White,Male 34 + Egyptian Mau,13,3,Pointed,Male 35 + Devon Rex,1,3,Orange,Male 36 + Egyptian Mau,8,3,Cream,Male 37 + Sphynx,6,3,Tortoiseshell,Female 38 + Norwegian Forest,5,9,Sable,Female 39 + Norwegian Forest,5,6,Tabby,Male 40 + Persian,6,2,Sable,Male 41 + American Shorthair,13,8,Black,Male 42 + Ragdoll,18,3,Cream,Male 43 + Burmese,13,4,Blue,Female 44 + Himalayan,7,9,Tabby,Female 45 + Egyptian Mau,8,6,White,Male 46 + Exotic Shorthair,17,2,White,Male 47 + Egyptian Mau,1,7,Gray,Female 48 + Egyptian Mau,16,6,White,Male 49 + Turkish Angora,11,5,Bicolor,Male 50 + Abyssinian,4,9,Blue,Female 51 + Persian,4,3,Bicolor,Male 52 + Maine Coon,17,4,Black,Male 53 + Oriental,17,7,Red,Female 54 + Manx,10,9,Tricolor,Female 55 + Persian,6,2,Blue,Male 56 + Scottish Fold,17,6,Tricolor,Male 57 + Balinese,18,2,Orange,Male 58 + Cornish Rex,10,5,Tabby,Male 59 + Ragdoll,13,4,Brown,Male 60 + Savannah,16,7,Gray,Male 61 + American Shorthair,7,8,Bicolor,Female 62 + Cornish Rex,15,6,Blue,Male 63 + Munchkin,2,7,Blue,Male 64 + Siamese,5,9,Brown,Female 65 + Persian,17,5,White,Male 66 + Persian,5,4,Bicolor,Male 67 + Bengal,8,3,Red,Female 68 + Chartreux,15,2,Calico,Male 69 + Sphynx,8,8,Calico,Male 70 + British Shorthair,3,5,Tricolor,Male 71 + Birman,17,7,Pointed,Female 72 + Balinese,16,7,Tricolor,Female 73 + Himalayan,16,9,Orange,Male 74 + Norwegian Forest,19,2,Brown,Female 75 + Bengal,12,2,Tricolor,Male 76 + Oriental,15,5,Tabby,Female 77 + Scottish Fold,8,5,Tricolor,Male 78 + Singapura,3,6,Calico,Male 79 + Burmese,18,4,Bicolor,Female 80 + Maine Coon,4,8,Black,Female 81 + Maine Coon,8,7,Tricolor,Female 82 + Abyssinian,14,3,Pointed,Female 83 + Oriental,17,4,Gray,Female 84 + Manx,6,7,Black,Male 85 + Ragdoll,5,8,Cream,Female 86 + British Shorthair,14,7,Red,Female 87 + Cornish Rex,6,8,Red,Female 88 + Savannah,12,3,Sable,Female 89 + Turkish Angora,9,3,Orange,Male 90 + American Shorthair,1,8,Tricolor,Male 91 + Ocicat,18,6,Sable,Female 92 + Persian,6,8,Calico,Female 93 + Turkish Angora,5,4,Brown,Male 94 + Ragdoll,2,5,Tricolor,Male 95 + Chartreux,6,2,Tabby,Male 96 + Russian Blue,17,7,Cream,Male 97 + Manx,7,6,Sable,Male 98 + Scottish Fold,9,6,Sable,Male 99 + Balinese,5,6,White,Female 100 + Savannah,11,9,Red,Female 101 + Bengal,11,5,Tortoiseshell,Female 102 + British Shorthair,4,7,Red,Male 103 + Bengal,6,8,White,Female 104 + Norwegian Forest,10,2,Cream,Female 105 + Balinese,9,3,Black,Female 106 + Ragdoll,18,7,Red,Male 107 + Russian Blue,9,5,Tortoiseshell,Male 108 + Bengal,11,4,Calico,Male 109 + Balinese,2,4,Orange,Female 110 + Birman,15,5,Cream,Male 111 + Turkish Angora,6,6,Brown,Female 112 + Norwegian Forest,17,5,Black,Female 113 + Balinese,4,7,Tortoiseshell,Female 114 + Ragdoll,8,9,Calico,Male 115 + Singapura,2,8,Blue,Male 116 + Cornish Rex,9,2,Tricolor,Female 117 + Norwegian Forest,1,7,Cream,Female 118 + Siberian,6,3,Gray,Female 119 + Chartreux,16,8,Calico,Female 120 + Chartreux,7,9,Bicolor,Male 121 + Devon Rex,16,3,Pointed,Male 122 + Himalayan,6,9,Sable,Female 123 + Sphynx,10,3,Tabby,Male 124 + Oriental,18,8,Tortoiseshell,Female 125 + Ragdoll,17,7,Black,Male 126 + Persian,17,3,Bicolor,Female 127 + Sphynx,12,6,Red,Female 128 + Persian,15,7,Pointed,Female 129 + Himalayan,6,8,Brown,Female 130 + American Shorthair,16,7,Bicolor,Male 131 + Bengal,14,4,Calico,Male 132 + Siamese,12,9,Red,Female 133 + Devon Rex,12,4,Blue,Male 134 + Exotic Shorthair,2,5,Black,Female 135 + Ragdoll,8,3,Cream,Male 136 + Siamese,17,4,Tortoiseshell,Female 137 + Scottish Fold,8,2,Brown,Male 138 + Siberian,16,8,Bicolor,Female 139 + Devon Rex,1,5,Blue,Female 140 + Abyssinian,5,9,Tortoiseshell,Female 141 + Chartreux,19,6,Calico,Female 142 + Oriental,3,4,Orange,Female 143 + Persian,9,3,Black,Male 144 + Scottish Fold,11,8,Gray,Male 145 + American Shorthair,6,8,Bicolor,Female 146 + Savannah,7,8,Orange,Female 147 + Singapura,7,6,Pointed,Male 148 + Cornish Rex,5,2,White,Female 149 + Ocicat,2,2,Calico,Female 150 + Siamese,5,2,Brown,Female 151 + Manx,6,6,Calico,Female 152 + Siamese,6,7,Tabby,Female 153 + Ragdoll,7,4,Calico,Male 154 + Ocicat,4,4,Red,Female 155 + Ragdoll,18,7,Sable,Male 156 + American Shorthair,16,7,Tabby,Female 157 + Turkish Angora,19,3,Gray,Male 158 + Ragdoll,10,7,Blue,Female 159 + Balinese,5,6,Gray,Male 160 + Himalayan,18,4,Red,Male 161 + American Shorthair,3,7,Pointed,Male 162 + Ocicat,4,5,Red,Female 163 + Turkish Angora,14,3,Brown,Male 164 + Oriental,12,4,Red,Male 165 + Singapura,14,5,Tricolor,Male 166 + Maine Coon,5,3,Calico,Male 167 + Bengal,18,2,Orange,Male 168 + Scottish Fold,7,2,Gray,Male 169 + Tonkinese,16,5,Bicolor,Female 170 + Savannah,3,2,Pointed,Male 171 + Birman,11,5,Black,Male 172 + Savannah,18,3,Brown,Female 173 + Siamese,6,4,Bicolor,Male 174 + Egyptian Mau,5,9,Sable,Female 175 + Devon Rex,5,3,Cream,Male 176 + Persian,16,5,Orange,Female 177 + Tonkinese,3,8,Brown,Male 178 + Persian,12,6,Red,Male 179 + British Shorthair,3,6,Bicolor,Female 180 + Egyptian Mau,2,9,Gray,Male 181 + Turkish Angora,15,8,Red,Male 182 + Scottish Fold,17,7,Gray,Female 183 + Egyptian Mau,12,7,White,Male 184 + Burmese,2,7,Tortoiseshell,Male 185 + Munchkin,2,5,Orange,Male 186 + Birman,14,2,Cream,Male 187 + Siberian,7,5,Gray,Male 188 + Burmese,14,9,Pointed,Female 189 + Exotic Shorthair,7,9,Brown,Female 190 + Siamese,17,7,Tricolor,Female 191 + Ragdoll,4,4,Pointed,Female 192 + Siamese,15,9,Pointed,Female 193 + Savannah,3,3,White,Female 194 + Siberian,6,5,Tricolor,Female 195 + Devon Rex,8,9,Pointed,Male 196 + Birman,16,7,Bicolor,Female 197 + Birman,15,8,Pointed,Female 198 + Egyptian Mau,4,4,Tricolor,Male 199 + Birman,8,6,Gray,Female 200 + Singapura,8,5,Orange,Female 201 + Siamese,7,2,Orange,Male 202 + Burmese,18,7,Blue,Male 203 + Balinese,12,5,Tabby,Female 204 + Ragdoll,4,7,Tabby,Female 205 + Russian Blue,14,6,Gray,Male 206 + Exotic Shorthair,5,7,Red,Male 207 + Turkish Angora,7,7,Sable,Male 208 + Persian,12,4,Orange,Male 209 + Bengal,15,5,Tricolor,Male 210 + Ragdoll,19,9,Tortoiseshell,Male 211 + Siberian,13,5,Sable,Male 212 + Savannah,4,7,Black,Male 213 + Munchkin,6,8,Bicolor,Male 214 + Tonkinese,8,2,Tortoiseshell,Female 215 + Siberian,15,5,Pointed,Female 216 + Manx,12,3,Black,Male 217 + Siberian,10,8,Black,Female 218 + Savannah,12,8,Black,Male 219 + Burmese,17,5,Orange,Male 220 + Devon Rex,8,4,Tricolor,Male 221 + Burmese,2,8,Tortoiseshell,Female 222 + Exotic Shorthair,19,3,Cream,Male 223 + Chartreux,1,2,Cream,Male 224 + Turkish Angora,10,4,Tabby,Female 225 + Manx,9,2,Pointed,Female 226 + Devon Rex,19,8,Brown,Female 227 + Munchkin,12,8,Bicolor,Female 228 + Manx,18,8,Black,Male 229 + Tonkinese,16,5,Red,Female 230 + Chartreux,4,5,White,Male 231 + Exotic Shorthair,11,5,Tricolor,Male 232 + Egyptian Mau,15,6,Tabby,Female 233 + Maine Coon,16,6,Tabby,Female 234 + Birman,2,9,Bicolor,Male 235 + Persian,13,6,Sable,Female 236 + Bengal,12,3,Black,Female 237 + Ocicat,8,6,Red,Male 238 + Ocicat,12,7,Sable,Female 239 + Manx,14,9,Blue,Female 240 + British Shorthair,3,7,Tortoiseshell,Male 241 + Chartreux,2,5,Red,Male 242 + Siberian,17,9,Bicolor,Female 243 + Abyssinian,2,5,Tabby,Female 244 + Burmese,17,2,Black,Male 245 + Burmese,2,4,Tricolor,Female 246 + Norwegian Forest,2,4,Tricolor,Male 247 + Oriental,13,3,Tabby,Female 248 + American Shorthair,7,4,Orange,Female 249 + Birman,9,9,Sable,Male 250 + Tonkinese,9,8,Calico,Male 251 + Norwegian Forest,14,3,Cream,Female 252 + Savannah,11,9,Brown,Female 253 + British Shorthair,19,2,Sable,Female 254 + Norwegian Forest,1,5,Tricolor,Female 255 + Exotic Shorthair,5,5,Tricolor,Male 256 + Manx,1,3,Tricolor,Male 257 + Maine Coon,6,6,Cream,Female 258 + Tonkinese,16,9,Orange,Female 259 + Russian Blue,16,2,White,Male 260 + Burmese,13,9,Pointed,Male 261 + Exotic Shorthair,14,9,Sable,Female 262 + Burmese,11,7,Sable,Female 263 + Ragdoll,10,5,Black,Male 264 + American Shorthair,17,5,Brown,Male 265 + Norwegian Forest,7,9,Cream,Male 266 + Ragdoll,4,8,Orange,Male 267 + Scottish Fold,17,2,Sable,Male 268 + Russian Blue,1,7,Brown,Female 269 + British Shorthair,2,7,Red,Female 270 + Ragdoll,19,3,Gray,Female 271 + Tonkinese,1,9,Cream,Female 272 + Exotic Shorthair,12,6,Bicolor,Female 273 + Sphynx,19,8,Blue,Male 274 + Cornish Rex,19,8,Orange,Male 275 + Savannah,16,3,Tabby,Male 276 + Persian,16,2,Calico,Male 277 + Savannah,8,4,Black,Female 278 + Birman,13,3,Bicolor,Female 279 + Balinese,14,4,Bicolor,Male 280 + Scottish Fold,19,8,Tricolor,Male 281 + Tonkinese,15,2,Black,Female 282 + Savannah,15,7,Brown,Female 283 + Sphynx,8,4,Blue,Male 284 + Exotic Shorthair,13,5,Tortoiseshell,Female 285 + Munchkin,12,9,Sable,Female 286 + Norwegian Forest,13,4,Sable,Female 287 + Birman,16,6,White,Female 288 + Siamese,12,6,Pointed,Female 289 + Ocicat,14,8,Cream,Male 290 + Egyptian Mau,15,2,Tabby,Male 291 + Manx,19,6,Cream,Female 292 + Cornish Rex,5,9,Brown,Female 293 + Chartreux,2,7,Gray,Male 294 + Egyptian Mau,18,7,Tricolor,Female 295 + Turkish Angora,18,8,Gray,Male 296 + Balinese,17,4,Tortoiseshell,Male 297 + Chartreux,10,8,Gray,Male 298 + Exotic Shorthair,17,9,Calico,Male 299 + Ragdoll,3,5,Pointed,Female 300 + Ragdoll,16,2,Cream,Male 301 + Abyssinian,18,9,Tortoiseshell,Male 302 + Oriental,7,3,Tricolor,Female 303 + Oriental,1,5,Tabby,Male 304 + Oriental,7,8,Cream,Male 305 + Cornish Rex,13,3,White,Female 306 + Ragdoll,16,2,Tortoiseshell,Male 307 + Turkish Angora,11,3,Calico,Female 308 + Singapura,3,5,Bicolor,Female 309 + American Shorthair,9,9,Sable,Female 310 + Russian Blue,7,6,Red,Female 311 + Ragdoll,3,8,Red,Male 312 + Oriental,1,2,White,Male 313 + Scottish Fold,11,6,Tabby,Male 314 + Ocicat,13,6,Tortoiseshell,Male 315 + Siberian,4,6,Black,Male 316 + Abyssinian,10,5,Tabby,Female 317 + Abyssinian,8,8,Orange,Female 318 + Exotic Shorthair,17,7,Blue,Female 319 + Chartreux,11,8,Black,Female 320 + Maine Coon,5,4,Tricolor,Male 321 + Russian Blue,18,6,Gray,Female 322 + Siamese,4,4,Gray,Female 323 + Siamese,6,2,Orange,Male 324 + Burmese,7,3,Bicolor,Male 325 + Maine Coon,12,6,White,Male 326 + Sphynx,3,7,Sable,Male 327 + Birman,8,4,Bicolor,Female 328 + Bengal,10,2,Black,Male 329 + Persian,1,5,Orange,Female 330 + Savannah,17,7,Blue,Male 331 + Siamese,18,8,Calico,Female 332 + Sphynx,9,7,Brown,Female 333 + Chartreux,16,2,Sable,Male 334 + Devon Rex,17,5,White,Male 335 + Birman,18,3,Brown,Female 336 + Exotic Shorthair,11,3,White,Female 337 + Maine Coon,18,7,Black,Male 338 + Himalayan,4,4,White,Female 339 + Devon Rex,8,9,Blue,Female 340 + Ragdoll,10,5,Orange,Female 341 + Burmese,4,5,Pointed,Female 342 + Ocicat,8,7,Orange,Male 343 + Birman,17,3,Tricolor,Male 344 + Balinese,3,7,Cream,Female 345 + Bengal,5,7,Tabby,Female 346 + Devon Rex,5,2,Gray,Male 347 + Manx,7,2,Blue,Male 348 + Ragdoll,1,4,Bicolor,Female 349 + Abyssinian,18,3,Black,Female 350 + Munchkin,6,8,Brown,Female 351 + Ragdoll,15,9,Pointed,Male 352 + American Shorthair,9,3,Tortoiseshell,Male 353 + Exotic Shorthair,3,6,Pointed,Female 354 + Himalayan,18,7,Pointed,Male 355 + Maine Coon,16,9,Black,Female 356 + American Shorthair,17,4,Red,Male 357 + Himalayan,9,3,Red,Female 358 + Exotic Shorthair,13,6,Tortoiseshell,Female 359 + Balinese,8,5,White,Female 360 + Exotic Shorthair,13,9,Orange,Male 361 + Siamese,1,8,Tabby,Female 362 + Sphynx,12,7,Calico,Female 363 + Sphynx,12,6,Tricolor,Female 364 + Russian Blue,9,3,Black,Male 365 + Russian Blue,1,2,Gray,Male 366 + Chartreux,14,4,Bicolor,Female 367 + Exotic Shorthair,14,5,Pointed,Male 368 + Siamese,6,8,Orange,Male 369 + Norwegian Forest,16,9,Bicolor,Female 370 + Ocicat,8,7,Blue,Female 371 + Chartreux,19,9,White,Female 372 + Abyssinian,5,2,Tortoiseshell,Male 373 + Abyssinian,15,4,Gray,Female 374 + Savannah,13,5,Gray,Male 375 + Tonkinese,6,5,Brown,Female 376 + Himalayan,17,7,Orange,Female 377 + British Shorthair,5,7,Orange,Male 378 + Abyssinian,10,3,Bicolor,Male 379 + American Shorthair,5,6,Pointed,Female 380 + Munchkin,17,7,Orange,Female 381 + Savannah,19,9,Tabby,Female 382 + Egyptian Mau,6,2,Cream,Female 383 + Himalayan,15,7,Calico,Male 384 + Oriental,4,9,Gray,Female 385 + Exotic Shorthair,17,6,Blue,Female 386 + Turkish Angora,1,9,Cream,Male 387 + Chartreux,18,3,Gray,Male 388 + Oriental,10,3,Gray,Female 389 + Manx,19,2,Red,Male 390 + American Shorthair,2,8,Black,Male 391 + Persian,17,5,Pointed,Male 392 + Ocicat,18,9,Pointed,Female 393 + Oriental,13,4,Tabby,Female 394 + Munchkin,7,8,Red,Female 395 + Savannah,5,5,Bicolor,Male 396 + Himalayan,4,6,Sable,Female 397 + Oriental,7,8,Orange,Male 398 + Singapura,5,7,Black,Female 399 + Persian,19,2,Tricolor,Female 400 + Tonkinese,7,8,Sable,Female 401 + Devon Rex,13,3,Bicolor,Male 402 + Scottish Fold,4,7,Sable,Male 403 + Bengal,15,5,Tricolor,Female 404 + Burmese,18,2,Cream,Female 405 + Balinese,4,4,Pointed,Female 406 + Ragdoll,4,7,Bicolor,Male 407 + Egyptian Mau,2,9,Gray,Male 408 + Birman,5,8,Tricolor,Female 409 + Burmese,8,3,Blue,Female 410 + Ocicat,11,5,Red,Female 411 + Exotic Shorthair,11,3,Black,Female 412 + Ocicat,18,9,Gray,Female 413 + Turkish Angora,19,9,Brown,Male 414 + Cornish Rex,17,6,Black,Female 415 + Persian,1,4,Red,Male 416 + Egyptian Mau,5,9,Black,Male 417 + Birman,3,7,Red,Female 418 + Abyssinian,14,4,Pointed,Female 419 + Cornish Rex,2,4,Brown,Female 420 + Siberian,3,8,Black,Female 421 + Singapura,3,6,Brown,Female 422 + Himalayan,13,5,Blue,Male 423 + Burmese,8,9,Sable,Male 424 + Balinese,14,9,Black,Female 425 + Cornish Rex,18,9,Pointed,Male 426 + Persian,13,7,Sable,Male 427 + Savannah,18,5,Calico,Female 428 + Munchkin,1,8,Gray,Male 429 + Bengal,2,5,Tortoiseshell,Male 430 + Manx,5,5,Pointed,Male 431 + Persian,11,9,Bicolor,Male 432 + Scottish Fold,11,5,Gray,Female 433 + Turkish Angora,1,2,Blue,Female 434 + Tonkinese,3,8,Blue,Female 435 + Munchkin,2,6,Blue,Female 436 + Balinese,14,4,Orange,Female 437 + American Shorthair,16,5,Bicolor,Male 438 + Bengal,18,5,Brown,Female 439 + Tonkinese,5,4,Cream,Male 440 + Ragdoll,8,4,Orange,Male 441 + Singapura,7,2,Bicolor,Female 442 + Egyptian Mau,10,6,Pointed,Female 443 + Abyssinian,16,3,Brown,Female 444 + Birman,19,7,Pointed,Female 445 + Exotic Shorthair,11,2,Black,Female 446 + Siberian,19,3,Tabby,Male 447 + Sphynx,3,2,Tricolor,Male 448 + Persian,18,6,White,Male 449 + Birman,4,6,Bicolor,Female 450 + Norwegian Forest,17,3,Cream,Male 451 + Norwegian Forest,13,8,Tortoiseshell,Female 452 + Chartreux,4,5,Tabby,Male 453 + Savannah,14,7,Tortoiseshell,Female 454 + Bengal,3,5,Cream,Male 455 + Abyssinian,4,5,Calico,Female 456 + Munchkin,18,8,Orange,Female 457 + Siberian,13,3,Sable,Male 458 + Singapura,7,5,Tabby,Male 459 + Scottish Fold,11,4,Black,Female 460 + Balinese,11,4,Tortoiseshell,Male 461 + Turkish Angora,6,6,Tortoiseshell,Male 462 + Himalayan,11,3,Sable,Male 463 + Ocicat,9,5,Blue,Male 464 + Egyptian Mau,16,4,White,Female 465 + Ragdoll,5,5,White,Male 466 + Oriental,6,7,Gray,Female 467 + American Shorthair,4,2,Black,Male 468 + Chartreux,8,5,Gray,Female 469 + Siamese,16,6,White,Male 470 + Egyptian Mau,16,8,Gray,Male 471 + Chartreux,11,2,Tortoiseshell,Female 472 + Singapura,14,9,Tricolor,Male 473 + Savannah,8,3,White,Male 474 + Cornish Rex,6,5,Orange,Female 475 + Munchkin,8,5,Red,Female 476 + Munchkin,19,2,Bicolor,Female 477 + American Shorthair,8,6,Blue,Female 478 + Siberian,1,9,Orange,Female 479 + Cornish Rex,13,6,Cream,Female 480 + Maine Coon,8,6,Blue,Male 481 + British Shorthair,9,7,Black,Male 482 + Scottish Fold,16,3,Orange,Male 483 + Chartreux,5,8,Tortoiseshell,Male 484 + Devon Rex,11,9,Tabby,Male 485 + Ocicat,17,2,Gray,Male 486 + Devon Rex,9,9,Red,Male 487 + Singapura,17,8,Black,Female 488 + Munchkin,15,4,Black,Male 489 + Ragdoll,1,3,Calico,Female 490 + Singapura,16,6,Gray,Male 491 + Himalayan,13,6,Blue,Female 492 + Scottish Fold,3,5,Cream,Male 493 + Oriental,14,7,Sable,Male 494 + Russian Blue,3,7,Red,Male 495 + Siberian,18,3,Gray,Female 496 + Manx,14,2,Tortoiseshell,Male 497 + British Shorthair,17,8,Brown,Male 498 + British Shorthair,6,8,Calico,Female 499 + Abyssinian,8,6,White,Male 500 + Birman,2,4,Gray,Male 501 + Siberian,18,5,Pointed,Male 502 + Burmese,3,2,Calico,Male 503 + Abyssinian,2,2,Tricolor,Male 504 + Devon Rex,5,7,Tortoiseshell,Female 505 + Burmese,9,2,Gray,Male 506 + Tonkinese,19,9,Sable,Male 507 + Burmese,2,7,Tricolor,Male 508 + Norwegian Forest,4,7,Cream,Male 509 + Manx,17,8,White,Female 510 + Birman,4,7,Brown,Female 511 + Ragdoll,6,9,Bicolor,Female 512 + British Shorthair,2,5,Tricolor,Male 513 + Himalayan,4,4,Tricolor,Female 514 + Abyssinian,8,6,Blue,Female 515 + Balinese,2,5,Pointed,Male 516 + Manx,2,5,Gray,Male 517 + Siamese,8,4,Brown,Female 518 + Munchkin,5,8,Tortoiseshell,Male 519 + Devon Rex,14,8,Pointed,Female 520 + Burmese,13,2,Cream,Female 521 + American Shorthair,19,6,Gray,Female 522 + Siberian,1,3,Cream,Female 523 + Cornish Rex,12,9,Sable,Male 524 + Burmese,3,2,Tricolor,Male 525 + Bengal,14,7,White,Male 526 + Bengal,5,2,Tabby,Male 527 + Russian Blue,17,4,Bicolor,Female 528 + Himalayan,17,3,White,Female 529 + Cornish Rex,11,6,Bicolor,Female 530 + Tonkinese,12,6,Cream,Female 531 + Manx,4,9,Tabby,Female 532 + Balinese,9,6,Bicolor,Female 533 + Maine Coon,15,9,Calico,Male 534 + Sphynx,1,4,Tabby,Female 535 + Manx,1,7,Tortoiseshell,Female 536 + Cornish Rex,3,3,Gray,Male 537 + Ocicat,12,3,Brown,Male 538 + Exotic Shorthair,6,2,Brown,Female 539 + Maine Coon,3,7,Orange,Male 540 + Egyptian Mau,8,5,Red,Female 541 + Chartreux,13,3,Calico,Male 542 + Cornish Rex,12,6,Calico,Male 543 + Egyptian Mau,2,6,Cream,Male 544 + Tonkinese,17,5,Cream,Male 545 + Tonkinese,19,5,Pointed,Male 546 + Abyssinian,19,2,Gray,Male 547 + Oriental,15,2,Bicolor,Male 548 + Himalayan,16,8,Red,Male 549 + Oriental,16,4,Blue,Male 550 + Tonkinese,6,7,Black,Female 551 + Persian,2,8,Calico,Female 552 + Egyptian Mau,11,6,Sable,Female 553 + Burmese,3,4,Cream,Male 554 + Bengal,9,6,Tricolor,Female 555 + Himalayan,16,4,Cream,Male 556 + Balinese,8,9,Gray,Male 557 + Chartreux,13,2,Pointed,Male 558 + Devon Rex,4,3,Calico,Male 559 + Ragdoll,2,7,Tabby,Female 560 + Scottish Fold,17,8,Sable,Male 561 + Maine Coon,18,5,Tabby,Male 562 + Balinese,17,6,Red,Female 563 + Bengal,6,7,Orange,Male 564 + Bengal,11,2,Red,Female 565 + Devon Rex,18,8,White,Male 566 + Devon Rex,14,2,Gray,Male 567 + Norwegian Forest,1,2,Tortoiseshell,Male 568 + Scottish Fold,2,4,Tortoiseshell,Male 569 + Siberian,7,7,Cream,Male 570 + Birman,10,9,Bicolor,Female 571 + Ocicat,6,9,Tricolor,Male 572 + Savannah,13,5,Calico,Female 573 + Balinese,11,8,Tabby,Female 574 + British Shorthair,17,2,Cream,Female 575 + Oriental,18,4,Calico,Female 576 + Munchkin,5,8,Red,Female 577 + Ocicat,15,2,Gray,Female 578 + Norwegian Forest,14,9,Cream,Male 579 + Ragdoll,18,4,Tabby,Female 580 + Egyptian Mau,7,9,Sable,Male 581 + Russian Blue,11,7,Blue,Male 582 + American Shorthair,6,3,Bicolor,Male 583 + Himalayan,5,9,Cream,Female 584 + Scottish Fold,5,4,Tricolor,Male 585 + Siamese,19,6,Gray,Male 586 + Maine Coon,19,9,Brown,Female 587 + Savannah,11,5,Gray,Female 588 + Ragdoll,12,4,Pointed,Female 589 + Russian Blue,15,5,Tabby,Male 590 + Bengal,17,9,White,Female 591 + Singapura,2,4,Tricolor,Female 592 + Maine Coon,9,5,Blue,Female 593 + Himalayan,8,9,Tabby,Male 594 + Persian,6,9,Gray,Male 595 + Abyssinian,16,7,Red,Female 596 + Burmese,10,3,Red,Female 597 + Singapura,1,6,Cream,Male 598 + Bengal,15,6,Tricolor,Male 599 + Ragdoll,3,6,Pointed,Female 600 + Sphynx,5,8,Sable,Male 601 + British Shorthair,1,8,Pointed,Male 602 + Ragdoll,6,4,Pointed,Female 603 + Siamese,18,9,Brown,Female 604 + Manx,5,8,White,Male 605 + Birman,1,6,Bicolor,Male 606 + Munchkin,18,2,Red,Female 607 + Maine Coon,18,2,Cream,Female 608 + Munchkin,9,8,Sable,Male 609 + Bengal,10,8,Pointed,Female 610 + Singapura,5,6,Black,Female 611 + Persian,10,7,Gray,Male 612 + Burmese,13,6,Red,Female 613 + Siberian,17,4,Pointed,Female 614 + Egyptian Mau,4,8,White,Female 615 + Oriental,1,6,Black,Male 616 + Chartreux,15,5,Pointed,Female 617 + Sphynx,1,7,Calico,Female 618 + Maine Coon,12,3,White,Female 619 + Abyssinian,2,4,Red,Female 620 + Exotic Shorthair,19,4,Tortoiseshell,Female 621 + Birman,15,8,Red,Female 622 + Tonkinese,13,2,Pointed,Female 623 + Balinese,9,4,Blue,Female 624 + Abyssinian,6,4,Black,Male 625 + Ragdoll,3,8,Cream,Female 626 + Chartreux,18,3,Cream,Female 627 + Ocicat,16,7,Blue,Female 628 + Russian Blue,4,9,Tricolor,Female 629 + Ragdoll,17,5,Cream,Female 630 + British Shorthair,19,8,Tortoiseshell,Female 631 + Balinese,6,3,Gray,Male 632 + Abyssinian,19,7,Tortoiseshell,Male 633 + Egyptian Mau,8,7,Gray,Male 634 + Persian,18,7,Sable,Female 635 + Sphynx,5,5,Calico,Male 636 + Ocicat,14,2,Gray,Female 637 + Savannah,16,7,Sable,Female 638 + Oriental,15,3,Tricolor,Male 639 + Egyptian Mau,19,3,Tricolor,Female 640 + Abyssinian,1,3,Tabby,Male 641 + Chartreux,5,6,Tricolor,Male 642 + Sphynx,7,6,Gray,Male 643 + Munchkin,13,8,Tricolor,Male 644 + Birman,4,9,Tricolor,Male 645 + Savannah,19,7,Gray,Male 646 + Turkish Angora,14,3,Blue,Male 647 + Persian,18,4,Bicolor,Female 648 + Birman,2,2,Bicolor,Female 649 + Egyptian Mau,19,4,Orange,Male 650 + British Shorthair,13,2,Tortoiseshell,Male 651 + Manx,16,9,Sable,Female 652 + Scottish Fold,8,8,Sable,Male 653 + Egyptian Mau,3,8,Brown,Male 654 + Siamese,8,7,Pointed,Female 655 + Ocicat,14,8,Cream,Male 656 + Cornish Rex,17,2,Sable,Female 657 + Persian,2,6,White,Female 658 + Egyptian Mau,17,8,Calico,Female 659 + Singapura,14,2,Tabby,Female 660 + Turkish Angora,6,8,Calico,Male 661 + Persian,19,9,Cream,Male 662 + Egyptian Mau,17,3,Calico,Male 663 + British Shorthair,13,9,Gray,Female 664 + Maine Coon,5,9,Sable,Female 665 + Russian Blue,17,3,Pointed,Female 666 + Ocicat,15,7,Black,Female 667 + Manx,9,7,Blue,Male 668 + American Shorthair,15,8,Gray,Male 669 + Siberian,18,2,White,Male 670 + Oriental,11,8,Tricolor,Male 671 + Bengal,15,6,Red,Female 672 + Manx,7,4,Pointed,Female 673 + Exotic Shorthair,14,6,Calico,Male 674 + Ocicat,5,6,Pointed,Female 675 + Himalayan,16,9,Gray,Male 676 + Ragdoll,15,4,Red,Female 677 + Siamese,11,3,Tricolor,Female 678 + Balinese,12,8,Blue,Female 679 + Siberian,15,7,Red,Female 680 + Manx,12,8,Tabby,Female 681 + Norwegian Forest,3,5,Blue,Male 682 + Cornish Rex,1,6,Tabby,Female 683 + Bengal,15,3,Tortoiseshell,Female 684 + Oriental,7,2,Blue,Male 685 + Bengal,19,6,Red,Male 686 + Himalayan,15,6,Calico,Male 687 + American Shorthair,14,9,Tortoiseshell,Female 688 + Siberian,13,8,Pointed,Female 689 + Siberian,6,2,Cream,Male 690 + Cornish Rex,9,9,Blue,Male 691 + Siamese,9,5,Gray,Female 692 + Ragdoll,16,5,Red,Female 693 + Oriental,11,4,Brown,Female 694 + Singapura,11,7,Tricolor,Female 695 + Cornish Rex,18,2,Red,Female 696 + Singapura,1,9,Calico,Male 697 + Tonkinese,8,3,Brown,Male 698 + Tonkinese,7,3,Tortoiseshell,Male 699 + Russian Blue,3,5,Gray,Female 700 + Norwegian Forest,2,4,White,Female 701 + Siamese,17,7,Calico,Female 702 + Singapura,14,4,Tricolor,Female 703 + Egyptian Mau,18,8,White,Female 704 + British Shorthair,8,3,Black,Male 705 + Turkish Angora,2,7,Pointed,Male 706 + Devon Rex,3,7,Bicolor,Female 707 + Exotic Shorthair,1,8,Bicolor,Female 708 + Munchkin,19,4,Black,Male 709 + Norwegian Forest,7,7,Cream,Male 710 + Singapura,7,5,White,Female 711 + Birman,4,5,Bicolor,Male 712 + Persian,5,4,Cream,Female 713 + Scottish Fold,19,5,Black,Female 714 + Savannah,7,7,Gray,Male 715 + Siberian,15,8,Calico,Female 716 + Abyssinian,16,5,Black,Female 717 + British Shorthair,18,4,Calico,Female 718 + Siberian,2,5,Tabby,Male 719 + Chartreux,10,9,Orange,Male 720 + Norwegian Forest,18,2,Tortoiseshell,Female 721 + Oriental,12,5,Blue,Male 722 + British Shorthair,1,6,Tricolor,Female 723 + Chartreux,4,3,Tabby,Female 724 + Savannah,5,2,Black,Male 725 + American Shorthair,16,4,Tricolor,Female 726 + Abyssinian,6,3,White,Male 727 + Munchkin,5,6,Red,Female 728 + Maine Coon,10,3,Brown,Female 729 + Oriental,17,5,Blue,Female 730 + Siamese,17,3,Gray,Female 731 + American Shorthair,6,9,Pointed,Male 732 + Munchkin,1,4,Tortoiseshell,Female 733 + Turkish Angora,4,5,Orange,Male 734 + Sphynx,9,9,Orange,Male 735 + Ocicat,10,5,Tricolor,Male 736 + Tonkinese,11,6,Tricolor,Male 737 + Bengal,7,8,Cream,Female 738 + Exotic Shorthair,13,7,Black,Female 739 + American Shorthair,12,9,Black,Male 740 + Munchkin,3,3,Tortoiseshell,Male 741 + Turkish Angora,18,7,Pointed,Male 742 + Exotic Shorthair,8,9,Calico,Male 743 + American Shorthair,8,6,Tricolor,Male 744 + Maine Coon,7,8,Blue,Female 745 + Russian Blue,6,5,Sable,Male 746 + Persian,10,5,Blue,Male 747 + Oriental,13,8,Bicolor,Female 748 + Devon Rex,9,6,Orange,Female 749 + Siamese,2,8,Calico,Male 750 + Birman,15,5,Tabby,Male 751 + Egyptian Mau,14,8,Sable,Male 752 + Exotic Shorthair,16,7,Black,Female 753 + Scottish Fold,5,7,Red,Female 754 + Devon Rex,3,3,Cream,Male 755 + Singapura,8,2,Blue,Female 756 + Ocicat,14,7,Gray,Male 757 + Burmese,9,8,Tortoiseshell,Female 758 + Burmese,6,6,Bicolor,Female 759 + Maine Coon,8,4,Tabby,Male 760 + Persian,16,2,Sable,Male 761 + Sphynx,16,4,Black,Female 762 + Burmese,10,5,Pointed,Male 763 + Siamese,10,2,Orange,Female 764 + Norwegian Forest,12,5,Brown,Female 765 + Ragdoll,4,9,White,Male 766 + Munchkin,8,5,Sable,Female 767 + Turkish Angora,19,9,Bicolor,Female 768 + Sphynx,9,9,Red,Female 769 + Savannah,2,9,White,Male 770 + Egyptian Mau,4,8,Sable,Female 771 + Burmese,19,7,Black,Male 772 + British Shorthair,18,6,Brown,Male 773 + Balinese,15,8,Red,Female 774 + British Shorthair,11,8,Calico,Male 775 + Munchkin,11,4,Bicolor,Male 776 + Egyptian Mau,12,8,Calico,Male 777 + British Shorthair,14,7,Tortoiseshell,Female 778 + Siamese,15,3,Black,Male 779 + Munchkin,6,6,Pointed,Male 780 + Munchkin,11,6,Blue,Female 781 + British Shorthair,8,4,Pointed,Male 782 + Sphynx,18,6,Cream,Male 783 + Ocicat,6,9,Orange,Male 784 + Sphynx,7,4,Red,Female 785 + Siberian,12,6,Orange,Male 786 + Oriental,12,2,Black,Male 787 + Bengal,18,9,Blue,Male 788 + Tonkinese,19,4,Bicolor,Female 789 + Siberian,6,3,Orange,Female 790 + Chartreux,18,8,Blue,Female 791 + Ocicat,9,7,Orange,Male 792 + Himalayan,18,6,Black,Female 793 + Ragdoll,11,7,Brown,Male 794 + Siberian,8,8,Calico,Male 795 + Egyptian Mau,12,2,Tricolor,Female 796 + Singapura,15,7,Pointed,Male 797 + Birman,1,3,Red,Male 798 + Manx,2,8,Calico,Male 799 + Chartreux,2,6,Pointed,Male 800 + Siberian,5,6,Bicolor,Female 801 + Sphynx,13,7,Blue,Male 802 + Tonkinese,9,7,Orange,Male 803 + Devon Rex,19,7,Orange,Male 804 + Manx,13,5,Tabby,Male 805 + Turkish Angora,4,6,Calico,Male 806 + Cornish Rex,11,3,Orange,Male 807 + Sphynx,8,3,Tricolor,Female 808 + Maine Coon,15,2,Sable,Male 809 + Sphynx,9,5,Cream,Male 810 + British Shorthair,15,2,Tortoiseshell,Male 811 + Russian Blue,4,9,Gray,Male 812 + Singapura,4,8,Orange,Female 813 + Scottish Fold,18,2,Sable,Female 814 + Ocicat,13,6,Bicolor,Female 815 + Tonkinese,14,8,Sable,Male 816 + Turkish Angora,8,2,Tricolor,Female 817 + Birman,16,4,Brown,Male 818 + Abyssinian,15,5,Sable,Male 819 + Siberian,8,6,Brown,Female 820 + Sphynx,11,4,Tortoiseshell,Male 821 + Norwegian Forest,14,3,Red,Male 822 + Ocicat,19,5,Tortoiseshell,Male 823 + Scottish Fold,2,9,Sable,Female 824 + Ragdoll,12,3,Tabby,Male 825 + Scottish Fold,19,7,Cream,Male 826 + American Shorthair,15,8,Brown,Male 827 + Manx,6,3,Tricolor,Female 828 + Ocicat,9,6,White,Male 829 + Manx,19,4,Orange,Female 830 + Ragdoll,3,5,Orange,Female 831 + Exotic Shorthair,12,6,White,Male 832 + Turkish Angora,13,2,Calico,Female 833 + American Shorthair,12,5,Tabby,Female 834 + Sphynx,9,6,Tricolor,Female 835 + Singapura,5,9,Sable,Male 836 + Bengal,18,5,Brown,Female 837 + Himalayan,13,9,Cream,Male 838 + Sphynx,18,5,Calico,Female 839 + Burmese,11,8,Brown,Female 840 + Ragdoll,17,6,Tabby,Male 841 + Sphynx,11,3,Orange,Female 842 + Birman,12,8,Tricolor,Female 843 + Bengal,3,3,Tabby,Male 844 + Singapura,11,8,Blue,Female 845 + Himalayan,13,6,White,Female 846 + Cornish Rex,18,5,Bicolor,Female 847 + Burmese,8,3,Brown,Male 848 + Maine Coon,17,4,Sable,Female 849 + American Shorthair,11,2,Blue,Male 850 + Maine Coon,3,2,Brown,Male 851 + Turkish Angora,16,4,Black,Female 852 + Himalayan,12,9,Pointed,Female 853 + Abyssinian,15,8,Sable,Female 854 + Chartreux,10,4,Tricolor,Female 855 + Savannah,4,4,Black,Female 856 + Turkish Angora,17,5,Blue,Male 857 + Devon Rex,1,3,Tabby,Female 858 + Balinese,14,4,Blue,Female 859 + Maine Coon,7,6,Tortoiseshell,Male 860 + Himalayan,5,7,Brown,Female 861 + Exotic Shorthair,4,2,Gray,Male 862 + Russian Blue,18,2,Sable,Female 863 + Tonkinese,17,4,Brown,Male 864 + Turkish Angora,8,3,Black,Male 865 + Tonkinese,12,4,Tabby,Male 866 + Persian,3,6,Blue,Female 867 + Siamese,9,4,White,Female 868 + Egyptian Mau,9,5,Bicolor,Female 869 + Cornish Rex,7,9,Orange,Male 870 + Munchkin,2,8,Orange,Male 871 + Manx,5,8,Brown,Male 872 + Turkish Angora,12,8,Cream,Male 873 + American Shorthair,6,8,Pointed,Male 874 + Savannah,8,4,Bicolor,Male 875 + Balinese,11,5,Brown,Female 876 + Oriental,10,3,Tortoiseshell,Male 877 + Turkish Angora,19,8,Gray,Male 878 + Persian,6,7,Brown,Female 879 + Russian Blue,14,8,Gray,Female 880 + Tonkinese,16,3,Calico,Female 881 + Oriental,13,9,Bicolor,Female 882 + American Shorthair,12,6,Brown,Female 883 + Bengal,1,3,Orange,Female 884 + Abyssinian,15,5,Red,Male 885 + Ragdoll,8,3,Bicolor,Female 886 + Devon Rex,1,5,Tortoiseshell,Female 887 + Russian Blue,2,6,Gray,Male 888 + Sphynx,16,5,Pointed,Male 889 + Balinese,14,4,Tortoiseshell,Female 890 + Siberian,12,8,Gray,Male 891 + Devon Rex,16,3,Bicolor,Male 892 + Siberian,5,8,Gray,Female 893 + American Shorthair,11,8,Blue,Male 894 + Egyptian Mau,8,2,Brown,Male 895 + Himalayan,11,8,Cream,Female 896 + Abyssinian,12,4,Calico,Female 897 + Singapura,1,7,Red,Female 898 + Himalayan,18,8,Tricolor,Female 899 + Turkish Angora,13,8,Gray,Male 900 + Exotic Shorthair,12,5,Gray,Male 901 + Ragdoll,16,9,Red,Female 902 + Scottish Fold,3,7,Tricolor,Male 903 + Balinese,3,7,Brown,Male 904 + Scottish Fold,11,7,Brown,Male 905 + Maine Coon,5,4,Pointed,Female 906 + Cornish Rex,5,4,Black,Female 907 + Balinese,13,4,Red,Male 908 + Devon Rex,18,8,Bicolor,Male 909 + Scottish Fold,17,8,Tortoiseshell,Male 910 + American Shorthair,16,4,Tricolor,Male 911 + Munchkin,7,5,Black,Female 912 + Singapura,7,3,Tabby,Male 913 + Cornish Rex,17,3,Cream,Male 914 + Balinese,10,4,Orange,Female 915 + Devon Rex,14,2,Calico,Male 916 + Siamese,10,9,Blue,Male 917 + British Shorthair,3,3,Orange,Male 918 + Oriental,10,5,Tricolor,Male 919 + Siamese,15,8,White,Female 920 + Balinese,5,5,Blue,Male 921 + Russian Blue,1,3,Sable,Female 922 + Oriental,11,5,Cream,Male 923 + Manx,14,5,Calico,Female 924 + Munchkin,12,6,Bicolor,Male 925 + Chartreux,3,5,Red,Female 926 + Bengal,6,3,Tortoiseshell,Male 927 + Singapura,8,3,Orange,Male 928 + Bengal,18,7,Brown,Male 929 + Oriental,4,7,Sable,Male 930 + Scottish Fold,16,8,Tricolor,Male 931 + Russian Blue,3,2,Brown,Female 932 + Birman,17,4,Tabby,Female 933 + Maine Coon,19,3,Tortoiseshell,Female 934 + Sphynx,19,5,Black,Female 935 + Abyssinian,11,7,White,Male 936 + Persian,19,7,Sable,Male 937 + Singapura,4,2,Orange,Female 938 + Maine Coon,18,6,Tabby,Male 939 + Singapura,8,9,Orange,Female 940 + Ragdoll,11,8,Gray,Male 941 + Manx,15,7,Black,Male 942 + American Shorthair,6,2,Cream,Female 943 + Burmese,12,5,Tricolor,Male 944 + American Shorthair,11,3,Bicolor,Male 945 + Balinese,11,8,Calico,Male 946 + Munchkin,10,8,Calico,Female 947 + Birman,4,2,Sable,Male 948 + American Shorthair,12,8,Tortoiseshell,Female 949 + Manx,1,5,Red,Female 950 + Burmese,7,6,Brown,Female 951 + Abyssinian,2,7,Cream,Female 952 + Scottish Fold,13,2,White,Female 953 + Ocicat,10,9,Cream,Male 954 + Munchkin,12,5,Brown,Male 955 + Burmese,4,4,White,Male 956 + American Shorthair,10,3,Tortoiseshell,Male 957 + Ragdoll,9,5,Tortoiseshell,Male 958 + Russian Blue,9,4,Brown,Female 959 + Egyptian Mau,10,3,Pointed,Male 960 + Siberian,14,7,Bicolor,Male 961 + Tonkinese,16,9,Pointed,Female 962 + Persian,16,3,Tabby,Male 963 + Scottish Fold,5,3,Blue,Female 964 + Ragdoll,2,4,Tricolor,Female 965 + British Shorthair,6,2,Red,Male 966 + Ocicat,11,7,Sable,Male 967 + Ragdoll,1,4,Tortoiseshell,Male 968 + Manx,7,8,Orange,Female 969 + British Shorthair,4,4,Blue,Female 970 + Egyptian Mau,17,5,Sable,Female 971 + Siamese,4,5,White,Male 972 + American Shorthair,7,6,Cream,Female 973 + American Shorthair,10,9,Red,Female 974 + British Shorthair,6,4,Cream,Male 975 + Balinese,12,4,Orange,Male 976 + Savannah,18,6,Tortoiseshell,Female 977 + Tonkinese,12,4,Tortoiseshell,Male 978 + Persian,4,9,Calico,Female 979 + Bengal,15,4,Brown,Female 980 + Siberian,15,6,Tabby,Female 981 + Oriental,17,6,Blue,Male 982 + Siamese,4,6,Pointed,Male 983 + Maine Coon,7,3,White,Female 984 + Russian Blue,12,5,Calico,Female 985 + Norwegian Forest,7,6,Bicolor,Female 986 + Tonkinese,3,3,Red,Female 987 + Maine Coon,1,9,Sable,Male 988 + Cornish Rex,2,7,Tabby,Male 989 + Russian Blue,5,5,White,Male 990 + Sphynx,14,9,White,Male 991 + British Shorthair,9,9,White,Male 992 + Maine Coon,8,6,Tabby,Female 993 + Scottish Fold,18,9,Red,Male 994 + British Shorthair,9,7,Tabby,Female 995 + Exotic Shorthair,6,4,Calico,Female 996 + British Shorthair,2,4,Tabby,Female 997 + British Shorthair,19,5,Gray,Female 998 + British Shorthair,11,2,Bicolor,Female 999 + Savannah,12,5,Bicolor,Female 1000 + American Shorthair,8,3,Tortoiseshell,Female 1001 + Chartreux,11,4,Sable,Female
+55
python/oct15/cats/main.py
··· 1 + import numpy 2 + import pandas as pd 3 + import matplotlib.pyplot as plt 4 + import seaborn as sns 5 + 6 + 7 + def loadCatsDatabase(): 8 + df = pd.read_csv('./cats/cats_dataset.csv') 9 + return df 10 + 11 + 12 + def avg_age(df: pd.DataFrame, breed: str|None = None) -> float: 13 + new_df = df 14 + if breed: 15 + new_df = df[df["Breed"] == breed] 16 + return numpy.round(new_df['Age (Years)'].astype(int).sum()/len(new_df['Age (Years)']), 2) 17 + 18 + def high_age_breed(df: pd.DataFrame) -> tuple[str, float]: 19 + vals: list[tuple[str, float]] = [] 20 + for breed in df["Breed"].unique(): 21 + vals.append((breed, avg_age(df, str(breed)))) 22 + highest = vals[0] 23 + for (b, v) in vals[1:]: 24 + if v > highest[1]: 25 + highest = (b, v) 26 + return highest 27 + 28 + def weight_avg(df: pd.DataFrame) -> float: 29 + return numpy.round(df["Weight (kg)"].astype(float).sum()/len(df["Weight (kg)"]), 2) 30 + 31 + def gender_heavier(df: pd.DataFrame) -> str: 32 + male_avg = weight_avg(df[df["Gender"] == "Male"]) 33 + female_avg = weight_avg(df[df["Gender"] == "Female"]) 34 + return "male" if male_avg > female_avg else "female" 35 + 36 + def correlation(df: pd.DataFrame) -> bool: 37 + corr = df["Age (Years)"].corr(df["Weight (kg)"]) 38 + return abs(corr) > 0.9 39 + 40 + def cat_age_histogram(df: pd.DataFrame) -> None: 41 + ages = df["Age (Years)"].astype(int) 42 + _ = sns.histplot(data=ages) 43 + plt.show() 44 + 45 + print("Running tests...", end="") 46 + try: 47 + df = loadCatsDatabase() 48 + assert(avg_age(df) == 10.21) # Q1 49 + assert(high_age_breed(df) == ("Himalayan", 11.67)) # Q2 50 + assert(gender_heavier(df) == "female") # Q3 51 + assert(not correlation(df)) # Q4 52 + cat_age_histogram(df) 53 + print("Passed!") 54 + except: 55 + print("Failed :(")
python/oct15/fast-food-nutrition/Figure_1.png

This is a binary file and will not be displayed.

python/oct15/fast-food-nutrition/Figure_2.png

This is a binary file and will not be displayed.

+6
python/oct15/fast-food-nutrition/README.txt
··· 1 + Source: 2 + https://www.kaggle.com/datasets/ulrikthygepedersen/fastfood-nutrition 3 + 4 + License: 5 + Attribution 4.0 International (CC BY 4.0) 6 + https://creativecommons.org/licenses/by/4.0/
+516
python/oct15/fast-food-nutrition/fastfood.csv
··· 1 + restaurant,item,calories,cal_fat,total_fat,sat_fat,trans_fat,cholesterol,sodium,total_carb,fiber,sugar,protein,vit_a,vit_c,calcium,salad 2 + Mcdonalds,Artisan Grilled Chicken Sandwich,380,60,7,2,0,95,1110,44,3,11,37,4,20,20,Other 3 + Mcdonalds,Single Bacon Smokehouse Burger,840,410,45,17,1.5,130,1580,62,2,18,46,6,20,20,Other 4 + Mcdonalds,Double Bacon Smokehouse Burger,1130,600,67,27,3,220,1920,63,3,18,70,10,20,50,Other 5 + Mcdonalds,Grilled Bacon Smokehouse Chicken Sandwich,750,280,31,10,0.5,155,1940,62,2,18,55,6,25,20,Other 6 + Mcdonalds,Crispy Bacon Smokehouse Chicken Sandwich,920,410,45,12,0.5,120,1980,81,4,18,46,6,20,20,Other 7 + Mcdonalds,Big Mac,540,250,28,10,1,80,950,46,3,9,25,10,2,15,Other 8 + Mcdonalds,Cheeseburger,300,100,12,5,0.5,40,680,33,2,7,15,10,2,10,Other 9 + Mcdonalds,Classic Chicken Sandwich,510,210,24,4,0,65,1040,49,3,6,25,0,4,2,Other 10 + Mcdonalds,Double Cheeseburger,430,190,21,11,1,85,1040,35,2,7,25,20,4,15,Other 11 + Mcdonalds,Double Quarter Pounderยฎ with Cheese,770,400,45,21,2.5,175,1290,42,3,10,51,20,6,20,Other 12 + Mcdonalds,Filet-O-Fishยฎ,380,170,18,4,0,40,640,38,2,5,15,2,0,15,Other 13 + Mcdonalds,Garlic White Cheddar Burger,620,300,34,13,1.5,95,790,48,3,11,32,10,10,35,Other 14 + Mcdonalds,Grilled Garlic White Cheddar Chicken Sandwich,530,180,20,7,0,125,1150,48,3,11,42,10,20,35,Other 15 + Mcdonalds,Crispy Garlic White Cheddar Chicken Sandwich,700,300,34,9,0,85,1190,67,5,11,33,10,15,35,Other 16 + Mcdonalds,Hamburger,250,70,8,3,0,30,480,31,2,6,13,2,2,4,Other 17 + Mcdonalds,Lobster Roll,290,50,5,1.5,0,65,630,35,2,3,24,4,6,15,Other 18 + Mcdonalds,Maple Bacon Dijon 1/4 lb Burger,640,330,36,14,1.5,110,1260,40,3,10,37,6,15,15,Other 19 + Mcdonalds,Grilled Maple Bacon Dijon Chicken Sandwich,580,190,21,8,0,135,1890,50,3,14,48,4,30,30,Other 20 + Mcdonalds,Crispy Maple Bacon Dijon Chicken Sandwich,740,310,35,9,0.5,95,1780,69,5,14,39,4,20,290,Other 21 + Mcdonalds,McChicken,350,130,15,3.5,0,40,600,40,2,5,15,2,2,4,Other 22 + Mcdonalds,McDouble,380,160,18,8,1,70,840,34,2,7,23,10,2,10,Other 23 + Mcdonalds,McRib,480,200,22,7,0,80,870,45,2,12,25,2,2,6,Other 24 + Mcdonalds,Pico Guacamole 1/4 lb Burger,580,300,33,12,1.5,95,920,41,4,7,29,8,15,15,Other 25 + Mcdonalds,Grilled Pico Guacamole Chicken Sandwich,520,160,18,6,0,115,1540,50,4,12,40,8,25,30,Other 26 + Mcdonalds,Crispy Pico Guacamole Chicken Sandwich,680,280,32,7,0,80,1430,69,6,12,31,8,15,30,Other 27 + Mcdonalds,Premium Buttermilk Crispy Chicken Deluxe Sandwich,570,200,23,5,0,60,1050,64,4,11,28,4,10,20,Other 28 + Mcdonalds,Premium Crispy Chicken Deluxe Sandwich,530,200,22,4,0,45,1000,59,3,13,25,6,10,20,Other 29 + Mcdonalds,Quarter Pounderยฎ with Cheese,530,240,27,13,1.5,100,1090,41,3,10,31,20,6,15,Other 30 + Mcdonalds,Signature Sriracha Burger,670,320,35,12,1.5,95,1010,56,4,13,32,20,15,30,Other 31 + Mcdonalds,Grilled Signature Sriracha Chicken Sandwich,560,180,20,5,0,115,1550,56,4,14,41,20,25,30,Other 32 + Mcdonalds,Crispy Signature Sriracha Chicken Sandwich,730,300,33,7,0,80,1430,75,5,13,32,20,20,30,Other 33 + Mcdonalds,Sweet BBQ Bacon 1/4 lb Burger,690,340,37,14,1.5,110,1310,51,3,14,38,6,15,15,Other 34 + Mcdonalds,Grilled Sweet BBQ Bacon Chicken Sandwich,630,200,22,7,0,135,1930,61,4,18,48,4,30,25,Other 35 + Mcdonalds,Crispy Sweet BBQ Bacon Chicken Sandwich,800,320,36,9,0.5,95,1820,80,5,18,39,4,20,30,Other 36 + Mcdonalds,3 piece Buttermilk Crispy Chicken Tenders,370,190,21,3.5,0,70,910,16,0,0,28,0,0,2,Other 37 + Mcdonalds,4 piece Buttermilk Crispy Chicken Tenders,480,250,28,4.5,0,95,1290,21,0,1,38,0,0,2,Other 38 + Mcdonalds,6 piece Buttermilk Crispy Chicken Tenders,760,390,44,8,0.5,145,1890,32,1,1,58,0,0,2,Other 39 + Mcdonalds,10 piece Buttermilk Crispy Chicken Tenders,1210,630,70,12,1,240,3230,52,1,4,94,0,0,4,Other 40 + Mcdonalds,12 piece Buttermilk Crispy Chicken Tenders,1510,790,88,15,1,295,3770,64,1,2,115,0,2,6,Other 41 + Mcdonalds,20 piece Buttermilk Crispy Chicken Tenders,2430,1270,141,24,2,475,6080,103,2,3,186,0,2,8,Other 42 + Mcdonalds,4 Piece Chicken McNuggets,180,100,11,2,0,30,340,11,1,0,10,0,2,0,Other 43 + Mcdonalds,6 Piece Chicken McNuggets,270,140,16,2.5,0,45,510,16,1,0,15,0,2,0,Other 44 + Mcdonalds,10 Piece Chicken McNuggets,440,240,27,4.5,0,75,840,26,2,0,24,0,4,2,Other 45 + Mcdonalds,20 Piece Chicken McNuggets,890,480,53,9,0,145,1680,53,4,0,49,0,8,4,Other 46 + Mcdonalds,40 piece Chicken McNuggets,1770,960,107,18,0.5,295,3370,105,7,1,98,0,15,6,Other 47 + Mcdonalds,4 piece Sweet N' Spicy Honey BBQ Glazed Tenders,640,240,27,4,0,105,1780,63,2,35,39,4,15,4,Other 48 + Mcdonalds,6 piece Sweet N' Spicy Honey BBQ Glazed Tenders,960,360,40,6,0,160,2670,94,3,52,58,4,25,8,Other 49 + Mcdonalds,10 piece Sweet N' Spicy Honey BBQ Glazed Tenders,1600,600,66,10,0,265,4450,156,5,87,97,8,40,10,Other 50 + Mcdonalds,Premium Asian Salad w/o Chicken,140,70,7,0.5,0,0,20,13,5,7,7,180,45,10,Other 51 + Mcdonalds,Premium Asian Salad w/ Grilled Chicken,270,80,9,1,0,80,740,18,5,10,31,180,70,10,Other 52 + Mcdonalds,Premium Asian Salad w/ Crispy Chicken,490,250,28,8,0,95,1120,28,4,4,33,180,60,15,Other 53 + Mcdonalds,Premium Bacon Ranch Salad w/o Chicken,190,110,12,5,0,40,660,9,3,3,14,180,50,15,Other 54 + Mcdonalds,Premium Bacon Ranch Salad w/ Grilled Chicken,320,120,14,6,0,45,1230,9,3,4,42,180,60,15,Other 55 + Mcdonalds,Premium Bacon Ranch Salad w/ Crispy Chicken,490,250,28,8,0,95,1120,28,4,4,33,180,60,15,Other 56 + Mcdonalds,Premium Southwest Salad w/o Chicken,220,90,10,3.5,0,15,500,26,6,9,8,180,40,20,Other 57 + Mcdonalds,Premium Southwest Salad w/ Grilled Chicken,350,100,12,4.5,0,110,1070,27,6,9,37,180,50,20,Other 58 + Mcdonalds,Premium Southwest Salad w/ Crispy Chicken,520,230,25,6,0,75,960,46,8,9,28,180,40,20,Other 59 + Chick Fil-A,Chargrilled Chicken Club Sandwich,430,144,16,8,0,85,1120,37,3,7,37,30,40,25,Other 60 + Chick Fil-A,Chargrilled Chicken Sandwich,310,54,6,2,0,55,820,36,3,7,29,25,40,10,Other 61 + Chick Fil-A,Chick-n-Slider,270,99,11,2.5,0,45,800,26,1,4,16,NA,0,2,Other 62 + Chick Fil-A,1 Piece Chick-n-Strips,120,54,6,3,0,25,320,6,0,1,11,0,0,2,Other 63 + Chick Fil-A,2 Piece Chick-n-Strips,230,108,12,3,0,55,630,13,1,1,22,0,2,4,Other 64 + Chick Fil-A,3 Piece Chick-n-Strips,350,153,17,3,0,70,940,22,1,3,28,2,2,6,Other 65 + Chick Fil-A,4 piece Chick-n-Strips,470,207,23,3,0,90,1250,29,1,4,37,2,4,8,Other 66 + Chick Fil-A,Chicken Deluxe,500,207,23,7,0,75,1590,42,3,6,31,30,10,20,Other 67 + Chick Fil-A,4 piece Chicken Nuggets,130,54,6,1.5,0,40,490,5,1,0,14,0,2,2,Other 68 + Chick Fil-A,6 piece Chicken Nuggets,190,81,9,1.5,0,55,730,7,1,0,21,0,4,2,Other 69 + Chick Fil-A,8 piece Chicken Nuggets,260,110,12,3,0,70,990,9,1,1,28,0,2,4,Other 70 + Chick Fil-A,12 piece Chicken Nuggets,390,162,18,1.5,0,115,1460,14,2,1,41,0,8,4,Other 71 + Chick Fil-A,30 piece Chicken Nuggets,970,414,46,2.5,0,285,3660,35,4,1,103,NA,20,10,Other 72 + Chick Fil-A,Chicken Salad Sandwich,490,170,19,3,0,80,1130,55,5,12,28,35,8,15,Other 73 + Chick Fil-A,Chicken Sandwich,440,171,19,4,0,60,1350,40,2,5,28,2,4,15,Other 74 + Chick Fil-A,4 Piece Grilled Chicken Nuggets,70,18,2,1,0,35,220,1,0,0,13,0,6,0,Other 75 + Chick Fil-A,6 Piece Grilled Chicken Nuggets,110,27,3,1,0,50,330,2,0,0,19,0,8,0,Other 76 + Chick Fil-A,8 piece Grilled Chicken Nuggets,140,36,4,1,0,70,440,2,0,0,25,0,10,2,Other 77 + Chick Fil-A,12 Piece Grilled Chicken Nuggets,210,45,5,1,0,100,670,3,0,1,38,0,20,2,Other 78 + Chick Fil-A,Spicy Grilled Chicken Sub Sandwich,430,108,12,4.5,0,85,1310,47,5,9,33,NA,25,25,Other 79 + Chick Fil-A,Regular Grilled Chicken Sub Sandwich,450,117,13,6,0,75,1000,48,4,10,34,NA,50,25,Other 80 + Chick Fil-A,Smokehouse BBQ Bacon Sandwich,500,162,18,0,0,95,1200,46,2,10,33,45,40,20,Other 81 + Chick Fil-A,Spicy Chicken Sandwich,450,171,19,4,0,60,1620,41,1,5,29,4,2,15,Other 82 + Chick Fil-A,Spicy Deluxe,540,225,25,8,0,80,1760,43,2,6,34,30,10,30,Other 83 + Chick Fil-A,Chargrilled Chicken Cool Wrap,350,126,14,5,0,60,960,29,15,3,37,60,35,35,Other 84 + Chick Fil-A,Chicken Enchiladas Meal Kit,860,423,47,16,1,100,2520,70,NA,8,39,NA,NA,NA,Other 85 + Chick Fil-A,Chicken Parmesan Meal Kit,720,279,31,15,0,120,1780,65,NA,7,48,NA,NA,NA,Other 86 + Sonic,Hatch Green Chile Cheeseburger,710,380,43,17,2,120,1120,44,2,7,35,10,25,30,Other 87 + Sonic,Jalapeno Burger,640,330,37,14,2,100,930,42,2,6,31,4,2,20,Other 88 + Sonic,Jr. Burger,340,150,17,6,1,35,640,34,1,6,15,2,4,6,Other 89 + Sonic,Jr. Chili Cheeseburger,410,220,24,9,0.5,55,730,32,1,4,20,7,1,15,Other 90 + Sonic,Jr. Deluxe Burger,380,200,23,6,1,40,470,32,1,4,15,2,4,6,Other 91 + Sonic,Jr. Deluxe Cheeseburger,450,250,28,9,1,60,800,33,1,4,19,6,4,15,Other 92 + Sonic,Jr. Double Cheeseburger,600,350,38,16,2,110,1350,35,1,7,31,15,4,25,Other 93 + Sonic,Sonic Bacon Cheeseburger (w/mayo),870,530,59,20,2,140,1350,45,2,7,39,10,8,30,Other 94 + Sonic,Sonic Burger W/ Mustard,640,330,37,14,2,100,790,43,2,7,31,6,8,20,Other 95 + Sonic,Sonic Burger W/ Ketchup,650,340,37,14,2,100,860,46,2,10,32,8,10,20,Other 96 + Sonic,Sonic Burger W/ Mayonnaise,740,430,48,15,2,110,760,44,2,7,31,6,8,20,Other 97 + Sonic,Sonic Cheeseburger W/ Mustard,710,380,43,17,2,120,1120,43,2,7,35,10,8,30,Other 98 + Sonic,Sonic Cheeseburger W/ Ketchup,720,380,43,17,2,120,1190,47,2,10,35,15,10,30,Other 99 + Sonic,Sonic Cheeseburger W/ Mayonnaise,800,480,54,18,2,130,1090,44,2,7,35,10,8,30,Other 100 + Sonic,Super Sonic Bacon Double Cheeseburger (w/mayo),1280,830,92,36,4,260,1630,44,2,7,67,15,6,40,Other 101 + Sonic,Super Sonic Double Cheeseburger W/ Mustard,1120,680,76,32,4,235,1550,44,2,8,63,15,8,40,Other 102 + Sonic,Super Sonic Double Cheeseburger W/ Ketchup,1130,680,76,32,4,235,1620,47,2,11,63,20,10,40,Other 103 + Sonic,Super Sonic Double Cheeseburger W/ Mayo,1220,780,87,34,4,245,1520,45,2,8,63,15,8,40,Other 104 + Sonic,Super Sonic Jalapeno Double Cheeseburger,1120,680,76,32,4,235,1690,43,2,7,63,15,2,40,Other 105 + Sonic,Veggie Burger W/ Ketchup,450,130,14,4,0,10,1410,67,5,11,15,6,8,25,Other 106 + Sonic,Veggie Burger With Mustard,450,130,14,4,0,10,1350,64,5,8,15,6,8,27,Other 107 + Sonic,Veggie Burger W/ Mustard,450,130,14,4,0,10,1300,64,5,8,15,6,8,25,Other 108 + Sonic,Grilled Asiago Caesar Chicken Club Sandwich,610,270,30,7,0,110,1570,44,3,8,40,11,20,16,Other 109 + Sonic,Crispy Asiago Caesar Chicken Club Sandwich,680,350,39,9,0,80,1120,53,4,7,31,11,7,16,Other 110 + Sonic,Grilled Chicken Sandwich,430,180,20,4,0,80,940,33,2,6,28,6,8,10,Other 111 + Sonic,Crispy Chicken Sandwich,570,300,33,5,0,45,1060,47,4,6,23,6,8,10,Other 112 + Sonic,Chicken Strip Sandwich,450,220,24,4,0,35,740,43,1,4,19,0,0,4,Other 113 + Sonic,3 Piece Crispy Chicken Tender Dinner,280,130,14,2.5,0,0,800,16,0,0,22,NA,NA,NA,Other 114 + Sonic,5 Piece Crispy Chicken Tender Dinner,470,220,24,4.5,0,0,1340,26,0,0,37,NA,NA,NA,Other 115 + Sonic,Deluxe Ultimate Chicken Sandwich,740,350,39,8,0,90,1550,63,4,12,33,10,8,15,Other 116 + Sonic,Buffalo Dunked Ultimate Chicken Sandwich,1000,550,61,12,0.5,125,4520,70,5,12,23,NA,NA,NA,Other 117 + Sonic,Garlic Parmesan Dunked Ultimate Chicken Sandwich,1350,900,100,17,0,190,2180,69,4,10,23,NA,NA,NA,Other 118 + Sonic,Small Jumbo Popcorn Chicken,380,190,22,4,0,45,1250,27,3,1,18,0,0,2,Other 119 + Sonic,Large Jumbo Popcorn Chicken,560,290,32,6,1,65,1890,41,5,2,27,0,0,4,Other 120 + Sonic,Small Spicy Jumbo Popcorn Chicken,350,150,17,3,0,45,860,30,2,0,21,10,0,2,Other 121 + Sonic,Large Spicy Jumbo Popcorn Chicken,610,270,30,5,0,80,1500,51,3,0,36,17,0,3,Other 122 + Sonic,3 Piece Super Crunch Chicken Strip Dinner,970,410,46,8,1,55,2160,109,7,9,30,1,6,13,Other 123 + Sonic,4 Piece Super Crunch Chicken Strip Dinner,1080,460,51,9,1,75,2390,118,8,9,37,1,7,13,Other 124 + Sonic,5 Piece Super Crunch Chicken Strip Dinner,1190,510,57,10,1,90,2610,126,8,9,44,2,8,14,Other 125 + Sonic,3 Piece Super Crunch Chicken Strips,330,140,16,3,0,55,670,25,2,0,22,1,2,1,Other 126 + Sonic,4 Piece Super Crunch Chicken Strips,440,190,21,4,0,70,900,34,2,1,29,1,2,1,Other 127 + Sonic,5 Piece Super Crunch Chicken Strips,550,240,26,5,0,90,1120,42,3,1,36,1,3,2,Other 128 + Sonic,Traditional Ultimate Chicken Sandwich,730,350,39,8,0,90,1540,62,3,11,32,4,2,15,Other 129 + Sonic,Ultimate Chicken Club,100,580,64,15,0.5,100,2070,65,4,12,39,15,8,30,Other 130 + Sonic,"All Beef All-american Style Dog โ€“ 6""",370,160,18,7,0,40,1180,40,1,15,12,2,4,8,Other 131 + Sonic,"All Beef Chicago Dog โ€“ 6""",430,180,20,7,0,40,2310,49,1,17,14,4,6,10,Other 132 + Sonic,"All Beef Chili Cheese Coney โ€“ 6""",410,230,26,11,0,65,1140,30,2,4,17,10,2,20,Other 133 + Sonic,"All Beef New York Dog โ€“ 6""",340,170,19,7,0,40,1250,30,3,4,13,2,10,8,Other 134 + Sonic,"All Beef Regular Hot Dog โ€“ 6""",320,160,18,7,0,40,870,27,1,3,11,0,2,8,Other 135 + Sonic,Cheesy Bacon Pretzel Dog - 6 In.,500,240,26,10,0,50,1410,46,2,7,15,1,3,8,Other 136 + Sonic,Corn Dog,210,100,11,4,0,20,530,23,2,4,6,0,0,4,Other 137 + Sonic,Footlong Quarter Pound Coney,830,490,54,22,1,85,1940,54,3,9,30,15,4,30,Other 138 + Sonic,The Original Pretzel Dog,320,160,18,7,0,35,910,27,1,2,11,0,0,4,Other 139 + Arbys,Arby's Melt,330,100,11,4,0,30,920,40,2,5,18,2,0,8,Other 140 + Arbys,Arby-Q Sandwich,400,90,10,3,0,30,1230,58,3,23,18,4,10,10,Other 141 + Arbys,Beef 'n Cheddar Classic,450,180,20,6,1,50,1280,45,2,9,23,2,2,15,Other 142 + Arbys,Beef 'n Cheddar Mid,630,290,32,11,1.5,100,2100,48,2,9,39,2,2,15,Other 143 + Arbys,Bourbon BBQ Brisket Sandwich,650,300,33,12,1,105,1460,51,2,15,38,NA,NA,NA,Other 144 + Arbys,Bourbon BBQ Chicken Sandwich,690,280,31,9,0,90,1990,66,3,16,38,NA,NA,NA,Other 145 + Arbys,Bourbon BBQ Steak Sandwich,690,280,31,9,0,90,1990,66,3,16,38,NA,NA,NA,Other 146 + Arbys,Buttermilk Buffalo Chicken Sandwich,540,220,24,4.5,0,60,2110,53,2,6,29,NA,NA,NA,Other 147 + Arbys,Buttermilk Chicken Bacon & Swiss,650,280,31,9,0,90,1750,56,2,9,39,NA,NA,NA,Other 148 + Arbys,Buttermilk Chicken Cordon Bleu Sandwich,690,310,35,10,0,110,2000,53,1,7,41,NA,NA,NA,Other 149 + Arbys,Buttermilk Crispy Chicken Sandwich,550,230,26,4.5,0,60,1480,52,2,6,29,NA,NA,NA,Other 150 + Arbys,Classic French Dip & Swiss/Au Jus,540,210,23,11,1,85,2500,50,2,3,35,2,8,15,Other 151 + Arbys,Classic Roast Beef,360,120,14,5,0.5,50,970,37,2,5,23,0,0,6,Other 152 + Arbys,Double Roast Beef,510,210,24,9,1.5,95,1610,38,2,5,38,0,0,6,Other 153 + Arbys,Fire-Roasted Philly Steak,640,290,32,11,0.5,105,1950,46,3,4,42,NA,NA,NA,Other 154 + Arbys,Grand Turkey Club,480,220,24,7,0,65,1610,37,2,9,30,15,10,15,Other 155 + Arbys,Greek Gyro,710,390,44,13,0,75,1360,55,4,6,23,NA,NA,NA,Other 156 + Arbys,Half Pound Beef 'n Cheddar Sandwich,740,350,39,14,2,130,2530,48,2,9,49,NA,NA,NA,Other 157 + Arbys,Half Pound French Dip & Swiss,750,330,36,17,2,150,3350,51,2,3,55,NA,NA,NA,Other 158 + Arbys,Half Pound Roast Beef Sandwich,610,270,30,12,2,130,2040,38,2,5,48,NA,NA,NA,Other 159 + Arbys,Ham & Swiss Melt,300,80,9,4,0,35,1030,37,2,6,18,2,0,15,Other 160 + Arbys,Loaded Italian Sandwich,680,360,40,14,0.5,100,2270,49,3,7,32,NA,NA,NA,Other 161 + Arbys,Pecan Chicken Salad Flatbread,710,410,46,7,0.5,65,980,53,4,9,22,NA,NA,NA,Other 162 + Arbys,Pecan Chicken Salad Sandwich,840,400,44,6,0.5,75,1210,81,6,20,33,10,8,25,Other 163 + Arbys,2 piece Prime-Cut Chicken Tenders,240,100,11,1.5,0,30,640,19,1,0,16,0,0,2,Other 164 + Arbys,3 piece Prime-Cut Chicken Tenders,360,150,17,2.5,0,45,950,28,2,0,23,0,4,2,Other 165 + Arbys,5 piece Prime-Cut Chicken Tenders,600,250,28,4,0,75,1590,47,3,0,39,0,8,2,Other 166 + Arbys,Reuben Sandwich,680,280,31,8,0.5,80,2420,62,4,5,37,6,20,35,Other 167 + Arbys,Roast Beef Gyro,550,260,29,7,1,60,1290,48,3,5,24,10,15,10,Other 168 + Arbys,Roast Turkey & Swiss Sandwich,710,260,28,7,0,65,1930,79,5,15,38,20,10,45,Other 169 + Arbys,Roast Turkey & Swiss Wrap,520,240,27,9,0,65,1640,39,4,6,30,20,10,35,Other 170 + Arbys,"Roast Turkey, Ranch & Bacon Sandwich",800,310,34,10,0.5,80,2420,79,5,16,45,20,10,45,Other 171 + Arbys,"Roast Turkey, Ranch & Bacon Wrap",620,310,34,11,0.5,85,2130,39,4,6,37,20,10,30,Other 172 + Arbys,Smoke Mountain w/ Beef Short Rib,740,320,35,13,1,125,2050,62,4,17,43,NA,NA,NA,Other 173 + Arbys,Smokehouse Beef Short Rib Sandwich,590,250,59,10,1,75,1510,59,4,14,26,NA,NA,NA,Other 174 + Arbys,Smokehouse Brisket,600,310,35,12,1,110,1240,42,2,7,33,4,8,20,Other 175 + Arbys,Super Roast Beef,430,160,17,5,1,45,1060,45,3,11,23,10,10,8,Other 176 + Arbys,Three Cheese Steak Sandwich,650,320,36,15,1,115,1760,44,2,9,30,NA,NA,NA,Other 177 + Arbys,Triple Decker Sandwich,1030,459,51,17,1,155,2940,83,5,19,62,NA,NA,NA,Other 178 + Arbys,Turkey Avocado Club,730,252,28,6,0,65,2140,80,6,16,41,NA,NA,NA,Other 179 + Arbys,Turkey Gyro,470,180,20,3.5,0,45,1520,48,3,5,25,10,15,10,Other 180 + Arbys,Ultimate BLT,980,495,55,14,0,85,2130,80,6,19,43,NA,NA,NA,Other 181 + Arbys,Buffalo Chicken Slider,290,120,13,2,0,20,860,31,2,2,12,NA,NA,NA,Other 182 + Arbys,Chicken Tender 'n Cheese Slider,290,110,12,3.5,0,25,720,30,1,1,15,NA,NA,NA,Other 183 + Arbys,Corned Beef 'n Cheese Slider,220,80,9,3.5,0,30,890,21,1,1,14,NA,NA,NA,Other 184 + Arbys,Ham 'n Cheese Slider,210,70,8,3,0,25,780,21,1,2,13,NA,NA,NA,Other 185 + Arbys,Jalapeno Roast Beef 'n Cheese Slider,240,90,11,4.5,0,30,670,21,1,1,14,NA,NA,NA,Other 186 + Arbys,Pizza Slider,300,150,17,6,0,35,930,23,1,2,13,NA,NA,NA,Other 187 + Arbys,Roast Beef 'n Cheese Slider,240,90,11,4.5,0,30,670,21,1,1,14,NA,NA,NA,Other 188 + Arbys,Turkey 'n Cheese Slider,200,60,7,2.5,0,25,760,21,1,2,14,NA,NA,NA,Other 189 + Arbys,Chopped Side Salad,70,45,5,2.5,0,15,100,4,1,2,5,35,10,10,Other 190 + Arbys,Crispy Chicken Farmhouse Salad,430,220,24,8,0,65,1000,26,4,4,28,60,20,25,Other 191 + Arbys,Greek Gyro Salad,420,340,37,9,0,55,700,11,2,4,10,NA,NA,NA,Other 192 + Arbys,Roast Turkey Farmhouse Salad,230,120,13,7,0,55,870,8,2,5,22,60,20,25,Other 193 + Arbys,Super Greek Salad,720,480,53,15,0,85,1310,39,5,7,22,NA,NA,NA,Other 194 + Burger King,American Brewhouse King,1550,1134,126,47,8,805,1820,21,3,7,134,NA,NA,NA,Other 195 + Burger King,Bacon & Swiss Sourdough King,1000,585,65,24,3,200,1320,48,2,8,56,NA,NA,NA,Other 196 + Burger King,Bacon Cheeseburger,330,140,16,7,0,55,830,32,1,7,18,NA,NA,NA,Other 197 + Burger King,Bacon Cheeseburger Deluxe,290,120,14,6,0.5,40,720,28,1,7,12,NA,NA,NA,Other 198 + Burger King,Bacon King,1040,630,48,28,2.5,220,1900,48,1,10,57,NA,NA,NA,Other 199 + Burger King,Bacon King Jr,730,351,39,9,0,90,1930,63,0,16,32,NA,NA,NA,Other 200 + Burger King,BBQ Bacon King,1100,675,75,29,3,220,1850,51,NA,13,57,NA,NA,NA,Other 201 + Burger King,Cheeseburger,300,130,14,6,0,45,710,28,1,6,16,NA,NA,NA,Other 202 + Burger King,Double Bacon Cheeseburger,520,280,31,14,1,105,1180,33,1,8,31,NA,NA,NA,Other 203 + Burger King,Double Cheeseburger,450,230,26,12,1,95,960,29,1,6,26,NA,NA,NA,Other 204 + Burger King,Double Hamburger,360,160,18,8,0,70,520,28,1,6,22,NA,NA,NA,Other 205 + Burger King,Double Quarter Pound King,900,486,54,25,3,210,1740,50,2,11,56,NA,NA,NA,Other 206 + Burger King,Extra Long Cheeseburger,580,300,33,13,1.5,85,1030,45,2,9,26,NA,NA,NA,Other 207 + Burger King,Farmhouse King,1220,720,80,28,3,335,2050,62,NA,15,NA,NA,NA,NA,Other 208 + Burger King,Hamburger,260,90,10,4,0,35,490,28,1,6,13,NA,NA,NA,Other 209 + Burger King,Homestyle Cheeseburger,550,250,27,12,1.5,95,1140,48,2,10,30,NA,NA,NA,Other 210 + Burger King,Jalapeno King Sandwich,990,585,65,24,3,205,1550,46,2,7,55,NA,NA,NA,Other 211 + Burger King,Mushroom & Swiss King,940,567,63,21,2.5,175,1380,45,NA,8,49,NA,NA,NA,Other 212 + Burger King,Rodeo Burger,310,110,13,4,0.5,25,450,38,1,9,9,NA,NA,NA,Other 213 + Burger King,Rodeo King,1250,738,82,31,3.5,230,2270,69,3,14,60,NA,NA,NA,Other 214 + Burger King,Sourdough King Single,730,387,43,16,1.5,125,1570,52,2,12,35,NA,NA,NA,Other 215 + Burger King,Sourdough King Double,970,549,61,24,3,205,1640,52,2,12,55,NA,NA,NA,Other 216 + Burger King,Steakhouse King,1100,666,74,24,1,180,1620,59,NA,13,50,NA,NA,NA,Other 217 + Burger King,Bacon & Cheese Whopper,770,432,48,16,2,95,1360,47,2,9,29,NA,NA,NA,Other 218 + Burger King,DOUBLE WHOPPER w/o Cheese,900,510,57,19,2,140,1050,51,3,11,47,NA,NA,NA,Other 219 + Burger King,DOUBLE WHOPPER w/ Cheese,990,580,65,24,2,160,1480,53,3,11,52,NA,NA,NA,Other 220 + Burger King,WHOPPER w/o Cheese,660,360,40,12,1.5,90,980,49,2,11,28,NA,NA,NA,Other 221 + Burger King,WHOPPER w/ Cheese,760,430,47,16,1,100,1410,53,3,11,33,NA,NA,NA,Other 222 + Burger King,WHOPPER JR. w/o Cheese,340,170,19,5,0,40,510,28,2,6,14,NA,NA,NA,Other 223 + Burger King,WHOPPER JR. w/ Cheese,380,210,23,8,1,55,730,29,2,6,16,NA,NA,NA,Other 224 + Burger King,Bacon Cheddar Ranch Chicken Salad w/ grilled Chicken & Dressing,590,360,40,12,0,150,1540,18,3,6,42,NA,NA,NA,Other 225 + Burger King,Bacon Cheddar Ranch Chicken Salad w/ crispy Chicken & Dressing,720,450,50,13,0,120,1960,32,5,7,36,NA,NA,NA,Other 226 + Burger King,Chicken BLT Salad w/ Grilled Chicken,550,330,37,10,0,115,1640,17,3,5,36,NA,NA,NA,Other 227 + Burger King,Chicken BLT Salad w/ Crispy Chicken,690,430,48,12,1,100,1750,31,4,8,35,NA,NA,NA,Other 228 + Burger King,Chicken Caesar Salad w/ Grilled Chicken,530,290,32,5,0,95,1640,26,3,6,35,NA,NA,NA,Other 229 + Burger King,Chicken Caesar Salad w/ Crispy Chicken,670,380,43,7,0,80,1760,40,5,8,34,NA,NA,NA,Other 230 + Burger King,"Chicken, Apple & Cranberry Salad w/ Grilled Chicken",560,270,30,7,0,90,980,40,4,34,29,NA,NA,NA,Other 231 + Burger King,"Chicken, Apple & Cranberry Salad w/ Crispy Chicken",700,370,41,9,0,80,1090,54,5,37,28,NA,NA,NA,Other 232 + Burger King,"Garden Grilled Chicken Salad w/ Grilled Chicken, no dressing",320,120,14,6,0,115,650,16,2,4,36,NA,NA,NA,Other 233 + Burger King,"Garden Grilled Chicken Salad w/ Crispy Chicken, no dressing",450,220,24,7,0,85,1070,30,5,6,29,NA,NA,NA,Other 234 + Burger King,Side Caesar Salad with dressing,220,180,20,4,0,10,540,7,2,3,6,NA,NA,NA,Other 235 + Burger King,Side Garden Salad and Avocado Ranch Dressing,230,190,21,5,0,30,520,7,2,3,5,NA,NA,NA,Other 236 + Burger King,Bacon Cheddar Ranch Crispy Chicken Sandwich,830,468,52,14,0.5,110,2100,57,NA,9,34,NA,NA,NA,Other 237 + Burger King,BBQ Bacon Crispy Chicken Sandwich,440,243,27,4.5,0,15,630,44,NA,13,7,NA,NA,NA,Other 238 + Burger King,Big Fish Sandwich,530,250,27,4.5,0,30,1360,54,2,7,17,NA,NA,NA,Other 239 + Burger King,BK VEGGIE Burger,410,150,16,3,0,5,1030,44,7,8,22,NA,NA,NA,Other 240 + Burger King,Chicken Burger,480,220,25,2.5,0,5,1160,42,2,10,22,NA,NA,NA,Other 241 + Burger King,Chicken Cordon Bleu Sandwich,730,351,39,9,0,90,1930,63,NA,16,32,NA,NA,NA,Other 242 + Burger King,Chicken Fries,290,150,17,3,1.5,40,780,18,1,1,16,NA,NA,NA,Other 243 + Burger King,4 Piece Chicken Nuggets,190,100,11,2,0,25,310,10,1,0,10,NA,NA,NA,Other 244 + Burger King,6 Piece Chicken Nuggets,290,150,17,3,0,40,460,15,1,0,15,NA,NA,NA,Other 245 + Burger King,20 Piece Chicken Nuggets,950,500,55,11,0,130,1530,50,5,0,51,NA,NA,NA,Other 246 + Burger King,Chicken Nuggets (10pc),470,260,29,5,0,50,890,34,5,0,21,NA,NA,NA,Other 247 + Burger King,Chicken Parmesan Sandwich,570,225,25,8,0,70,1340,57,NA,9,32,NA,NA,NA,Other 248 + Burger King,Crispy Buffalo Chicken Melt,580,252,28,8,0.5,70,2310,56,NA,8,30,NA,NA,NA,Other 249 + Burger King,Crispy Chicken Jr.,430,250,28,4.5,0,30,760,34,2,4,12,NA,NA,NA,Other 250 + Burger King,Crispy Chicken Sandwich,670,370,41,7,0.5,60,1070,54,2,7,23,NA,NA,NA,Other 251 + Burger King,Grilled Chicken Sandwich,470,170,19,3.5,0,85,850,39,2,6,37,NA,NA,NA,Other 252 + Burger King,Grilled Chili Cheese Dog,330,170,19,8,1,40,980,28,2,5,14,NA,NA,NA,Other 253 + Burger King,Grilled Hot Dog,310,140,16,6,1,30,960,32,2,10,11,NA,NA,NA,Other 254 + Burger King,Jalapeno Chicken Fries,300,160,18,3,0,40,950,19,1,1,15,NA,NA,NA,Other 255 + Burger King,Original Chicken Sandwich,630,350,39,7,1,65,1390,46,3,4,24,NA,NA,NA,Other 256 + Burger King,Pretzel Chicken Fries,340,189,21,3.5,0,45,1200,21,1,1,16,NA,NA,NA,Other 257 + Burger King,Rodeo Crispy Chicken Sandwich,410,150,17,3,0,20,870,53,2,14,12,NA,NA,NA,Other 258 + Burger King,Sourdough Chicken Club,840,459,51,12,1,95,1760,62,3,7,32,NA,NA,NA,Other 259 + Burger King,4 Piece Spicy Chicken Nuggets,210,135,15,3,0,20,570,11,2,0,8,NA,NA,NA,Other 260 + Burger King,Spicy Chicken Nuggets,530,333,37,7,0,55,1420,28,NA,0,20,NA,NA,NA,Other 261 + Burger King,Spicy Crispy Chicken Jr.,410,220,25,4.5,0,35,850,35,2,5,12,NA,NA,NA,Other 262 + Burger King,Spicy Crispy Chicken Sandwich,700,378,42,7,0,65,1140,57,3,8,25,NA,NA,NA,Other 263 + Burger King,Spicy Crispy Jalapeno Chicken Sandwich,760,405,45,11,0,95,1720,58,3,8,32,NA,NA,NA,Other 264 + Dairy Queen,1/2 lb. FlameThrowerยฎ GrillBurger,1000,660,74,26,2,170,1610,40,2,9,46,25,8,30,Other 265 + Dairy Queen,1/2 lb. GrillBurger with Cheese,800,460,51,20,2,135,1280,44,3,13,40,25,6,35,Other 266 + Dairy Queen,1/4 lb. Bacon Cheese GrillBurger,630,330,37,13,1,95,1250,44,2,13,30,20,6,25,Other 267 + Dairy Queen,1/4 lb. GrillBurger with Cheese,540,270,30,11,1,70,1020,44,3,13,23,20,6,25,Other 268 + Dairy Queen,1/4 lb. Mushroom Swiss GrillBurger,570,310,35,11,1,75,820,39,2,8,24,2,0,25,Other 269 + Dairy Queen,Original Cheeseburger,400,160,18,9,1,65,930,34,1,8,19,10,0,10,Other 270 + Dairy Queen,Original Double Cheeseburger,630,310,34,18,2,125,1240,34,1,9,34,15,0,20,Other 271 + Dairy Queen,4 Piece Chicken Strip Basket w/ Country Gravy,1030,480,53,9,1,80,2780,105,9,4,35,2,0,10,Other 272 + Dairy Queen,6 Piece Chicken Strip Basket w/ Country Gravy,1260,590,66,11,1,120,3500,121,12,4,49,2,0,10,Other 273 + Dairy Queen,Bacon Cheese Dog,420,240,26,11,1,60,1140,26,1,3,19,NA,NA,NA,Other 274 + Dairy Queen,Cheese Dog,390,220,24,11,1,50,1000,26,1,3,16,NA,NA,NA,Other 275 + Dairy Queen,Chili Cheese Dog,380,220,24,11,1,55,900,23,1,3,16,10,0,15,Other 276 + Dairy Queen,Chili Dog,330,180,20,8,1,40,1050,24,1,5,13,8,0,6,Other 277 + Dairy Queen,Hot Dog,290,160,17,7,1,35,900,22,1,4,11,4,0,6,Other 278 + Dairy Queen,Relish Dog,350,180,20,8,1,35,1000,30,1,6,13,NA,NA,NA,Other 279 + Dairy Queen,Barbecue Pork Sandwich,310,80,9,3,0,50,830,41,2,9,17,10,4,4,Other 280 + Dairy Queen,Breaded Mushrooms,250,80,9,1,0,0,500,36,2,1,7,0,2,2,Other 281 + Dairy Queen,Regular Cheese Curds,550,410,45,25,0,150,900,0,0,0,35,30,0,100,Other 282 + Dairy Queen,Large Cheese Curds,1050,670,75,43,1,180,2210,52,0,30,43,NA,NA,NA,Other 283 + Dairy Queen,Chili Cheese Mega Dog,760,440,49,21,2,100,1570,48,2,6,32,NA,NA,NA,Other 284 + Dairy Queen,Corn Dog,260,140,15,4,0,20,450,26,1,7,6,0,4,0,Other 285 + Dairy Queen,Crispy Fish Sandwich,470,200,22,3,0,20,1210,53,2,7,17,10,2,6,Other 286 + Dairy Queen,Deluxe Cheeseburger,400,160,18,9,1,65,930,35,1,9,20,20,6,10,Other 287 + Dairy Queen,Deluxe Double Cheeseburger,640,310,34,18,2,125,1240,35,1,9,34,25,6,20,Other 288 + Dairy Queen,Deluxe Double Hamburger,540,240,26,13,1,100,750,34,1,9,29,15,6,4,Other 289 + Dairy Queen,Deluxe Hamburger,350,130,14,7,1,50,680,34,1,9,17,15,6,4,Other 290 + Dairy Queen,DQ Ultimateยฎ Burger,780,430,48,22,2,150,1390,34,1,7,41,20,6,20,Other 291 + Dairy Queen,Pork Tenderloin Sandwich,580,310,34,7,0,45,910,48,2,6,19,NA,NA,NA,Other 292 + Dairy Queen,Steak Finger Basket,910,430,48,13,0.5,45,2210,95,5,2,23,NA,NA,NA,Other 293 + Dairy Queen,3 chicken strips Chicken Strips,350,180,20,3,0,60,960,22,10,0,22,NA,NA,NA,Other 294 + Dairy Queen,Chicken Bacon Ranch Sandwich,500,180,20,8,0,65,1190,45,3,3,33,NA,NA,NA,Other 295 + Dairy Queen,Chicken Mozzarella Sandwich,640,220,25,8,0,60,1530,68,4,3,34,NA,NA,NA,Other 296 + Dairy Queen,Crispy Chicken BLT Salad,520,280,31,10,0,100,1470,25,9,6,37,NA,NA,NA,Other 297 + Dairy Queen,Crispy Chicken Garden Greens Salad,280,120,13,2,0,40,670,24,9,6,17,NA,NA,NA,Other 298 + Dairy Queen,Crispy Chicken Sandwich,600,270,30,5,0,55,1250,59,7,8,24,10,6,15,Other 299 + Dairy Queen,Crispy Chicken Wrap,350,190,21,5,0,35,820,30,2,1,12,10,2,10,Other 300 + Dairy Queen,Grilled Chicken BLT Salad,380,170,19,9,0,100,1540,11,3,6,42,NA,NA,NA,Other 301 + Dairy Queen,Grilled Chicken Garden Greens Salad,150,20,2,0.5,0,40,730,10,3,6,23,NA,NA,NA,Other 302 + Dairy Queen,Grilled Chicken Sandwich,360,140,15,3,0,50,1040,32,1,5,25,10,8,6,Other 303 + Dairy Queen,Grilled Chicken Wrap,280,130,15,4,0,30,800,22,1,1,15,10,4,10,Other 304 + Dairy Queen,Side Salad,20,0,0,0,0,0,15,5,2,3,1,50,30,15,Other 305 + Dairy Queen,Turkey BLT Sandwich,550,240,26,8,0,60,1420,45,3,3,30,NA,NA,NA,Other 306 + Subway,"6"" B.L.T.",320,80,9,4,0,20,680,43,5,6,15,8,8,30,Other 307 + Subway,Footlong B.L.T.,640,160,18,8,0,40,1360,86,10,12,30,16,16,60,Other 308 + Subway,"6"" BBQ Rib Sandwich",430,160,18,6,0,50,590,47,5,8,19,8,20,30,Other 309 + Subway,Footlong BBQ Rib Sandwich,860,320,36,12,0,100,1180,94,10,16,38,16,40,60,Other 310 + Subway,"6"" Big Hot Pastrami",580,310,31,11,0,85,1470,47,5,7,29,10,45,40,Other 311 + Subway,Footlong Big Hot Pastrami,1160,620,62,22,0,170,2940,94,10,14,58,20,90,80,Other 312 + Subway,"6"" Big Philly Cheesesteak",500,150,17,9,1,85,1310,51,6,8,38,15,20,50,Other 313 + Subway,Footlong Big Philly Cheesesteak,1000,300,34,18,2,170,2620,102,12,16,76,30,40,100,Other 314 + Subway,Kids Mini Sub Black Forest Ham,180,20,3,0.5,0,10,450,30,3,5,10,6,15,20,Other 315 + Subway,"6"" Black Forest Ham",290,40,5,1,0,20,830,46,5,8,18,8,20,30,Other 316 + Subway,Footlong Black Forest Ham,580,80,10,2,0,40,1660,92,10,16,36,16,40,60,Other 317 + Subway,"6"" Carved Turkey",330,45,5,1,0,45,890,45,5,7,25,8,20,30,Other 318 + Subway,Footlong Carved Turkey,660,90,10,2,0,90,1780,90,10,14,50,16,40,60,Other 319 + Subway,"6"" Carved Turkey & Bacon w/ Cheese",570,230,26,7,0,70,1600,46,5,8,33,10,20,40,Other 320 + Subway,Footlong Carved Turkey & Bacon w/ Cheese,1140,460,52,14,0,140,3200,92,10,16,66,20,40,80,Other 321 + Subway,"6"" Chicken & Bacon Ranch Melt",570,250,28,10,1,95,1080,47,5,8,35,15,25,50,Other 322 + Subway,Footlong Chicken & Bacon Ranch Melt,1140,500,56,20,2,190,2160,94,10,16,70,30,50,100,Other 323 + Subway,"6"" Chicken Pizziola Melt",460,140,16,6,0,80,1140,49,6,9,32,15,30,45,Other 324 + Subway,Footlong Chicken Pizziola Melt,920,280,32,12,0,160,2280,98,12,18,64,30,60,90,Other 325 + Subway,"6"" Cold Cut Combo",370,120,13,4,0,50,1140,46,5,7,18,10,20,35,Other 326 + Subway,Footlong Cold Cut Combo,740,240,26,8,0,100,2280,92,10,14,36,20,40,70,Other 327 + Subway,"6"" Corned Beef Reuben",470,130,15,4.5,0,85,1770,45,7,12,39,10,35,20,Other 328 + Subway,Footlong Corned Beef Reuben,940,260,30,9,0,170,3540,90,14,24,78,20,70,40,Other 329 + Subway,"6"" Italian B.M.T.",410,150,16,6,0,45,1300,46,5,8,20,8,20,30,Other 330 + Subway,Footlong Italian B.M.T.,820,300,32,12,0,90,2600,92,10,16,40,16,40,60,Other 331 + Subway,"6"" Italian Hero",550,260,29,10,0,75,1470,47,5,9,26,10,20,40,Other 332 + Subway,Footlong Italian Hero,1100,520,58,20,0,150,2940,94,10,18,52,20,40,80,Other 333 + Subway,"6"" Meatball Marinara",480,160,18,7,1,30,950,59,8,12,21,25,35,35,Other 334 + Subway,Footlong Meatball Marinara,960,320,36,14,2,60,1900,118,16,24,42,50,70,70,Other 335 + Subway,"6"" Oven Roasted Chicken",320,40,5,2,0,25,640,47,5,8,23,8,30,30,Other 336 + Subway,Footlong Oven Roasted Chicken,640,80,10,4,0,50,1280,44,10,16,46,16,60,60,Other 337 + Subway,Kids Mini Sub Roast Beef,200,25,3,1,0,25,390,30,4,5,14,6,15,20,Other 338 + Subway,"6"" Roast Beef",320,40,5,2,0,40,700,45,5,7,24,8,20,30,Other 339 + Subway,Footlong Roast Beef,640,80,10,4,0,80,1400,90,10,14,48,16,40,60,Other 340 + Subway,"6"" Rotisserie Style Chicken",350,50,6,1.5,0,50,540,44,5,7,29,8,20,30,Other 341 + Subway,Footlong Rotisserie Style Chicken,700,100,12,3,0,100,1080,88,10,14,58,16,40,60,Other 342 + Subway,"6"" Spicy Italian",480,220,24,9,1,50,1520,46,5,8,20,8,20,30,Other 343 + Subway,Footlong Spicy Italian,960,440,48,18,2,100,3040,92,10,16,40,16,40,60,Other 344 + Subway,"6"" Steak and Cheese",380,90,10,5,0,50,1060,48,5,8,26,10,20,40,Other 345 + Subway,Footlong Steak and Cheese,760,180,20,10,0,100,2120,96,10,16,52,20,40,80,Other 346 + Subway,"6"" Subway Club",310,40,5,2,0,40,880,46,5,7,23,8,20,30,Other 347 + Subway,Footlong Subway Club,620,80,10,4,0,80,1760,92,10,14,46,16,40,60,Other 348 + Subway,"6"" Subway Melt (includes cheese)",370,100,11,5,0,45,1210,47,5,8,23,10,20,40,Other 349 + Subway,Footlong Subway Melt (includes cheese),740,200,22,10,0,90,1420,94,10,16,46,20,40,80,Other 350 + Subway,"6"" Subway Seafood Sensation",420,170,19,3,0,20,690,51,5,8,13,10,20,35,Other 351 + Subway,Footlong Subway Seafood Sensation,840,340,38,6,0,40,1380,102,10,16,26,20,40,70,Other 352 + Subway,"6"" Sweet Onion Chicken Teriyaki",380,40,5,1,0,50,900,59,5,18,26,8,30,35,Other 353 + Subway,Footlong Sweet Onion Chicken Teriyaki,760,80,10,2,0,100,1800,118,10,36,52,16,60,70,Other 354 + Subway,"6"" Tuna",470,210,24,4,0,30,620,44,5,6,20,8,20,30,Other 355 + Subway,Footlong Tuna,940,420,48,8,0,60,1240,88,10,12,40,16,40,60,Other 356 + Subway,"6"" Turkey & Bacon Avocado",390,110,13,3.5,0,30,860,49,8,7,22,10,200,30,Other 357 + Subway,Footlong Turkey & Bacon Avocado,780,220,26,7,0,60,1720,98,16,14,44,20,400,60,Other 358 + Subway,Kids Mini Sub Turkey Breast,180,20,2,0.5,0,10,380,30,3,5,10,6,15,20,Other 359 + Subway,"6"" Turkey Breast",280,30,4,1,0,20,810,46,5,7,18,8,20,30,Other 360 + Subway,Footlong Turkey Breast,560,60,8,2,0,40,1620,92,10,14,36,16,40,60,Other 361 + Subway,"6"" Turkey Breast & Ham",280,35,4,1,0,20,820,46,5,8,18,8,20,30,Other 362 + Subway,Footlong Turkey Breast & Ham,560,70,8,2,0,40,1640,92,10,16,36,16,40,60,Other 363 + Subway,"6"" Turkey Italiano Melt (with Provolone)",490,210,24,9,1,50,1480,47,5,8,24,10,20,45,Other 364 + Subway,Footlong Turkey Italiano Melt (with Provolone),980,420,48,18,2,100,2960,94,10,16,48,20,40,90,Other 365 + Subway,Kids Mini Sub Veggie Delite,150,15,2,0,0,0,190,29,3,4,6,6,15,20,Other 366 + Subway,"6"" Veggie Delite",230,20,3,1,0,0,310,44,5,6,8,8,20,30,Other 367 + Subway,Footlong Veggie Delite,460,40,6,2,0,0,620,88,10,12,16,16,40,60,Other 368 + Subway,"6"" Veggie Patty",390,70,7,1,0,10,800,56,8,8,23,15,20,35,Other 369 + Subway,Footlong Veggie Patty,780,140,14,2,0,20,1600,112,16,16,46,30,20,70,Other 370 + Subway,Autumn Carved Turkey Salad,300,80,9,3,0,60,1120,26,3,22,25,40,40,15,Other 371 + Subway,B.L.T. Salad,150,70,8,4,0,20,420,10,4,5,10,50,50,6,Other 372 + Subway,Big Hot Pastrami Melt Salad,400,300,29,11,0,85,1250,12,4,4,23,25,70,10,Other 373 + Subway,Big Philly Cheesesteak Salad,330,140,16,8,1,85,1080,17,5,6,32,60,50,25,Other 374 + Subway,Black Forest Ham Salad,110,25,3,1,0,20,590,11,4,6,12,25,45,4,Other 375 + Subway,Buffalo Chicken Salad (with Ranch dressing),360,230,26,4,0,60,1100,13,4,6,20,50,60,8,Other 376 + Subway,Carved Turkey & Bacon w/ Cheese Salad,280,110,12,4.5,0,65,1320,11,4,5,28,50,50,15,Other 377 + Subway,Carved Turkey Salad,150,30,4,0,0,45,680,8,3,3,19,40,40,6,Other 378 + Subway,Chicken & Bacon Ranch Melt Salad (includes Ranch dressing),510,340,38,12,1,100,1040,14,4,7,30,60,60,30,Other 379 + Subway,Cold Cut Combo Salad,180,95,11,4,0,45,820,12,4,5,12,50,50,10,Other 380 + Subway,Double Chicken Salad,220,35,5,1.5,0,100,490,10,4,4,36,50,60,8,Other 381 + Subway,Italian B.M.T.ยฎ Salad,230,135,15,6,0,45,1060,12,4,6,14,50,50,6,Other 382 + Subway,Italian Hero Salad,230,140,15,5,0,45,1060,13,4,8,14,40,60,4,Other 383 + Subway,Meatball Marinara Salad,310,150,17,7,1,30,720,25,6,10,16,60,70,10,Other 384 + Subway,Oven Roasted Chicken Salad,140,25,3,0.5,0,50,280,10,4,4,19,50,60,8,Other 385 + Subway,Roast Beef Salad,140,30,4,1,0,40,450,10,4,5,18,25,45,4,Other 386 + Subway,Spicy Italian Salad,310,205,23,9,1,50,1280,11,4,6,15,50,50,8,Other 387 + Subway,Steak & Cheese Salad,210,75,8,4,0,50,830,14,4,6,20,50,50,15,Other 388 + Subway,Subway Club Salad,140,30,4,1,0,40,640,11,4,5,17,25,45,6,Other 389 + Subway,Subway Meltยฎ Salad,200,85,10,5,0,45,910,13,4,6,18,50,50,15,Other 390 + Subway,Sweet Onion Chicken Teriyaki Salad,200,25,3,1,0,50,660,24,4,16,20,25,50,6,Other 391 + Subway,Tuna Salad,310,215,24,4,0,40,370,10,4,4,15,50,50,6,Other 392 + Subway,Turkey Breast & Ham Salad,110,20,3,1,0,25,580,11,4,5,12,25,45,6,Other 393 + Subway,Turkey Breast Salad,110,20,2,1,0,20,570,11,4,5,12,25,45,6,Other 394 + Subway,Veggie Delite Salad,50,10,1,0,0,0,65,9,4,4,3,25,45,4,Other 395 + Subway,Chipotle Southwest Steak & Cheese Wrap,760,330,37,12,1,100,2250,65,4,7,43,15,45,30,Other 396 + Subway,Rotisserie-Style Chicken Caesar Wrap,730,310,34,10,0.5,135,1900,53,3,4,55,15,8,45,Other 397 + Subway,"Turkey, Bacon & Guacamole Wrap",810,380,42,13,0.5,75,2970,62,3,6,43,10,30,30,Other 398 + Subway,Cheese & Veggies Pizza,740,230,25,11,0,50,1270,100,5,9,36,35,30,60,Other 399 + Subway,Cheese Pizza,680,200,22,9,0,40,1070,96,4,7,32,25,4,45,Other 400 + Subway,Pepperoni Pizza,790,290,32,13,0,60,1350,96,4,8,38,30,4,60,Other 401 + Subway,Sausage Pizza,820,310,34,14,0,70,1420,97,4,8,39,30,4,60,Other 402 + Taco Bell,1/2 lb.* Cheesy Potato Burrito,540,230,26,7,1,45,1360,59,7,4,19,NA,NA,NA,Other 403 + Taco Bell,1/2 lb.* Combo Burrito,460,170,18,7,1,45,1320,53,9,3,21,NA,NA,NA,Other 404 + Taco Bell,7-Layer Burrito,510,170,19,7,0,20,1090,68,11,4,16,NA,NA,NA,Other 405 + Taco Bell,Bean Burrito,370,100,11,4,0,5,960,56,9,3,13,NA,NA,NA,Other 406 + Taco Bell,Beefy 5-Layer Burrito,550,200,22,8,0,35,1270,68,8,5,19,NA,NA,NA,Other 407 + Taco Bell,Beefy Fritosยฎ Burrito,440,160,18,5,0,20,1030,55,4,3,13,NA,NA,NA,Other 408 + Taco Bell,Black Bean Burrito,410,110,12,4,0,10,1100,62,8,3,14,NA,NA,NA,Other 409 + Taco Bell,Burrito Supremeยฎ โ€“ Beef,420,140,16,7,0,35,1090,53,8,5,16,NA,NA,NA,Other 410 + Taco Bell,Burrito Supremeยฎ - Chicken,390,110,12,5,0,40,1050,52,7,5,19,NA,NA,NA,Other 411 + Taco Bell,Burrito Supremeยฎ - Steak,390,120,13,5,0,30,1090,52,7,5,17,NA,NA,NA,Other 412 + Taco Bell,Cantina Power Burrito - Chicken,760,240,27,6,0,60,1960,96,12,7,32,NA,NA,NA,Other 413 + Taco Bell,Cantina Power Burrito - Steak,780,250,28,7,0,50,1900,98,13,7,33,NA,NA,NA,Other 414 + Taco Bell,Cantina Power Burrito - Veggie,740,230,26,5,0,10,1750,107,17,8,20,NA,NA,NA,Other 415 + Taco Bell,Cheesy Bean and Rice Burrito,420,160,17,3.5,0,0,930,55,6,4,11,NA,NA,NA,Other 416 + Taco Bell,Chili Cheese Burrito,380,150,17,8,1,35,930,41,5,2,16,NA,NA,NA,Other 417 + Taco Bell,Chicken Crunchy Cheesy Core Burrito,610,210,24,9,0,55,1510,74,5,5,25,10,4,35,Other 418 + Taco Bell,Steak Crunchy Cheesy Core Burrito,610,220,24,9,0,50,1520,75,5,5,25,10,4,40,Other 419 + Taco Bell,Beef Crunchy Cheesy Core Burrito,630,240,26,10,0.5,45,1530,76,7,5,22,15,4,35,Other 420 + Taco Bell,Loaded Taco Burrito,550,260,29,9,0.5,50,1130,52,7,4,20,15,6,20,Other 421 + Taco Bell,Chicken Quesarito,620,270,30,10,0,60,1440,64,4,4,24,NA,NA,NA,Other 422 + Taco Bell,Steak Quesarito,630,280,31,11,0.5,65,1410,64,3,4,25,NA,NA,NA,Other 423 + Taco Bell,Beef Quesarito,650,300,34,12,0.5,60,1450,65,6,5,22,NA,NA,NA,Other 424 + Taco Bell,Shredded Chicken Burrito,400,160,18,4.5,0,30,960,45,3,3,16,NA,NA,NA,Other 425 + Taco Bell,Smothered Burrito - Beef,710,320,35,13,1,75,2260,70,10,4,28,NA,NA,NA,Other 426 + Taco Bell,Smothered Burrito - Shredded Chicken,650,250,28,10,0,70,2230,67,8,4,34,NA,NA,NA,Other 427 + Taco Bell,Smothered Burrito - Steak,670,260,29,11,0.5,80,2080,68,7,4,35,NA,NA,NA,Other 428 + Taco Bell,Chicken Spicy Cheesy Core Burrito,540,180,20,8,0,55,1740,66,5,5,24,15,8,35,Other 429 + Taco Bell,Steak Spicy Cheesy Core Burrito,550,190,21,9,0,50,1750,66,5,5,24,10,6,35,Other 430 + Taco Bell,Beef Spicy Cheesy Core Burrito,570,210,23,10,0.5,45,1760,68,7,5,22,15,6,35,Other 431 + Taco Bell,Triple Melt Burrito,410,140,16,6,0,30,1030,50,4,3,15,6,2,20,Other 432 + Taco Bell,XXL Grilled Stuft Burrito - Beef,880,380,42,14,1,75,2020,94,12,6,31,NA,NA,NA,Other 433 + Taco Bell,XXL Grilled Stuft Burrito - Chicken,830,320,35,11,0,85,1940,91,10,6,37,NA,NA,NA,Other 434 + Taco Bell,XXL Grilled Stuft Burrito - Steak,820,320,36,12,1,70,2020,91,10,7,33,NA,NA,NA,Other 435 + Taco Bell,Chicken Soft Taco,170,50,6,3,0,30,460,18,1,1,12,NA,NA,NA,Other 436 + Taco Bell,Cool Ranchยฎ Doritosยฎ Double Deckerยฎ Taco,320,120,14,5,0,25,770,36,6,2,13,NA,NA,NA,Other 437 + Taco Bell,Cool Ranchยฎ Doritosยฎ Locos Taco,160,90,10,3.5,0,25,350,13,2,1,8,NA,NA,NA,Other 438 + Taco Bell,Cool Ranchยฎ Doritosยฎ Locos Taco Supreme,200,100,12,4.5,0,35,370,15,3,3,9,NA,NA,NA,Other 439 + Taco Bell,Crunchy Taco,170,90,10,4,0,25,290,12,3,1,8,NA,NA,NA,Other 440 + Taco Bell,Crunchy Taco Supremeยฎ,200,110,12,5,0,35,320,15,3,2,9,NA,NA,NA,Other 441 + Taco Bell,Double Deckerยฎ Taco,320,120,14,5,0,25,640,37,7,2,13,NA,NA,NA,Other 442 + Taco Bell,DOUBLE DECKERยฎ Taco Supremeยฎ,350,140,16,6,0,35,670,40,7,3,14,NA,NA,NA,Other 443 + Taco Bell,Spicy Sweet Double Stacked Taco,340,160,18,7,0,35,640,32,4,6,12,10,2,15,Other 444 + Taco Bell,Cool Ranch Habanero Double Stacked Taco,350,180,20,8,0.5,40,630,30,4,3,13,15,2,20,Other 445 + Taco Bell,Nacho Crunch Double Stacked Taco,380,170,19,6,0,35,650,39,5,2,13,8,2,20,Other 446 + Taco Bell,Fiery Doritosยฎ Double Deckerยฎ Taco,320,120,13,5,0,25,770,36,7,2,14,NA,NA,NA,Other 447 + Taco Bell,Fiery Doritosยฎ Locos Taco,170,90,10,3.5,0,25,370,12,3,1,8,NA,NA,NA,Other 448 + Taco Bell,Fiery Doritosยฎ Locos Taco Supreme,200,110,12,5,0,30,390,15,3,2,9,NA,NA,NA,Other 449 + Taco Bell,Grilled Steak Soft Taco,250,130,14,4,0,30,550,19,2,2,11,NA,NA,NA,Other 450 + Taco Bell,Nacho Cheese Doritosยฎ Double Deckerยฎ Taco,320,120,13,5,0,25,760,36,7,2,14,NA,NA,NA,Other 451 + Taco Bell,Nacho Cheese Doritosยฎ Locos Tacos,170,80,9,4,0,25,340,13,2,1,8,NA,NA,NA,Other 452 + Taco Bell,Nacho Cheese Doritosยฎ Locos Tacos Supreme,200,100,11,5,0,35,370,15,3,2,9,NA,NA,NA,Other 453 + Taco Bell,Soft Taco Supremeยฎ โ€“ Beef,230,100,11,5,0,35,530,22,3,3,10,NA,NA,NA,Other 454 + Taco Bell,Soft Taco-Beef,200,80,9,4,0,25,510,19,3,1,10,NA,NA,NA,Other 455 + Taco Bell,Spicy Potato Soft Taco,250,120,13,3,0,10,510,28,3,1,6,NA,NA,NA,Other 456 + Taco Bell,Chalupa Supremeยฎ - Chicken,340,160,18,4,0,40,530,29,3,4,16,NA,NA,NA,Other 457 + Taco Bell,Chalupa Supremeยฎ - Steak,340,170,18,4,0,30,570,29,3,4,14,NA,NA,NA,Other 458 + Taco Bell,Chalupa Supremeยฎโ€“Beef,370,190,21,5,0,30,570,31,4,4,13,NA,NA,NA,Other 459 + Taco Bell,Double Chalupa,600,310,35,8,0.5,50,1010,50,6,5,21,15,4,15,Other 460 + Taco Bell,Wild Naked Chicken Chalupa,420,250,28,6,0,65,1070,23,4,2,19,6,4,6,Other 461 + Taco Bell,Mild Naked Chicken Chalupa,440,270,30,7,0,70,1090,22,3,1,20,6,4,6,Other 462 + Taco Bell,Spicy Double Chalupa,600,310,35,8,0.5,50,1240,52,7,5,21,15,8,15,Other 463 + Taco Bell,Fresco Bean Burrito,350,80,9,3,0,0,950,57,9,3,11,NA,NA,NA,Other 464 + Taco Bell,Fresco Burrito Supremeยฎ โ€“ Chicken,340,80,8,3,0,25,1020,50,7,4,17,NA,NA,NA,Other 465 + Taco Bell,Fresco Burrito Supremeยฎ โ€“ Steak,340,80,9,3,0,15,1060,50,7,4,15,NA,NA,NA,Other 466 + Taco Bell,Fresco Chicken Soft Taco,150,35,4,1,0,25,460,18,2,2,11,NA,NA,NA,Other 467 + Taco Bell,Fresco Crunchy Taco,140,70,8,2,0,20,290,13,3,1,6,NA,NA,NA,Other 468 + Taco Bell,Fresco Grilled Steak Soft Taco,150,35,4,2,0,15,500,19,2,2,9,NA,NA,NA,Other 469 + Taco Bell,Fresco Soft Taco,170,60,7,3,0,20,500,20,3,2,8,NA,NA,NA,Other 470 + Taco Bell,Cheesy Gordita Crunch,490,260,29,10,1,55,810,39,5,6,20,NA,NA,NA,Other 471 + Taco Bell,Doritosยฎ Cheesy Gordita Crunch - Cool Ranch,490,250,28,10,1,55,890,40,5,5,20,NA,NA,NA,Other 472 + Taco Bell,Doritosยฎ Cheesy Gordita Crunch - Fiery,490,250,28,10,1,55,890,40,5,4,20,NA,NA,NA,Other 473 + Taco Bell,Doritosยฎ Cheesy Gordita Crunch - Nacho Cheese,490,250,28,10,1,55,880,40,5,5,20,NA,NA,NA,Other 474 + Taco Bell,Double Cheesy Gordita Crunch,570,290,32,12,1,70,1110,44,7,5,25,15,2,30,Other 475 + Taco Bell,Gordita Supremeยฎ โ€“ Beef,300,120,14,5,0,30,550,31,4,6,13,NA,NA,NA,Other 476 + Taco Bell,Gordita Supremeยฎ - Chicken,270,90,10,4,0,40,510,29,2,6,16,NA,NA,NA,Other 477 + Taco Bell,Gordita Supremeยฎ - Steak,270,90,11,4,0,30,550,29,2,6,14,NA,NA,NA,Other 478 + Taco Bell,Nacho Fries Bellgrande,710,360,41,6,0,30,1420,73,10,4,13,10,4,8,Other 479 + Taco Bell,Nachos BellGrandeยฎ,760,360,39,6,0,30,1100,82,13,5,18,NA,NA,NA,Other 480 + Taco Bell,Nachos Supreme,430,210,23,5,0,30,690,44,7,3,12,NA,NA,NA,Other 481 + Taco Bell,Triple Layer Nachos,320,140,15,1.5,0,0,600,41,6,2,7,NA,NA,NA,Other 482 + Taco Bell,Triple Melt Nachos,260,140,16,4.5,0,30,550,19,3,1,10,6,0,10,Other 483 + Taco Bell,Beefy Cheddar Crunchwrap Slider,410,170,19,6,0,25,960,46,4,3,14,NA,NA,NA,Other 484 + Taco Bell,Beefy Mini Quesadilla,210,110,12,4,0,25,560,17,3,1,9,NA,NA,NA,Other 485 + Taco Bell,Beefy Nacho Griller,420,170,19,4.5,0,20,870,49,5,3,12,NA,NA,NA,Other 486 + Taco Bell,BLT Crunchwrap Slider,430,210,23,5,0,20,900,43,3,4,12,NA,NA,NA,Other 487 + Taco Bell,Cantina Power Bowl - Chicken,560,200,22,4,0,60,1520,64,9,4,26,NA,NA,NA,Other 488 + Taco Bell,Cantina Power Bowl - Steak,580,210,23,4,0,50,1460,66,10,4,27,NA,NA,NA,Other 489 + Taco Bell,Cantina Power Bowl - Veggie,540,190,21,3,0,10,1310,75,14,4,14,NA,NA,NA,Other 490 + Taco Bell,Cheese Quesadilla,480,240,27,11,1,50,1000,40,4,3,19,NA,NA,NA,Other 491 + Taco Bell,Cheese Roll-Up,190,80,9,5,0,20,450,18,2,1,9,NA,NA,NA,Other 492 + Taco Bell,Chicken Quesadilla,520,250,28,12,1,75,1210,41,4,3,27,NA,NA,NA,Other 493 + Taco Bell,Chickstar,620,340,37,8,0,50,1290,53,4,4,17,8,6,15,Other 494 + Taco Bell,Chili Cheese Burrito,380,150,17,8,1,35,930,41,5,2,16,NA,NA,NA,Other 495 + Taco Bell,Chipotle Crispy Chicken Griller,290,170,18,3,0,25,640,22,1,1,9,NA,NA,NA,Other 496 + Taco Bell,Crispy Chicken Quesadilla,650,340,37,13,0.5,75,1480,51,5,3,26,10,2,45,Other 497 + Taco Bell,Crunchwrap Supremeยฎ,540,190,21,6,0,30,1110,71,7,7,16,NA,NA,NA,Other 498 + Taco Bell,Double Tostada,270,100,11,4,0,15,650,32,8,2,12,NA,NA,NA,Other 499 + Taco Bell,Express Taco Salad w/ Chips,580,260,29,9,1,60,1270,59,8,7,23,NA,NA,NA,Other 500 + Taco Bell,Loaded Potato Griller,470,200,22,6,0,25,1120,55,4,5,13,NA,NA,NA,Other 501 + Taco Bell,Mexican Pizza,540,270,31,8,1,40,860,47,7,2,20,NA,NA,NA,Other 502 + Taco Bell,MexiMeltยฎ,270,130,14,7,1,40,740,21,3,2,14,NA,NA,NA,Other 503 + Taco Bell,Steak Quesalupa,440,210,23,10,0.5,60,840,36,3,3,22,15,6,35,Other 504 + Taco Bell,Chicken Quesalupa,440,200,23,10,0.5,60,840,37,3,3,22,15,8,35,Other 505 + Taco Bell,Beef Quesalupa,460,240,26,11,1,50,890,38,4,3,19,15,6,35,Other 506 + Taco Bell,Shredded Chicken Mini Quesadilla,180,70,8,2.5,0,25,540,15,2,1,12,NA,NA,NA,Other 507 + Taco Bell,Spicy Chicken Crunchwrap Slider,400,180,20,4,0,25,900,42,3,3,15,NA,NA,NA,Other 508 + Taco Bell,Spicy Tostada,200,90,10,2.5,0,10,440,22,4,1,7,NA,NA,NA,Other 509 + Taco Bell,Stacker,390,170,18,8,0.5,40,1050,39,4,3,18,8,2,30,Other 510 + Taco Bell,Steak Quesadilla,520,250,28,12,1,65,1250,41,4,3,25,NA,NA,NA,Other 511 + Taco Bell,Original Triple Double Crunchwrap,700,270,30,9,0.5,45,1550,85,9,7,23,15,6,25,Other 512 + Taco Bell,Spicy Triple Double Crunchwrap,780,340,38,10,0.5,50,1850,87,9,8,23,20,10,25,Other 513 + Taco Bell,Express Taco Salad w/ Chips,580,260,29,9,1,60,1270,59,8,7,23,NA,NA,NA,Other 514 + Taco Bell,Fiesta Taco Salad-Beef,780,380,42,10,1,60,1340,74,11,7,26,NA,NA,NA,Other 515 + Taco Bell,Fiesta Taco Salad-Chicken,720,320,35,7,0,70,1260,70,8,8,32,NA,NA,NA,Other 516 + Taco Bell,Fiesta Taco Salad-Steak,720,320,36,8,1,55,1340,70,8,8,28,NA,NA,NA,Other
+52
python/oct15/fast-food-nutrition/main.py
··· 1 + import pandas as pd 2 + import matplotlib.pyplot as plt 3 + import seaborn as sns 4 + 5 + def loadFastFoodDatabase(): 6 + df = pd.read_csv('fast-food-nutrition/fastfood.csv') 7 + return df 8 + 9 + def highest_cal_item(df: pd.DataFrame) -> tuple[str, int, str]: 10 + cals = df["calories"].astype(int) 11 + item = df.iloc[cals.argmax()] 12 + return (item["item"], item["calories"], item["restaurant"]) 13 + 14 + def cal_fat_correlation(df: pd.DataFrame) -> float: 15 + corr = df["calories"].corr(df["total_fat"]) 16 + return corr 17 + 18 + def scatter_plot(df: pd.DataFrame) -> None: 19 + sns.scatterplot(x=df["calories"], y=df["total_fat"]) 20 + plt.show() 21 + pass 22 + 23 + def high_rest_avg(df: pd.DataFrame) -> tuple[str, float]: 24 + avgs: list[tuple[str, float]] = [] 25 + for restaurant in df["restaurant"].unique(): 26 + items = df[df["restaurant"] == restaurant] 27 + avg = items["calories"].astype(int).sum()/len(items) 28 + avgs.append((restaurant, avg)) 29 + highest = avgs[0] 30 + for (r, avg) in avgs[1:]: 31 + if avg > highest[1]: 32 + highest = (r, avg) 33 + return highest 34 + 35 + def percent_500(df: pd.DataFrame) -> float: 36 + sodium = df["sodium"] 37 + df = df.assign(above_500=sodium > 500) 38 + # df["above_500"].value_counts().plot.pie(labels=["Above 500mg", "Below 500mg"]) 39 + # plt.show() 40 + return len(df[df["above_500"]])/len(sodium) 41 + 42 + print("Running test cases...", end="") 43 + try: 44 + df = loadFastFoodDatabase() 45 + assert(highest_cal_item(df) == ("20 piece Buttermilk Crispy Chicken Tenders", 2430, "Mcdonalds")) # Q1 46 + assert(cal_fat_correlation(df) == 0.9004936961298484) # Q2. This means that fats highly contribute to calorie count 47 + # scatter_plot(df) # Q3 48 + assert(high_rest_avg(df) == ("Mcdonalds", 640.3508771929825)) # Q4 49 + assert(percent_500(df) == 0.9145631067961165) # Q5 50 + print("Passed!") 51 + except: 52 + print("Failed :(")
python/oct15/sunrise-sunset/Figure_1.png

This is a binary file and will not be displayed.

python/oct15/sunrise-sunset/Figure_2.png

This is a binary file and will not be displayed.

+72
python/oct15/sunrise-sunset/main.py
··· 1 + import pandas as pd 2 + import requests 3 + from geopy.geocoders import Nominatim 4 + from geopy.location import Location 5 + import datetime 6 + import seaborn as sns 7 + import matplotlib.pyplot as plt 8 + 9 + def sunrise_time(location_name: str, date: str|None|tuple[str,str] = None) -> list[dict[str, str]]: 10 + nominatim = Nominatim(user_agent="CMU_Bootcamp") 11 + geo: Location | None = nominatim.geocode(location_name) 12 + if not geo: 13 + raise KeyError("Location not found") 14 + params = { 15 + "lng": geo.longitude, 16 + "lat": geo.latitude 17 + } 18 + 19 + if isinstance(date, tuple): 20 + params["date_start"] = date[0], 21 + params["date_end"] = date[1] 22 + else: 23 + params["date"] = date if date else "today" 24 + 25 + out = requests.get( 26 + "https://api.sunrisesunset.io/json", 27 + params 28 + ) 29 + j = out.json()['results'] 30 + res = j if isinstance(j, list) else [j] 31 + return [{ 32 + "sunrise": r["sunrise"], 33 + "sunset": r["sunset"], 34 + "date": r["date"] 35 + } for r in res] 36 + 37 + def dayLength(sunrise: str, sunset: str) -> float: 38 + sr = datetime.datetime.strptime(sunrise, "%I:%M:%S %p") 39 + ss = datetime.datetime.strptime(sunset, "%I:%M:%S %p") 40 + srhr = round(sr.hour + sr.minute/60, 1) 41 + sshr = round(ss.hour + ss.minute/60, 1) 42 + length = sshr - srhr 43 + return round(length, 1) 44 + 45 + location = "5000 Forbes Ave, Pittsburgh" 46 + print("Running checks...") 47 + try: 48 + compare_date = "2024-08-02" 49 + a = sunrise_time("Juneau, Alaska", compare_date) 50 + b = sunrise_time("Miami, Florida", compare_date) 51 + print(f"Juneau, Alaska {a[0]["sunrise"]}\nMiami, Florida {b[0]["sunrise"]}") 52 + df = pd.DataFrame(sunrise_time("Seattle, Washington", ("2023-01-01", "2023-12-31"))) 53 + print(f"Latest: {df["sunrise"].max()} | Earliest: {df["sunrise"].min()}") 54 + df = df.assign(dayLengthInHours=df.apply(lambda row: dayLength(row["sunrise"], row["sunset"]), axis=1)) 55 + print(f"Longest: {df["dayLengthInHours"].max()} | Shortest: {df['dayLengthInHours'].min()}") 56 + # ax = sns.lineplot(data=df["dayLengthInHours"]) 57 + # ax.set(xlabel="", ylabel="", xticklabels=[]) 58 + # plt.show() 59 + df = df.assign(month=df.apply(lambda row: datetime.datetime.strptime(row["date"], "%Y-%m-%d").strftime("%B"), axis=1)) 60 + print(df) 61 + avgs: dict[str, float] = {} 62 + for month in df["month"].unique(): 63 + this_month = pd.DataFrame(df[df["month"] == month]) 64 + total = this_month["dayLengthInHours"].astype(float).sum() 65 + avg = round(total / len(this_month), 1) 66 + avgs[month] = avg 67 + # ax = sns.barplot(data=avgs) 68 + # ax.tick_params(axis="x", rotation=45) 69 + # plt.show() 70 + print("Passed!") 71 + except: 72 + print("Failed :(")
+245
python/oct15/tic-tac-toe/main.py
··· 1 + # Tic-Tac-Toe 2 + # by David Kosbie 3 + 4 + # This implements a basic game of TicTacToe. 5 + 6 + # This version does not save or load the game (that is left for you to do!) 7 + 8 + import json 9 + from cmu_graphics import * 10 + import math 11 + import os 12 + 13 + def onAppStart(app): 14 + # Set the model values (in the app object) that never change. 15 + app.rows = 3 16 + app.cols = 3 17 + app.boardBounds = (50, 75, 350, 375) # left, top, right, bottom 18 + app.cellBorderWidth = 2 19 + resetApp(app) 20 + 21 + def resetApp(app): 22 + app.selection = None 23 + app.board = [[None]*app.cols for row in range(app.rows)] 24 + app.turn = 'X' 25 + app.message = "X's turn" 26 + app.turnCount = 0 27 + app.gameOver = False 28 + app.winningCells = None 29 + 30 + def saveGame(app): 31 + with open("savedGame.txt", "w") as f: 32 + json.dump({ 33 + "board": app.board, 34 + "turn": app.turn, 35 + "gameOver": app.gameOver, 36 + "winningCells": app.winningCells 37 + }, f) 38 + 39 + def loadGame(app): 40 + with open("savedGame.txt", "r") as f: 41 + game = json.load(f) 42 + app.selection = None 43 + app.board = game["board"] 44 + app.turn = game["turn"] 45 + app.message = f"{app.turn}'s turn" 46 + flat_list = [] 47 + for r in app.board: 48 + for c in r: 49 + if c != None: 50 + flat_list.append(1) 51 + app.turn_count = sum(flat_list) 52 + app.gameOver = game["gameOver"] 53 + app.winningCells = game["winningCells"] 54 + 55 + 56 + def onKeyPress(app, key): 57 + if key == 's': 58 + saveGame(app) 59 + elif key == 'l': 60 + loadGame(app) 61 + elif (app.gameOver) and (key == 'r'): 62 + resetApp(app) 63 + 64 + def onMousePress(app, mouseX, mouseY): 65 + # Always clear the selection on any mouse press. 66 + app.selection = None 67 + # Then, make the move, but only if the game is not over, and the move is legal 68 + # (that is, it's in an empty cell). 69 + if not app.gameOver: 70 + cell = getCell(app, mouseX, mouseY) 71 + if cell != None: 72 + row, col = cell 73 + if app.board[row][col] == None: 74 + makeMove(app, row, col) 75 + 76 + def onMouseMove(app, mouseX, mouseY): 77 + if app.gameOver: 78 + return 79 + # Set the cell selection as the mouse is moved, but only 80 + # if there is a selected cell, and that cell on the board is empty. 81 + # Otherwise, clear the cell selection. 82 + selectedCell = getCell(app, mouseX, mouseY) 83 + if selectedCell == None: 84 + app.selection = None 85 + else: 86 + row, col = selectedCell 87 + if app.board[row][col] == None: 88 + app.selection = selectedCell 89 + else: 90 + app.selection = None 91 + 92 + def makeMove(app, row, col): 93 + # We already know that this is a legal move, so set the board 94 + # to the current player, add one to the turn count, check if the 95 + # game is over, and if not, change turns. 96 + app.board[row][col] = app.turn 97 + app.turnCount += 1 98 + checkForGameOver(app) 99 + if not app.gameOver: 100 + changeTurns(app) 101 + 102 + def checkForGameOver(app): 103 + # Check if the game is over (tie or win), and if so, set app.gameOver to 104 + # True and set the app.message as appropriate. 105 + # First check for a tie game. If it is, set 106 + if app.turnCount == app.rows * app.cols: 107 + app.gameOver = True 108 + app.message = 'Tie game!' 109 + # It's not a tie game, so check if there are 3 in a row on the board, 110 + # in a search that is similar to wordSearch: 111 + else: 112 + directions = [ (0, 1), # right 113 + (1, 0), # down 114 + (1, 1), # right-down diagonal 115 + (1, -1) # right-up diagonal 116 + ] 117 + for startRow in range(app.rows): 118 + for startCol in range(app.cols): 119 + for drow,dcol in directions: 120 + winner = checkForWin(app, startRow, startCol, drow, dcol) 121 + if winner != None: 122 + app.gameOver = True 123 + app.message = f'{winner} wins!' 124 + return 125 + 126 + def checkForWin(app, startRow, startCol, drow, dcol): 127 + # Check for a winner (3 in a row) starting from (startRow, startCol) and 128 + # heading in the direction (drow, dcol). Return the winner if there 129 + # is one, otherwise None. Also, so that we can draw the line through 130 + # the winning 3-in-a-row run, store the winning cells in the order 131 + # they appear in app.winningCells. 132 + player = app.board[startRow][startCol] 133 + if player == None: 134 + return None 135 + winLength = 3 136 + winningCells = [ ] 137 + for i in range(winLength): 138 + row = startRow + i * drow 139 + col = startCol + i * dcol 140 + if ((row < 0) or (row >= app.rows) or 141 + (col < 0) or (col >= app.cols)): 142 + # we went off the board 143 + return None 144 + if app.board[row][col] != player: 145 + return None 146 + winningCells.append((row, col)) 147 + app.winningCells = winningCells 148 + return player 149 + 150 + def changeTurns(app): 151 + # Change the turn from 'X' to 'O' or 'O' to 'X', 152 + # and set the app.message as appropriate. 153 + app.turn = 'O' if (app.turn == 'X') else 'X' 154 + app.message = f"{app.turn}'s turn" 155 + 156 + def redrawAll(app): 157 + drawLabel('Tic-Tac-Toe', 200, 20, size=16, bold=True) 158 + drawLabel('Press s to save game, l to load game', 200, 40, size=14) 159 + drawAppMessage(app) 160 + drawBoard(app) 161 + drawWinningLine(app) 162 + 163 + def drawAppMessage(app): 164 + # Draw the app.message, and if the game is over, make the message red 165 + # and add a note to press r to restart. 166 + if app.gameOver: 167 + message = app.message + ' (press r to restart)' 168 + color = 'red' 169 + else: 170 + message = app.message 171 + color = 'black' 172 + drawLabel(message, 200, 60, size=14, fill=color) 173 + 174 + def drawBoard(app): 175 + # first draw each cell (with single-thickness): 176 + for row in range(app.rows): 177 + for col in range(app.cols): 178 + drawCell(app, row, col) 179 + # then draw the board outline (with double-thickness): 180 + x0, y0, x1, y1 = app.boardBounds 181 + drawRect(x0, y0, x1-x0, y1-y0, 182 + fill=None, border='black', 183 + borderWidth=2*app.cellBorderWidth) 184 + 185 + def drawCell(app, row, col): 186 + x0, y0, x1, y1 = getCellBounds(app, row, col) 187 + color = 'cyan' if (row, col) == app.selection else None 188 + drawRect(x0, y0, x1-x0, y1-y0, 189 + fill=color, border='black', borderWidth=app.cellBorderWidth) 190 + label = app.board[row][col] 191 + if label != None: 192 + cx = x0 + (x1 - x0)/2 193 + cy = y0 + (y1 - y0)/2 194 + drawLabel(label, cx, cy, size=24, bold=True) 195 + 196 + def drawWinningLine(app): 197 + # If there is a winner, then app.winningCells will contain the 198 + # cells in order, so draw a line from the center of the first cell 199 + # to the center of the last cell. 200 + if app.winningCells != None: 201 + cx0, cy0 = getCellCenter(app, app.winningCells[0]) 202 + cx1, cy1 = getCellCenter(app, app.winningCells[-1]) 203 + drawLine(cx0, cy0, cx1, cy1) 204 + 205 + def getCellCenter(app, cell): 206 + # Return the center of the given cell, a (row, col) tuple. 207 + row, col = cell 208 + x0, y0, x1, y1 = getCellBounds(app, row, col) 209 + cx = (x0 + x1) / 2 210 + cy = (y0 + y1) / 2 211 + return cx, cy 212 + 213 + def getCellBounds(app, row, col): 214 + boardX0, boardY0, boardX1, boardY1 = app.boardBounds 215 + cellWidth, cellHeight = getCellSize(app) 216 + x0 = boardX0 + col * cellWidth 217 + y0 = boardY0 + row * cellHeight 218 + x1 = x0 + cellWidth 219 + y1 = y0 + cellHeight 220 + return (x0, y0, x1, y1) 221 + 222 + def getCellSize(app): 223 + boardX0, boardY0, boardX1, boardY1 = app.boardBounds 224 + boardWidth = boardX1 - boardX0 225 + boardHeight = boardY1 - boardY0 226 + cellWidth = boardWidth / app.cols 227 + cellHeight = boardHeight / app.rows 228 + return (cellWidth, cellHeight) 229 + 230 + def getCell(app, x, y): 231 + boardX0, boardY0, boardX1, boardY1 = app.boardBounds 232 + dx = x - boardX0 233 + dy = y - boardY0 234 + cellWidth, cellHeight = getCellSize(app) 235 + row = math.floor(dy / cellHeight) 236 + col = math.floor(dx / cellWidth) 237 + if (0 <= row < app.rows) and (0 <= col < app.cols): 238 + return (row, col) 239 + else: 240 + return None 241 + 242 + def main(): 243 + runApp() 244 + 245 + main()
+24
react/.gitignore
··· 1 + # Logs 2 + logs 3 + *.log 4 + npm-debug.log* 5 + yarn-debug.log* 6 + yarn-error.log* 7 + pnpm-debug.log* 8 + lerna-debug.log* 9 + 10 + node_modules 11 + dist 12 + dist-ssr 13 + *.local 14 + 15 + # Editor directories and files 16 + .vscode/* 17 + !.vscode/extensions.json 18 + .idea 19 + .DS_Store 20 + *.suo 21 + *.ntvs* 22 + *.njsproj 23 + *.sln 24 + *.sw?
+75
react/README.md
··· 1 + # React + TypeScript + Vite 2 + 3 + This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. 4 + 5 + Currently, two official plugins are available: 6 + 7 + - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh 8 + - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh 9 + 10 + ## React Compiler 11 + 12 + The React Compiler is enabled on this template. See [this documentation](https://react.dev/learn/react-compiler) for more information. 13 + 14 + Note: This will impact Vite dev & build performances. 15 + 16 + ## Expanding the ESLint configuration 17 + 18 + If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules: 19 + 20 + ```js 21 + export default defineConfig([ 22 + globalIgnores(['dist']), 23 + { 24 + files: ['**/*.{ts,tsx}'], 25 + extends: [ 26 + // Other configs... 27 + 28 + // Remove tseslint.configs.recommended and replace with this 29 + tseslint.configs.recommendedTypeChecked, 30 + // Alternatively, use this for stricter rules 31 + tseslint.configs.strictTypeChecked, 32 + // Optionally, add this for stylistic rules 33 + tseslint.configs.stylisticTypeChecked, 34 + 35 + // Other configs... 36 + ], 37 + languageOptions: { 38 + parserOptions: { 39 + project: ['./tsconfig.node.json', './tsconfig.app.json'], 40 + tsconfigRootDir: import.meta.dirname, 41 + }, 42 + // other options... 43 + }, 44 + }, 45 + ]) 46 + ``` 47 + 48 + You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules: 49 + 50 + ```js 51 + // eslint.config.js 52 + import reactX from 'eslint-plugin-react-x' 53 + import reactDom from 'eslint-plugin-react-dom' 54 + 55 + export default defineConfig([ 56 + globalIgnores(['dist']), 57 + { 58 + files: ['**/*.{ts,tsx}'], 59 + extends: [ 60 + // Other configs... 61 + // Enable lint rules for React 62 + reactX.configs['recommended-typescript'], 63 + // Enable lint rules for React DOM 64 + reactDom.configs.recommended, 65 + ], 66 + languageOptions: { 67 + parserOptions: { 68 + project: ['./tsconfig.node.json', './tsconfig.app.json'], 69 + tsconfigRootDir: import.meta.dirname, 70 + }, 71 + // other options... 72 + }, 73 + }, 74 + ]) 75 + ```
+699
react/bun.lock
··· 1 + { 2 + "lockfileVersion": 1, 3 + "workspaces": { 4 + "": { 5 + "name": "react", 6 + "dependencies": { 7 + "@tailwindcss/vite": "^4.1.17", 8 + "draft-js": "^0.11.7", 9 + "react": "^19.2.0", 10 + "react-dom": "^19.2.0", 11 + "react-router": "^7.9.6", 12 + "tailwindcss": "^4.1.17", 13 + }, 14 + "devDependencies": { 15 + "@eslint/js": "^9.39.1", 16 + "@happy-dom/global-registrator": "^20.0.10", 17 + "@testing-library/jest-dom": "^6.9.1", 18 + "@testing-library/react": "^16.3.0", 19 + "@types/bun": "latest", 20 + "@types/draft-js": "^0.11.20", 21 + "@types/node": "^24.10.0", 22 + "@types/react": "^19.2.2", 23 + "@types/react-dom": "^19.2.2", 24 + "@vitejs/plugin-react": "^5.1.0", 25 + "babel-plugin-react-compiler": "^1.0.0", 26 + "eslint": "^9.39.1", 27 + "eslint-plugin-react-hooks": "^7.0.1", 28 + "eslint-plugin-react-refresh": "^0.4.24", 29 + "globals": "^16.5.0", 30 + "typescript": "~5.9.3", 31 + "typescript-eslint": "^8.46.3", 32 + "vite": "^7.2.2", 33 + }, 34 + }, 35 + }, 36 + "packages": { 37 + "@adobe/css-tools": ["@adobe/css-tools@4.4.4", "", {}, "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg=="], 38 + 39 + "@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], 40 + 41 + "@babel/compat-data": ["@babel/compat-data@7.28.5", "", {}, "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA=="], 42 + 43 + "@babel/core": ["@babel/core@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw=="], 44 + 45 + "@babel/generator": ["@babel/generator@7.28.5", "", { "dependencies": { "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ=="], 46 + 47 + "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="], 48 + 49 + "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="], 50 + 51 + "@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="], 52 + 53 + "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw=="], 54 + 55 + "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.27.1", "", {}, "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw=="], 56 + 57 + "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], 58 + 59 + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], 60 + 61 + "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], 62 + 63 + "@babel/helpers": ["@babel/helpers@7.28.4", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.4" } }, "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w=="], 64 + 65 + "@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="], 66 + 67 + "@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="], 68 + 69 + "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="], 70 + 71 + "@babel/runtime": ["@babel/runtime@7.28.4", "", {}, "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ=="], 72 + 73 + "@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="], 74 + 75 + "@babel/traverse": ["@babel/traverse@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/types": "^7.28.5", "debug": "^4.3.1" } }, "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ=="], 76 + 77 + "@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="], 78 + 79 + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="], 80 + 81 + "@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="], 82 + 83 + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="], 84 + 85 + "@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="], 86 + 87 + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="], 88 + 89 + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="], 90 + 91 + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="], 92 + 93 + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="], 94 + 95 + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="], 96 + 97 + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="], 98 + 99 + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="], 100 + 101 + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="], 102 + 103 + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="], 104 + 105 + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="], 106 + 107 + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="], 108 + 109 + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="], 110 + 111 + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="], 112 + 113 + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="], 114 + 115 + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="], 116 + 117 + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="], 118 + 119 + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="], 120 + 121 + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="], 122 + 123 + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="], 124 + 125 + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="], 126 + 127 + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="], 128 + 129 + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="], 130 + 131 + "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g=="], 132 + 133 + "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="], 134 + 135 + "@eslint/config-array": ["@eslint/config-array@0.21.1", "", { "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA=="], 136 + 137 + "@eslint/config-helpers": ["@eslint/config-helpers@0.4.2", "", { "dependencies": { "@eslint/core": "^0.17.0" } }, "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw=="], 138 + 139 + "@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="], 140 + 141 + "@eslint/eslintrc": ["@eslint/eslintrc@3.3.1", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ=="], 142 + 143 + "@eslint/js": ["@eslint/js@9.39.1", "", {}, "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw=="], 144 + 145 + "@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="], 146 + 147 + "@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="], 148 + 149 + "@happy-dom/global-registrator": ["@happy-dom/global-registrator@20.0.10", "", { "dependencies": { "@types/node": "^20.0.0", "happy-dom": "^20.0.10" } }, "sha512-GU0UBt9lJKhZlY/U0Bivj9ZVepDIQoAUupAAl/90THG4/urkzXNglkVYETsnt2pGBDgQ+4vBjMAbLu6XzcKcQA=="], 150 + 151 + "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], 152 + 153 + "@humanfs/node": ["@humanfs/node@0.16.7", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.4.0" } }, "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ=="], 154 + 155 + "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], 156 + 157 + "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="], 158 + 159 + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], 160 + 161 + "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], 162 + 163 + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], 164 + 165 + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], 166 + 167 + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], 168 + 169 + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], 170 + 171 + "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], 172 + 173 + "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], 174 + 175 + "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.47", "", {}, "sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw=="], 176 + 177 + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.53.2", "", { "os": "android", "cpu": "arm" }, "sha512-yDPzwsgiFO26RJA4nZo8I+xqzh7sJTZIWQOxn+/XOdPE31lAvLIYCKqjV+lNH/vxE2L2iH3plKxDCRK6i+CwhA=="], 178 + 179 + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.53.2", "", { "os": "android", "cpu": "arm64" }, "sha512-k8FontTxIE7b0/OGKeSN5B6j25EuppBcWM33Z19JoVT7UTXFSo3D9CdU39wGTeb29NO3XxpMNauh09B+Ibw+9g=="], 180 + 181 + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.53.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-A6s4gJpomNBtJ2yioj8bflM2oogDwzUiMl2yNJ2v9E7++sHrSrsQ29fOfn5DM/iCzpWcebNYEdXpaK4tr2RhfQ=="], 182 + 183 + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.53.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-e6XqVmXlHrBlG56obu9gDRPW3O3hLxpwHpLsBJvuI8qqnsrtSZ9ERoWUXtPOkY8c78WghyPHZdmPhHLWNdAGEw=="], 184 + 185 + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.53.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-v0E9lJW8VsrwPux5Qe5CwmH/CF/2mQs6xU1MF3nmUxmZUCHazCjLgYvToOk+YuuUqLQBio1qkkREhxhc656ViA=="], 186 + 187 + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.53.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-ClAmAPx3ZCHtp6ysl4XEhWU69GUB1D+s7G9YjHGhIGCSrsg00nEGRRZHmINYxkdoJehde8VIsDC5t9C0gb6yqA=="], 188 + 189 + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.53.2", "", { "os": "linux", "cpu": "arm" }, "sha512-EPlb95nUsz6Dd9Qy13fI5kUPXNSljaG9FiJ4YUGU1O/Q77i5DYFW5KR8g1OzTcdZUqQQ1KdDqsTohdFVwCwjqg=="], 190 + 191 + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.53.2", "", { "os": "linux", "cpu": "arm" }, "sha512-BOmnVW+khAUX+YZvNfa0tGTEMVVEerOxN0pDk2E6N6DsEIa2Ctj48FOMfNDdrwinocKaC7YXUZ1pHlKpnkja/Q=="], 192 + 193 + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.53.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-Xt2byDZ+6OVNuREgBXr4+CZDJtrVso5woFtpKdGPhpTPHcNG7D8YXeQzpNbFRxzTVqJf7kvPMCub/pcGUWgBjA=="], 194 + 195 + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.53.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-+LdZSldy/I9N8+klim/Y1HsKbJ3BbInHav5qE9Iy77dtHC/pibw1SR/fXlWyAk0ThnpRKoODwnAuSjqxFRDHUQ=="], 196 + 197 + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.53.2", "", { "os": "linux", "cpu": "none" }, "sha512-8ms8sjmyc1jWJS6WdNSA23rEfdjWB30LH8Wqj0Cqvv7qSHnvw6kgMMXRdop6hkmGPlyYBdRPkjJnj3KCUHV/uQ=="], 198 + 199 + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.53.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-3HRQLUQbpBDMmzoxPJYd3W6vrVHOo2cVW8RUo87Xz0JPJcBLBr5kZ1pGcQAhdZgX9VV7NbGNipah1omKKe23/g=="], 200 + 201 + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.53.2", "", { "os": "linux", "cpu": "none" }, "sha512-fMjKi+ojnmIvhk34gZP94vjogXNNUKMEYs+EDaB/5TG/wUkoeua7p7VCHnE6T2Tx+iaghAqQX8teQzcvrYpaQA=="], 202 + 203 + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.53.2", "", { "os": "linux", "cpu": "none" }, "sha512-XuGFGU+VwUUV5kLvoAdi0Wz5Xbh2SrjIxCtZj6Wq8MDp4bflb/+ThZsVxokM7n0pcbkEr2h5/pzqzDYI7cCgLQ=="], 204 + 205 + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.53.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-w6yjZF0P+NGzWR3AXWX9zc0DNEGdtvykB03uhonSHMRa+oWA6novflo2WaJr6JZakG2ucsyb+rvhrKac6NIy+w=="], 206 + 207 + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.53.2", "", { "os": "linux", "cpu": "x64" }, "sha512-yo8d6tdfdeBArzC7T/PnHd7OypfI9cbuZzPnzLJIyKYFhAQ8SvlkKtKBMbXDxe1h03Rcr7u++nFS7tqXz87Gtw=="], 208 + 209 + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.53.2", "", { "os": "linux", "cpu": "x64" }, "sha512-ah59c1YkCxKExPP8O9PwOvs+XRLKwh/mV+3YdKqQ5AMQ0r4M4ZDuOrpWkUaqO7fzAHdINzV9tEVu8vNw48z0lA=="], 210 + 211 + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.53.2", "", { "os": "none", "cpu": "arm64" }, "sha512-4VEd19Wmhr+Zy7hbUsFZ6YXEiP48hE//KPLCSVNY5RMGX2/7HZ+QkN55a3atM1C/BZCGIgqN+xrVgtdak2S9+A=="], 212 + 213 + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.53.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-IlbHFYc/pQCgew/d5fslcy1KEaYVCJ44G8pajugd8VoOEI8ODhtb/j8XMhLpwHCMB3yk2J07ctup10gpw2nyMA=="], 214 + 215 + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.53.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-lNlPEGgdUfSzdCWU176ku/dQRnA7W+Gp8d+cWv73jYrb8uT7HTVVxq62DUYxjbaByuf1Yk0RIIAbDzp+CnOTFg=="], 216 + 217 + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.53.2", "", { "os": "win32", "cpu": "x64" }, "sha512-S6YojNVrHybQis2lYov1sd+uj7K0Q05NxHcGktuMMdIQ2VixGwAfbJ23NnlvvVV1bdpR2m5MsNBViHJKcA4ADw=="], 218 + 219 + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.53.2", "", { "os": "win32", "cpu": "x64" }, "sha512-k+/Rkcyx//P6fetPoLMb8pBeqJBNGx81uuf7iljX9++yNBVRDQgD04L+SVXmXmh5ZP4/WOp4mWF0kmi06PW2tA=="], 220 + 221 + "@tailwindcss/node": ["@tailwindcss/node@4.1.17", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.6.1", "lightningcss": "1.30.2", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.1.17" } }, "sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg=="], 222 + 223 + "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.17", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.17", "@tailwindcss/oxide-darwin-arm64": "4.1.17", "@tailwindcss/oxide-darwin-x64": "4.1.17", "@tailwindcss/oxide-freebsd-x64": "4.1.17", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.17", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.17", "@tailwindcss/oxide-linux-arm64-musl": "4.1.17", "@tailwindcss/oxide-linux-x64-gnu": "4.1.17", "@tailwindcss/oxide-linux-x64-musl": "4.1.17", "@tailwindcss/oxide-wasm32-wasi": "4.1.17", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.17", "@tailwindcss/oxide-win32-x64-msvc": "4.1.17" } }, "sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA=="], 224 + 225 + "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.17", "", { "os": "android", "cpu": "arm64" }, "sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ=="], 226 + 227 + "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.17", "", { "os": "darwin", "cpu": "arm64" }, "sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg=="], 228 + 229 + "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.17", "", { "os": "darwin", "cpu": "x64" }, "sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog=="], 230 + 231 + "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.17", "", { "os": "freebsd", "cpu": "x64" }, "sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g=="], 232 + 233 + "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17", "", { "os": "linux", "cpu": "arm" }, "sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ=="], 234 + 235 + "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.17", "", { "os": "linux", "cpu": "arm64" }, "sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ=="], 236 + 237 + "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.17", "", { "os": "linux", "cpu": "arm64" }, "sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg=="], 238 + 239 + "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.17", "", { "os": "linux", "cpu": "x64" }, "sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ=="], 240 + 241 + "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.17", "", { "os": "linux", "cpu": "x64" }, "sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ=="], 242 + 243 + "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.17", "", { "dependencies": { "@emnapi/core": "^1.6.0", "@emnapi/runtime": "^1.6.0", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.0.7", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.4.0" }, "cpu": "none" }, "sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg=="], 244 + 245 + "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.17", "", { "os": "win32", "cpu": "arm64" }, "sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A=="], 246 + 247 + "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.17", "", { "os": "win32", "cpu": "x64" }, "sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw=="], 248 + 249 + "@tailwindcss/vite": ["@tailwindcss/vite@4.1.17", "", { "dependencies": { "@tailwindcss/node": "4.1.17", "@tailwindcss/oxide": "4.1.17", "tailwindcss": "4.1.17" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-4+9w8ZHOiGnpcGI6z1TVVfWaX/koK7fKeSYF3qlYg2xpBtbteP2ddBxiarL+HVgfSJGeK5RIxRQmKm4rTJJAwA=="], 250 + 251 + "@testing-library/dom": ["@testing-library/dom@10.4.1", "", { "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", "aria-query": "5.3.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", "picocolors": "1.1.1", "pretty-format": "^27.0.2" } }, "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg=="], 252 + 253 + "@testing-library/jest-dom": ["@testing-library/jest-dom@6.9.1", "", { "dependencies": { "@adobe/css-tools": "^4.4.0", "aria-query": "^5.0.0", "css.escape": "^1.5.1", "dom-accessibility-api": "^0.6.3", "picocolors": "^1.1.1", "redent": "^3.0.0" } }, "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA=="], 254 + 255 + "@testing-library/react": ["@testing-library/react@16.3.0", "", { "dependencies": { "@babel/runtime": "^7.12.5" }, "peerDependencies": { "@testing-library/dom": "^10.0.0", "@types/react": "^18.0.0 || ^19.0.0", "@types/react-dom": "^18.0.0 || ^19.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw=="], 256 + 257 + "@types/aria-query": ["@types/aria-query@5.0.4", "", {}, "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw=="], 258 + 259 + "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], 260 + 261 + "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], 262 + 263 + "@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="], 264 + 265 + "@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="], 266 + 267 + "@types/bun": ["@types/bun@1.3.2", "", { "dependencies": { "bun-types": "1.3.2" } }, "sha512-t15P7k5UIgHKkxwnMNkJbWlh/617rkDGEdSsDbu+qNHTaz9SKf7aC8fiIlUdD5RPpH6GEkP0cK7WlvmrEBRtWg=="], 268 + 269 + "@types/draft-js": ["@types/draft-js@0.11.20", "", { "dependencies": { "@types/react": "*", "immutable": "~3.7.4" } }, "sha512-bZHtHxXnCu4wlUXlDWrIlJSG2LJ6wcycSWoxcTCcGd0cVOm35p0vh87qpIPzGK2NALMMvJhQXdS330iYB3iGlw=="], 270 + 271 + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], 272 + 273 + "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], 274 + 275 + "@types/node": ["@types/node@24.10.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ=="], 276 + 277 + "@types/react": ["@types/react@19.2.6", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-p/jUvulfgU7oKtj6Xpk8cA2Y1xKTtICGpJYeJXz2YVO2UcvjQgeRMLDGfDeqeRW2Ta+0QNFwcc8X3GH8SxZz6w=="], 278 + 279 + "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], 280 + 281 + "@types/whatwg-mimetype": ["@types/whatwg-mimetype@3.0.2", "", {}, "sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA=="], 282 + 283 + "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.47.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.47.0", "@typescript-eslint/type-utils": "8.47.0", "@typescript-eslint/utils": "8.47.0", "@typescript-eslint/visitor-keys": "8.47.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.47.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-fe0rz9WJQ5t2iaLfdbDc9T80GJy0AeO453q8C3YCilnGozvOyCG5t+EZtg7j7D88+c3FipfP/x+wzGnh1xp8ZA=="], 284 + 285 + "@typescript-eslint/parser": ["@typescript-eslint/parser@8.47.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.47.0", "@typescript-eslint/types": "8.47.0", "@typescript-eslint/typescript-estree": "8.47.0", "@typescript-eslint/visitor-keys": "8.47.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-lJi3PfxVmo0AkEY93ecfN+r8SofEqZNGByvHAI3GBLrvt1Cw6H5k1IM02nSzu0RfUafr2EvFSw0wAsZgubNplQ=="], 286 + 287 + "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.47.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.47.0", "@typescript-eslint/types": "^8.47.0", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-2X4BX8hUeB5JcA1TQJ7GjcgulXQ+5UkNb0DL8gHsHUHdFoiCTJoYLTpib3LtSDPZsRET5ygN4qqIWrHyYIKERA=="], 288 + 289 + "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.47.0", "", { "dependencies": { "@typescript-eslint/types": "8.47.0", "@typescript-eslint/visitor-keys": "8.47.0" } }, "sha512-a0TTJk4HXMkfpFkL9/WaGTNuv7JWfFTQFJd6zS9dVAjKsojmv9HT55xzbEpnZoY+VUb+YXLMp+ihMLz/UlZfDg=="], 290 + 291 + "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.47.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-ybUAvjy4ZCL11uryalkKxuT3w3sXJAuWhOoGS3T/Wu+iUu1tGJmk5ytSY8gbdACNARmcYEB0COksD2j6hfGK2g=="], 292 + 293 + "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.47.0", "", { "dependencies": { "@typescript-eslint/types": "8.47.0", "@typescript-eslint/typescript-estree": "8.47.0", "@typescript-eslint/utils": "8.47.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-QC9RiCmZ2HmIdCEvhd1aJELBlD93ErziOXXlHEZyuBo3tBiAZieya0HLIxp+DoDWlsQqDawyKuNEhORyku+P8A=="], 294 + 295 + "@typescript-eslint/types": ["@typescript-eslint/types@8.47.0", "", {}, "sha512-nHAE6bMKsizhA2uuYZbEbmp5z2UpffNrPEqiKIeN7VsV6UY/roxanWfoRrf6x/k9+Obf+GQdkm0nPU+vnMXo9A=="], 296 + 297 + "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.47.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.47.0", "@typescript-eslint/tsconfig-utils": "8.47.0", "@typescript-eslint/types": "8.47.0", "@typescript-eslint/visitor-keys": "8.47.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-k6ti9UepJf5NpzCjH31hQNLHQWupTRPhZ+KFF8WtTuTpy7uHPfeg2NM7cP27aCGajoEplxJDFVCEm9TGPYyiVg=="], 298 + 299 + "@typescript-eslint/utils": ["@typescript-eslint/utils@8.47.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.47.0", "@typescript-eslint/types": "8.47.0", "@typescript-eslint/typescript-estree": "8.47.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-g7XrNf25iL4TJOiPqatNuaChyqt49a/onq5YsJ9+hXeugK+41LVg7AxikMfM02PC6jbNtZLCJj6AUcQXJS/jGQ=="], 300 + 301 + "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.47.0", "", { "dependencies": { "@typescript-eslint/types": "8.47.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-SIV3/6eftCy1bNzCQoPmbWsRLujS8t5iDIZ4spZOBHqrM+yfX2ogg8Tt3PDTAVKw3sSCiUgg30uOAvK2r9zGjQ=="], 302 + 303 + "@vitejs/plugin-react": ["@vitejs/plugin-react@5.1.1", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.47", "@types/babel__core": "^7.20.5", "react-refresh": "^0.18.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-WQfkSw0QbQ5aJ2CHYw23ZGkqnRwqKHD/KYsMeTkZzPT4Jcf0DcBxBtwMJxnu6E7oxw5+JC6ZAiePgh28uJ1HBA=="], 304 + 305 + "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], 306 + 307 + "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], 308 + 309 + "ajv": ["ajv@6.12.6", "", { "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" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], 310 + 311 + "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], 312 + 313 + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], 314 + 315 + "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], 316 + 317 + "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="], 318 + 319 + "asap": ["asap@2.0.6", "", {}, "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="], 320 + 321 + "babel-plugin-react-compiler": ["babel-plugin-react-compiler@1.0.0", "", { "dependencies": { "@babel/types": "^7.26.0" } }, "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw=="], 322 + 323 + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], 324 + 325 + "baseline-browser-mapping": ["baseline-browser-mapping@2.8.29", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-sXdt2elaVnhpDNRDz+1BDx1JQoJRuNk7oVlAlbGiFkLikHCAQiccexF/9e91zVi6RCgqspl04aP+6Cnl9zRLrA=="], 326 + 327 + "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], 328 + 329 + "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], 330 + 331 + "browserslist": ["browserslist@4.28.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", "electron-to-chromium": "^1.5.249", "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": { "browserslist": "cli.js" } }, "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ=="], 332 + 333 + "bun-types": ["bun-types@1.3.2", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-i/Gln4tbzKNuxP70OWhJRZz1MRfvqExowP7U6JKoI8cntFrtxg7RJK3jvz7wQW54UuvNC8tbKHHri5fy74FVqg=="], 334 + 335 + "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], 336 + 337 + "caniuse-lite": ["caniuse-lite@1.0.30001755", "", {}, "sha512-44V+Jm6ctPj7R52Na4TLi3Zri4dWUljJd+RDm+j8LtNCc/ihLCT+X1TzoOAkRETEWqjuLnh9581Tl80FvK7jVA=="], 338 + 339 + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], 340 + 341 + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], 342 + 343 + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], 344 + 345 + "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], 346 + 347 + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], 348 + 349 + "cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="], 350 + 351 + "core-js": ["core-js@3.47.0", "", {}, "sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg=="], 352 + 353 + "cross-fetch": ["cross-fetch@3.2.0", "", { "dependencies": { "node-fetch": "^2.7.0" } }, "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q=="], 354 + 355 + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], 356 + 357 + "css.escape": ["css.escape@1.5.1", "", {}, "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg=="], 358 + 359 + "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], 360 + 361 + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], 362 + 363 + "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], 364 + 365 + "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], 366 + 367 + "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], 368 + 369 + "dom-accessibility-api": ["dom-accessibility-api@0.6.3", "", {}, "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w=="], 370 + 371 + "draft-js": ["draft-js@0.11.7", "", { "dependencies": { "fbjs": "^2.0.0", "immutable": "~3.7.4", "object-assign": "^4.1.1" }, "peerDependencies": { "react": ">=0.14.0", "react-dom": ">=0.14.0" } }, "sha512-ne7yFfN4sEL82QPQEn80xnADR8/Q6ALVworbC5UOSzOvjffmYfFsr3xSZtxbIirti14R7Y33EZC5rivpLgIbsg=="], 372 + 373 + "electron-to-chromium": ["electron-to-chromium@1.5.255", "", {}, "sha512-Z9oIp4HrFF/cZkDPMpz2XSuVpc1THDpT4dlmATFlJUIBVCy9Vap5/rIXsASP1CscBacBqhabwh8vLctqBwEerQ=="], 374 + 375 + "enhanced-resolve": ["enhanced-resolve@5.18.3", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww=="], 376 + 377 + "esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], 378 + 379 + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], 380 + 381 + "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], 382 + 383 + "eslint": ["eslint@9.39.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.1", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.39.1", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g=="], 384 + 385 + "eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@7.0.1", "", { "dependencies": { "@babel/core": "^7.24.4", "@babel/parser": "^7.24.4", "hermes-parser": "^0.25.1", "zod": "^3.25.0 || ^4.0.0", "zod-validation-error": "^3.5.0 || ^4.0.0" }, "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA=="], 386 + 387 + "eslint-plugin-react-refresh": ["eslint-plugin-react-refresh@0.4.24", "", { "peerDependencies": { "eslint": ">=8.40" } }, "sha512-nLHIW7TEq3aLrEYWpVaJ1dRgFR+wLDPN8e8FpYAql/bMV2oBEfC37K0gLEGgv9fy66juNShSMV8OkTqzltcG/w=="], 388 + 389 + "eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="], 390 + 391 + "eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], 392 + 393 + "espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="], 394 + 395 + "esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="], 396 + 397 + "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], 398 + 399 + "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], 400 + 401 + "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], 402 + 403 + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], 404 + 405 + "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], 406 + 407 + "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], 408 + 409 + "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], 410 + 411 + "fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="], 412 + 413 + "fbjs": ["fbjs@2.0.0", "", { "dependencies": { "core-js": "^3.6.4", "cross-fetch": "^3.0.4", "fbjs-css-vars": "^1.0.0", "loose-envify": "^1.0.0", "object-assign": "^4.1.0", "promise": "^7.1.1", "setimmediate": "^1.0.5", "ua-parser-js": "^0.7.18" } }, "sha512-8XA8ny9ifxrAWlyhAbexXcs3rRMtxWcs3M0lctLfB49jRDHiaxj+Mo0XxbwE7nKZYzgCFoq64FS+WFd4IycPPQ=="], 414 + 415 + "fbjs-css-vars": ["fbjs-css-vars@1.0.2", "", {}, "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ=="], 416 + 417 + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], 418 + 419 + "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], 420 + 421 + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], 422 + 423 + "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], 424 + 425 + "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], 426 + 427 + "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], 428 + 429 + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], 430 + 431 + "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], 432 + 433 + "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], 434 + 435 + "globals": ["globals@16.5.0", "", {}, "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ=="], 436 + 437 + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], 438 + 439 + "graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="], 440 + 441 + "happy-dom": ["happy-dom@20.0.10", "", { "dependencies": { "@types/node": "^20.0.0", "@types/whatwg-mimetype": "^3.0.2", "whatwg-mimetype": "^3.0.0" } }, "sha512-6umCCHcjQrhP5oXhrHQQvLB0bwb1UzHAHdsXy+FjtKoYjUhmNZsQL8NivwM1vDvNEChJabVrUYxUnp/ZdYmy2g=="], 442 + 443 + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], 444 + 445 + "hermes-estree": ["hermes-estree@0.25.1", "", {}, "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw=="], 446 + 447 + "hermes-parser": ["hermes-parser@0.25.1", "", { "dependencies": { "hermes-estree": "0.25.1" } }, "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA=="], 448 + 449 + "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], 450 + 451 + "immutable": ["immutable@3.7.6", "", {}, "sha512-AizQPcaofEtO11RZhPPHBOJRdo/20MKQF9mBLnVkBoyHi1/zXK8fzVdnEpSV9gxqtnh6Qomfp3F0xT5qP/vThw=="], 452 + 453 + "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], 454 + 455 + "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], 456 + 457 + "indent-string": ["indent-string@4.0.0", "", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="], 458 + 459 + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], 460 + 461 + "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], 462 + 463 + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], 464 + 465 + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], 466 + 467 + "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], 468 + 469 + "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], 470 + 471 + "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], 472 + 473 + "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], 474 + 475 + "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], 476 + 477 + "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], 478 + 479 + "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], 480 + 481 + "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], 482 + 483 + "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], 484 + 485 + "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], 486 + 487 + "lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="], 488 + 489 + "lightningcss-android-arm64": ["lightningcss-android-arm64@1.30.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A=="], 490 + 491 + "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA=="], 492 + 493 + "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ=="], 494 + 495 + "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA=="], 496 + 497 + "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.2", "", { "os": "linux", "cpu": "arm" }, "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA=="], 498 + 499 + "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A=="], 500 + 501 + "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA=="], 502 + 503 + "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w=="], 504 + 505 + "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA=="], 506 + 507 + "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ=="], 508 + 509 + "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="], 510 + 511 + "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], 512 + 513 + "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], 514 + 515 + "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], 516 + 517 + "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], 518 + 519 + "lz-string": ["lz-string@1.5.0", "", { "bin": { "lz-string": "bin/bin.js" } }, "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ=="], 520 + 521 + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], 522 + 523 + "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], 524 + 525 + "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], 526 + 527 + "min-indent": ["min-indent@1.0.1", "", {}, "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg=="], 528 + 529 + "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], 530 + 531 + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], 532 + 533 + "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], 534 + 535 + "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], 536 + 537 + "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], 538 + 539 + "node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="], 540 + 541 + "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], 542 + 543 + "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], 544 + 545 + "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], 546 + 547 + "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], 548 + 549 + "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], 550 + 551 + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], 552 + 553 + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], 554 + 555 + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], 556 + 557 + "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], 558 + 559 + "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], 560 + 561 + "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], 562 + 563 + "pretty-format": ["pretty-format@27.5.1", "", { "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^17.0.1" } }, "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ=="], 564 + 565 + "promise": ["promise@7.3.1", "", { "dependencies": { "asap": "~2.0.3" } }, "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg=="], 566 + 567 + "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], 568 + 569 + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], 570 + 571 + "react": ["react@19.2.0", "", {}, "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ=="], 572 + 573 + "react-dom": ["react-dom@19.2.0", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.0" } }, "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ=="], 574 + 575 + "react-is": ["react-is@17.0.2", "", {}, "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="], 576 + 577 + "react-refresh": ["react-refresh@0.18.0", "", {}, "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw=="], 578 + 579 + "react-router": ["react-router@7.9.6", "", { "dependencies": { "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-Y1tUp8clYRXpfPITyuifmSoE2vncSME18uVLgaqyxh9H35JWpIfzHo+9y3Fzh5odk/jxPW29IgLgzcdwxGqyNA=="], 580 + 581 + "redent": ["redent@3.0.0", "", { "dependencies": { "indent-string": "^4.0.0", "strip-indent": "^3.0.0" } }, "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg=="], 582 + 583 + "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], 584 + 585 + "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], 586 + 587 + "rollup": ["rollup@4.53.2", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.53.2", "@rollup/rollup-android-arm64": "4.53.2", "@rollup/rollup-darwin-arm64": "4.53.2", "@rollup/rollup-darwin-x64": "4.53.2", "@rollup/rollup-freebsd-arm64": "4.53.2", "@rollup/rollup-freebsd-x64": "4.53.2", "@rollup/rollup-linux-arm-gnueabihf": "4.53.2", "@rollup/rollup-linux-arm-musleabihf": "4.53.2", "@rollup/rollup-linux-arm64-gnu": "4.53.2", "@rollup/rollup-linux-arm64-musl": "4.53.2", "@rollup/rollup-linux-loong64-gnu": "4.53.2", "@rollup/rollup-linux-ppc64-gnu": "4.53.2", "@rollup/rollup-linux-riscv64-gnu": "4.53.2", "@rollup/rollup-linux-riscv64-musl": "4.53.2", "@rollup/rollup-linux-s390x-gnu": "4.53.2", "@rollup/rollup-linux-x64-gnu": "4.53.2", "@rollup/rollup-linux-x64-musl": "4.53.2", "@rollup/rollup-openharmony-arm64": "4.53.2", "@rollup/rollup-win32-arm64-msvc": "4.53.2", "@rollup/rollup-win32-ia32-msvc": "4.53.2", "@rollup/rollup-win32-x64-gnu": "4.53.2", "@rollup/rollup-win32-x64-msvc": "4.53.2", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-MHngMYwGJVi6Fmnk6ISmnk7JAHRNF0UkuucA0CUW3N3a4KnONPEZz+vUanQP/ZC/iY1Qkf3bwPWzyY84wEks1g=="], 588 + 589 + "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], 590 + 591 + "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], 592 + 593 + "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], 594 + 595 + "set-cookie-parser": ["set-cookie-parser@2.7.2", "", {}, "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw=="], 596 + 597 + "setimmediate": ["setimmediate@1.0.5", "", {}, "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="], 598 + 599 + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], 600 + 601 + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], 602 + 603 + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], 604 + 605 + "strip-indent": ["strip-indent@3.0.0", "", { "dependencies": { "min-indent": "^1.0.0" } }, "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ=="], 606 + 607 + "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], 608 + 609 + "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], 610 + 611 + "tailwindcss": ["tailwindcss@4.1.17", "", {}, "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q=="], 612 + 613 + "tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="], 614 + 615 + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], 616 + 617 + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], 618 + 619 + "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], 620 + 621 + "ts-api-utils": ["ts-api-utils@2.1.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="], 622 + 623 + "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], 624 + 625 + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], 626 + 627 + "typescript-eslint": ["typescript-eslint@8.47.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.47.0", "@typescript-eslint/parser": "8.47.0", "@typescript-eslint/typescript-estree": "8.47.0", "@typescript-eslint/utils": "8.47.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-Lwe8i2XQ3WoMjua/r1PHrCTpkubPYJCAfOurtn+mtTzqB6jNd+14n9UN1bJ4s3F49x9ixAm0FLflB/JzQ57M8Q=="], 628 + 629 + "ua-parser-js": ["ua-parser-js@0.7.41", "", { "bin": { "ua-parser-js": "script/cli.js" } }, "sha512-O3oYyCMPYgNNHuO7Jjk3uacJWZF8loBgwrfd/5LE/HyZ3lUIOdniQ7DNXJcIgZbwioZxk0fLfI4EVnetdiX5jg=="], 630 + 631 + "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], 632 + 633 + "update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="], 634 + 635 + "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], 636 + 637 + "vite": ["vite@7.2.2", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ=="], 638 + 639 + "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], 640 + 641 + "whatwg-mimetype": ["whatwg-mimetype@3.0.0", "", {}, "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q=="], 642 + 643 + "whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], 644 + 645 + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], 646 + 647 + "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], 648 + 649 + "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], 650 + 651 + "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], 652 + 653 + "zod": ["zod@4.1.12", "", {}, "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ=="], 654 + 655 + "zod-validation-error": ["zod-validation-error@4.0.2", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ=="], 656 + 657 + "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], 658 + 659 + "@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], 660 + 661 + "@happy-dom/global-registrator/@types/node": ["@types/node@20.19.25", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ=="], 662 + 663 + "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.7.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg=="], 664 + 665 + "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.7.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA=="], 666 + 667 + "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], 668 + 669 + "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.0.7", "", { "dependencies": { "@emnapi/core": "^1.5.0", "@emnapi/runtime": "^1.5.0", "@tybys/wasm-util": "^0.10.1" }, "bundled": true }, "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw=="], 670 + 671 + "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], 672 + 673 + "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], 674 + 675 + "@testing-library/dom/aria-query": ["aria-query@5.3.0", "", { "dependencies": { "dequal": "^2.0.3" } }, "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A=="], 676 + 677 + "@testing-library/dom/dom-accessibility-api": ["dom-accessibility-api@0.5.16", "", {}, "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg=="], 678 + 679 + "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], 680 + 681 + "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], 682 + 683 + "@typescript-eslint/typescript-estree/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], 684 + 685 + "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], 686 + 687 + "happy-dom/@types/node": ["@types/node@20.19.25", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ=="], 688 + 689 + "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], 690 + 691 + "pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], 692 + 693 + "@happy-dom/global-registrator/@types/node/undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], 694 + 695 + "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], 696 + 697 + "happy-dom/@types/node/undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], 698 + } 699 + }
+2
react/bunfig.toml
··· 1 + [test] 2 + preload=["./preload.ts"]
+23
react/eslint.config.js
··· 1 + import js from '@eslint/js' 2 + import globals from 'globals' 3 + import reactHooks from 'eslint-plugin-react-hooks' 4 + import reactRefresh from 'eslint-plugin-react-refresh' 5 + import tseslint from 'typescript-eslint' 6 + import { defineConfig, globalIgnores } from 'eslint/config' 7 + 8 + export default defineConfig([ 9 + globalIgnores(['dist']), 10 + { 11 + files: ['**/*.{ts,tsx}'], 12 + extends: [ 13 + js.configs.recommended, 14 + tseslint.configs.recommended, 15 + reactHooks.configs.flat.recommended, 16 + reactRefresh.configs.vite, 17 + ], 18 + languageOptions: { 19 + ecmaVersion: 2020, 20 + globals: globals.browser, 21 + }, 22 + }, 23 + ])
+13
react/index.html
··· 1 + <!doctype html> 2 + <html lang="en"> 3 + <head> 4 + <meta charset="UTF-8" /> 5 + <link rel="icon" type="image/svg+xml" href="/vite.svg" /> 6 + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 7 + <title>react</title> 8 + </head> 9 + <body> 10 + <div id="root"></div> 11 + <script type="module" src="/src/main.tsx"></script> 12 + </body> 13 + </html>
+40
react/package.json
··· 1 + { 2 + "name": "react-blog", 3 + "private": true, 4 + "version": "0.0.0", 5 + "type": "module", 6 + "scripts": { 7 + "dev": "vite", 8 + "build": "tsc -b && vite build", 9 + "lint": "eslint .", 10 + "preview": "vite preview" 11 + }, 12 + "dependencies": { 13 + "@tailwindcss/vite": "^4.1.17", 14 + "draft-js": "^0.11.7", 15 + "react": "^19.2.0", 16 + "react-dom": "^19.2.0", 17 + "react-router": "^7.9.6", 18 + "tailwindcss": "^4.1.17" 19 + }, 20 + "devDependencies": { 21 + "@eslint/js": "^9.39.1", 22 + "@happy-dom/global-registrator": "^20.0.10", 23 + "@testing-library/jest-dom": "^6.9.1", 24 + "@testing-library/react": "^16.3.0", 25 + "@types/bun": "latest", 26 + "@types/draft-js": "^0.11.20", 27 + "@types/node": "^24.10.0", 28 + "@types/react": "^19.2.2", 29 + "@types/react-dom": "^19.2.2", 30 + "@vitejs/plugin-react": "^5.1.0", 31 + "babel-plugin-react-compiler": "^1.0.0", 32 + "eslint": "^9.39.1", 33 + "eslint-plugin-react-hooks": "^7.0.1", 34 + "eslint-plugin-react-refresh": "^0.4.24", 35 + "globals": "^16.5.0", 36 + "typescript": "~5.9.3", 37 + "typescript-eslint": "^8.46.3", 38 + "vite": "^7.2.2" 39 + } 40 + }
+3
react/preload.ts
··· 1 + import { GlobalRegistrator } from "@happy-dom/global-registrator"; 2 + 3 + GlobalRegistrator.register();
+61
react/src/App.tsx
··· 1 + import { posts } from "./lib/post"; 2 + import { BlogPostList } from "./components/BlogPostList"; 3 + import { Link } from "react-router"; 4 + import { useState } from "react"; 5 + 6 + export function App() { 7 + const [searchBarDisplay, displaySearchBar] = useState(false); 8 + return ( 9 + <> 10 + <title>Posts</title> 11 + <div className="w-screen p-5 flex flex-col items-center gap-10"> 12 + <nav className="flex justify-between items-center w-full sticky top-0"> 13 + <h1 className="text-3xl font-bold text-left">Blog App</h1> 14 + {searchBarDisplay ? ( 15 + <> 16 + <input 17 + type="text" 18 + placeholder="Search..." 19 + className="border border-gray-300 rounded px-2 py-1" 20 + onChange={(e) => { 21 + // Implement search functionality here 22 + }} 23 + /> 24 + <button 25 + className="bg-blue-500 hover:bg-blue-700 text-white w-full font-bold py-2 px-4 rounded cursor-pointer text-center" 26 + onClick={() => displaySearchBar(false)} 27 + > 28 + Close 29 + </button> 30 + </> 31 + ) : ( 32 + <button 33 + className="bg-blue-500 hover:bg-blue-700 text-white w-full font-bold py-2 px-4 rounded cursor-pointer text-center" 34 + onClick={() => displaySearchBar(true)} 35 + > 36 + Search 37 + </button> 38 + )} 39 + <div className="flex w-full justify-end items-center"> 40 + <Link to="/post" className="w-1/3"> 41 + <div className="bg-blue-500 hover:bg-blue-700 text-white w-full font-bold py-2 px-4 rounded cursor-pointer text-center"> 42 + New Post 43 + </div> 44 + </Link> 45 + </div> 46 + </nav> 47 + <div className="flex flex-col gap-4 md:grid md:grid-cols-3 items-center justify-between w-full"> 48 + <div className="flex w-full justify-end items-center"> 49 + <h1 className="text-5xl font-bold text-center">Posts</h1> 50 + <Link to="/post" className="w-1/3"> 51 + <div className="bg-blue-500 hover:bg-blue-700 text-white w-full font-bold py-2 px-4 rounded cursor-pointer text-center"> 52 + New Post 53 + </div> 54 + </Link> 55 + </div> 56 + </div> 57 + <BlogPostList posts={posts} /> 58 + </div> 59 + </> 60 + ); 61 + }
+17
react/src/component.test.tsx
··· 1 + /// <reference lib="dom" /> 2 + 3 + import { test, expect } from "bun:test"; 4 + import { render, screen } from "@testing-library/react"; 5 + import "@testing-library/jest-dom"; 6 + import { App } from "./App"; 7 + import { BrowserRouter } from "react-router"; 8 + import { posts } from "./lib/post"; 9 + 10 + test("renders app page", () => { 11 + render( 12 + <BrowserRouter> 13 + <App /> 14 + </BrowserRouter>, 15 + ); 16 + expect(screen.getAllByRole("heading")).toHaveLength(posts.length + 1); 17 + });
+95
react/src/components/BlogPostDetail.tsx
··· 1 + import { useParams, Outlet } from "react-router"; 2 + import { posts } from "../lib/post"; 3 + import { Link } from "react-router"; 4 + import { ContentState, convertFromRaw, Editor, EditorState } from "draft-js"; 5 + import { useState } from "react"; 6 + import { useNavigate } from "react-router"; 7 + 8 + export function BlogPostDetail({ 9 + deletePost, 10 + }: { 11 + deletePost: (id: number) => void; 12 + }) { 13 + const { postId } = useParams(); 14 + const post = posts.find((post) => post.id === parseInt(postId!)); 15 + const [editorState, setEditorState] = useState(() => { 16 + try { 17 + const data = JSON.parse(`"${post?.content ?? ""}"`); 18 + return EditorState.createWithContent(convertFromRaw(data)); 19 + } catch { 20 + console.log("fallback"); 21 + return EditorState.createWithContent( 22 + ContentState.createFromText(post?.content ?? ""), 23 + ); 24 + } 25 + }); 26 + const navigate = useNavigate(); 27 + 28 + if (!post) { 29 + return <div>Post not found</div>; 30 + } 31 + 32 + const formattedDate = new Date(post.datePosted).toLocaleDateString("en-US", { 33 + month: "long", 34 + day: "numeric", 35 + year: "numeric", 36 + }); 37 + 38 + return ( 39 + <> 40 + <title>{post.title}</title> 41 + <div className="md:grid md:grid-cols-3 flex flex-col w-full"> 42 + <Link 43 + to="/" 44 + className="text-gray-700 dark:text-gray-200 hover:text-gray-400 flex justify-center items-center w-16 mb-4 md:mb-0" 45 + > 46 + Home 47 + </Link> 48 + <h1 className="text-3xl md:text-4xl font-bold text-center mb-4 md:mb-0"> 49 + {post.title} 50 + </h1> 51 + <div className="flex md:justify-end items-center"> 52 + <Link to={`/post?postId=${post.id}`} className="w-1/3"> 53 + <div className="bg-blue-500 hover:bg-blue-700 text-white w-full font-bold py-2 px-4 rounded cursor-pointer text-center"> 54 + Edit Post 55 + </div> 56 + </Link> 57 + </div> 58 + </div> 59 + <div className="flex flex-col gap-1 md:gap-2.5 justify-center items-center mb-1.5 md:mb-2.5"> 60 + <p className="text-gray-700 dark:text-gray-400 text-sm md:text-lg"> 61 + By: {post.author} 62 + </p> 63 + <p className="text-gray-600 dark:text-gray-500 text-xs md:text-base"> 64 + Published on {formattedDate} 65 + </p> 66 + </div> 67 + <div className="text-sm md:text-lg md:w-3xl w-full md:mb-10"> 68 + <Editor 69 + editorState={editorState} 70 + onChange={setEditorState} 71 + readOnly={true} 72 + /> 73 + </div> 74 + <button 75 + className="bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-4 rounded cursor-pointer w-full md:w-3xl" 76 + onClick={() => { 77 + if (window.confirm("Are you sure you want to delete this post?")) { 78 + deletePost(post.id); 79 + navigate("/"); 80 + } 81 + }} 82 + > 83 + Delete 84 + </button> 85 + </> 86 + ); 87 + } 88 + 89 + export function PostLayout() { 90 + return ( 91 + <div className="flex flex-col justify-center gap-3.5 md:gap-5 items-center p-5 w-screen"> 92 + <Outlet /> 93 + </div> 94 + ); 95 + }
+255
react/src/components/BlogPostForm.tsx
··· 1 + import { posts, type BlogPost } from "../lib/post"; 2 + import { useRef, useState } from "react"; 3 + import { useNavigate } from "react-router"; 4 + import { useSearchParams } from "react-router"; 5 + import { 6 + ContentState, 7 + convertFromRaw, 8 + convertToRaw, 9 + Editor, 10 + EditorState, 11 + RichUtils, 12 + } from "draft-js"; 13 + import "draft-js/dist/Draft.css"; 14 + 15 + export function BlogPostForm({ 16 + post, 17 + onSubmit, 18 + }: { 19 + post: BlogPost | null; 20 + onSubmit: (post: BlogPost) => void; 21 + }) { 22 + const [postState, setPostState] = useState({ 23 + id: post?.id ?? posts.length, 24 + title: post?.title ?? "", 25 + summary: post?.summary ?? "", 26 + content: post?.content ?? "", 27 + author: post?.author ?? "", 28 + datePosted: post?.datePosted ?? new Date().toISOString().split("T")[0], 29 + }); 30 + const [missing, setMissing] = useState<string[]>([]); 31 + const [contentState, setContentState] = useState<EditorState>(() => { 32 + if (post?.content) { 33 + try { 34 + const rawContent = JSON.parse(post.content); 35 + return EditorState.createWithContent(convertFromRaw(rawContent)); 36 + } catch { 37 + // Fallback to plain text if JSON parsing fails 38 + return EditorState.createWithContent( 39 + ContentState.createFromText(post.content), 40 + ); 41 + } 42 + } 43 + return EditorState.createEmpty(); 44 + }); 45 + 46 + const editorRef = useRef<Editor>(null); 47 + 48 + const navigate = useNavigate(); 49 + 50 + const handleChange = ( 51 + event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>, 52 + ) => { 53 + const { name, value } = event.target; 54 + setPostState((prevState) => ({ ...prevState, [name]: value })); 55 + }; 56 + 57 + const handleMissing = () => { 58 + const missingFields = Object.entries(postState) 59 + .map(([key, value]) => (value === "" ? key : null)) 60 + .filter((key) => key !== null); 61 + setMissing(missingFields); 62 + }; 63 + 64 + const handleContentChange = (content: EditorState) => { 65 + setContentState(content); 66 + const rawContent = convertToRaw(content.getCurrentContent()); 67 + setPostState((prevState) => ({ 68 + ...prevState, 69 + content: JSON.stringify(rawContent), 70 + })); 71 + }; 72 + 73 + const handleInlineStyle = (style: string) => { 74 + setContentState((prevState) => 75 + RichUtils.toggleInlineStyle(prevState, style), 76 + ); 77 + }; 78 + 79 + const handleSubmit = (event: React.MouseEvent<HTMLButtonElement>) => { 80 + event.preventDefault(); 81 + 82 + if ( 83 + !postState.title || 84 + !postState.summary || 85 + !postState.content || 86 + !postState.author 87 + ) { 88 + handleMissing(); 89 + return; 90 + } 91 + 92 + onSubmit(postState); 93 + navigate("/"); 94 + }; 95 + 96 + return ( 97 + <form className="flex flex-col gap-4 dark:bg-slate-600 p-10 rounded-lg md:w-4xl w-md"> 98 + <label className="md:grid md:grid-cols-6 flex flex-col w-full gap-2"> 99 + Title: 100 + <input 101 + type="text" 102 + name="title" 103 + className="border-gray-400 md:col-start-2 md:col-span-5 border rounded h-8 py-1 px-2 w-full" 104 + value={postState.title} 105 + onChange={handleChange} 106 + required 107 + /> 108 + </label> 109 + {missing.includes("title") && ( 110 + <p className="text-red-500">Title is required</p> 111 + )} 112 + <label className="md:grid md:grid-cols-6 flex flex-col w-full gap-2"> 113 + Summary: 114 + <textarea 115 + name="summary" 116 + className="border-gray-400 md:col-start-2 md:col-span-5 border rounded min-h-16 h-auto py-1 px-2 w-full" 117 + value={postState.summary} 118 + onChange={handleChange} 119 + required 120 + /> 121 + </label> 122 + {missing.includes("summary") && ( 123 + <p className="text-red-500">Summary is required</p> 124 + )} 125 + <label className="md:grid md:grid-cols-6 flex flex-col w-full gap-2"> 126 + Content: 127 + </label> 128 + <div className="md:grid md:grid-cols-6"> 129 + <div className="md:col-start-2 md:col-span-5"> 130 + <div className="flex gap-2 mb-2 border-b pb-2"> 131 + <button 132 + type="button" 133 + onMouseDown={(e) => { 134 + e.preventDefault(); 135 + handleInlineStyle("BOLD"); 136 + }} 137 + className={`px-3 py-1 border rounded ${ 138 + contentState.getCurrentInlineStyle().has("BOLD") 139 + ? "bg-blue-500 text-white" 140 + : "bg-gray-500" 141 + }`} 142 + > 143 + <strong>B</strong> 144 + </button> 145 + <button 146 + type="button" 147 + onMouseDown={(e) => { 148 + e.preventDefault(); 149 + handleInlineStyle("ITALIC"); 150 + }} 151 + className={`px-3 py-1 border rounded ${ 152 + contentState.getCurrentInlineStyle().has("ITALIC") 153 + ? "bg-blue-500 text-white" 154 + : "bg-gray-500" 155 + }`} 156 + > 157 + <em>I</em> 158 + </button> 159 + <button 160 + type="button" 161 + onMouseDown={(e) => { 162 + e.preventDefault(); 163 + handleInlineStyle("UNDERLINE"); 164 + }} 165 + className={`px-3 py-1 border rounded ${ 166 + contentState.getCurrentInlineStyle().has("UNDERLINE") 167 + ? "bg-blue-500 text-white" 168 + : "bg-gray-500" 169 + }`} 170 + > 171 + <u>U</u> 172 + </button> 173 + </div> 174 + 175 + {/* Editor */} 176 + <div 177 + className="border-gray-400 border rounded p-2 cursor-text min-h-48 pointer-events-auto select-text" 178 + onMouseDown={(e) => { 179 + if (e.target === e.currentTarget) { 180 + e.preventDefault(); 181 + editorRef.current?.focus(); 182 + } 183 + }} 184 + > 185 + <Editor 186 + ref={editorRef} 187 + editorState={contentState} 188 + onChange={handleContentChange} 189 + placeholder="Write your content here..." 190 + /> 191 + </div> 192 + </div> 193 + </div> 194 + {missing.includes("content") && ( 195 + <p className="text-red-500">Content is required</p> 196 + )} 197 + <label className="md:grid md:grid-cols-6 flex flex-col w-full gap-2"> 198 + Author: 199 + <input 200 + type="text" 201 + name="author" 202 + className="border-gray-400 md:col-start-2 md:col-span-5 border rounded h-8 py-1 px-2 w-full" 203 + value={postState.author} 204 + onChange={handleChange} 205 + required 206 + /> 207 + </label> 208 + {missing.includes("author") && ( 209 + <p className="text-red-500">Author is required</p> 210 + )} 211 + <label className="md:grid md:grid-cols-6 flex flex-col w-full gap-2"> 212 + Date Posted: 213 + <input 214 + type="date" 215 + name="datePosted" 216 + value={postState.datePosted} 217 + onChange={handleChange} 218 + required 219 + /> 220 + </label> 221 + <button 222 + type="button" 223 + className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded cursor-pointer" 224 + onClick={handleSubmit} 225 + > 226 + {post ? "Save Post" : "Create Post"} 227 + </button> 228 + </form> 229 + ); 230 + } 231 + 232 + export function NewPostLayout() { 233 + const searchParams = useSearchParams()[0]; 234 + const postId = parseInt(searchParams.get("postId") ?? "-1"); 235 + const post = 236 + postId < 0 || postId >= posts.length 237 + ? null 238 + : posts.find((p) => p.id === postId)!; 239 + 240 + return ( 241 + <div className="flex flex-col gap-4 items-center justify-center dark:bg-slate-700 p-10 h-screen"> 242 + <h1 className="text-2xl font-bold">New Post</h1> 243 + <BlogPostForm 244 + post={post} 245 + onSubmit={(post) => { 246 + if (post.id < posts.length) { 247 + posts[post.id] = post; 248 + } else { 249 + posts.push(post); 250 + } 251 + }} 252 + /> 253 + </div> 254 + ); 255 + }
+33
react/src/components/BlogPostItem.tsx
··· 1 + import { Link } from "react-router"; 2 + 3 + export function BlogPostItem({ 4 + title, 5 + idx, 6 + datePosted, 7 + summary, 8 + }: { 9 + title: string; 10 + idx: number; 11 + datePosted: string; 12 + summary: string; 13 + }) { 14 + return ( 15 + <> 16 + <Link to={`/entries/${idx}`}> 17 + <div className="border border-gray-300 p-3.5 md:p-5 rounded-md flex flex-col gap justify-center items-center max-w-lg"> 18 + <div className="flex flex-row gap-4 justify-center items-center"> 19 + <p className="text-gray-500">#{idx + 1}</p> 20 + <h2 className="text-xl md:text-2xl dark:text-gray-300 text-gray-900 font-bold "> 21 + {title} 22 + </h2> 23 + </div> 24 + <p className="text-gray-500 text-sm">Posted on {datePosted}</p> 25 + <div className="h-3" /> 26 + <p className="text-left w-full"> 27 + {summary.length > 100 ? summary.substring(0, 100) + "..." : summary} 28 + </p> 29 + </div> 30 + </Link> 31 + </> 32 + ); 33 + }
+26
react/src/components/BlogPostList.tsx
··· 1 + import type { BlogPost } from "../lib/post"; 2 + import { BlogPostItem } from "./BlogPostItem"; 3 + 4 + export function BlogPostList({ posts }: { posts: BlogPost[] }) { 5 + if (!posts.length) { 6 + return <p className="text-lg text-center">No blog posts available</p>; 7 + } 8 + return ( 9 + <div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 items-center justify-center gap-5"> 10 + {posts 11 + .sort( 12 + (a, b) => 13 + new Date(b.datePosted).getTime() - new Date(a.datePosted).getTime(), 14 + ) 15 + .map((post, idx) => ( 16 + <BlogPostItem 17 + key={idx} 18 + idx={post.id} 19 + title={post.title} 20 + summary={post.summary} 21 + datePosted={post.datePosted} 22 + /> 23 + ))} 24 + </div> 25 + ); 26 + }
+22
react/src/index.css
··· 1 + @import "tailwindcss"; 2 + :root { 3 + font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; 4 + line-height: 1.5; 5 + font-weight: 400; 6 + 7 + color-scheme: light dark; 8 + color: rgba(255, 255, 255, 0.87); 9 + background-color: #242424; 10 + 11 + font-synthesis: none; 12 + text-rendering: optimizeLegibility; 13 + -webkit-font-smoothing: antialiased; 14 + -moz-osx-font-smoothing: grayscale; 15 + } 16 + 17 + @media (prefers-color-scheme: light) { 18 + :root { 19 + color: #213547; 20 + background-color: #ffffff; 21 + } 22 + }
+39
react/src/lib/post.ts
··· 1 + export interface BlogPost { 2 + id: number; 3 + datePosted: string; 4 + title: string; 5 + author: string; 6 + summary: string; 7 + content: string; 8 + } 9 + 10 + export const posts: BlogPost[] = [ 11 + { 12 + id: 0, 13 + datePosted: "2025-11-15", 14 + title: "My First Blog Post", 15 + author: "Samuel Shuert", 16 + summary: "First blog post", 17 + content: 18 + "This is my first blog post. I am excited to share my thoughts with the world! lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", 19 + }, 20 + { 21 + id: 1, 22 + datePosted: "2025-11-17", 23 + title: "My Second Blog Post", 24 + author: "Samuel Shuert", 25 + summary: "Another post", 26 + content: 27 + "This is my second blog post. I am excited to share my thoughts with the world!", 28 + }, 29 + { 30 + id: 2, 31 + datePosted: "2025-11-18", 32 + title: "My Third Blog Post", 33 + author: "Samuel Shuert", 34 + summary: 35 + "The third blog post lorem ipsum dolor sit amet consectetur adipiscing elit The third blog post lorem ipsum dolor sit amet consectetur adipiscing elit", 36 + content: 37 + "This is my third blog post. I am excited to share my thoughts with the world!", 38 + }, 39 + ];
+32
react/src/main.tsx
··· 1 + import { StrictMode } from "react"; 2 + import { createRoot } from "react-dom/client"; 3 + import { BrowserRouter, Routes, Route } from "react-router"; 4 + import "./index.css"; 5 + import { App } from "./App.tsx"; 6 + import { BlogPostDetail, PostLayout } from "./components/BlogPostDetail.tsx"; 7 + import { NewPostLayout } from "./components/BlogPostForm.tsx"; 8 + import { posts } from "./lib/post.ts"; 9 + 10 + const deletePost = (postId: number) => { 11 + const index = posts.findIndex((post) => post.id === postId); 12 + if (index !== -1) { 13 + posts.splice(index, 1); 14 + } 15 + }; 16 + 17 + createRoot(document.getElementById("root")!).render( 18 + <StrictMode> 19 + <BrowserRouter> 20 + <Routes> 21 + <Route index element={<App />} /> 22 + <Route path="entries" element={<PostLayout />}> 23 + <Route 24 + path=":postId" 25 + element={<BlogPostDetail deletePost={deletePost} />} 26 + /> 27 + </Route> 28 + <Route path="post" element={<NewPostLayout />} /> 29 + </Routes> 30 + </BrowserRouter> 31 + </StrictMode>, 32 + );
+28
react/tsconfig.app.json
··· 1 + { 2 + "compilerOptions": { 3 + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 4 + "target": "ES2022", 5 + "useDefineForClassFields": true, 6 + "lib": ["ES2022", "DOM", "DOM.Iterable"], 7 + "module": "ESNext", 8 + "types": ["vite/client", "@types/bun"], 9 + "skipLibCheck": true, 10 + 11 + /* Bundler mode */ 12 + "moduleResolution": "bundler", 13 + "allowImportingTsExtensions": true, 14 + "verbatimModuleSyntax": true, 15 + "moduleDetection": "force", 16 + "noEmit": true, 17 + "jsx": "react-jsx", 18 + 19 + /* Linting */ 20 + "strict": true, 21 + "noUnusedLocals": true, 22 + "noUnusedParameters": true, 23 + "erasableSyntaxOnly": true, 24 + "noFallthroughCasesInSwitch": true, 25 + "noUncheckedSideEffectImports": true 26 + }, 27 + "include": ["src"] 28 + }
+7
react/tsconfig.json
··· 1 + { 2 + "files": [], 3 + "references": [ 4 + { "path": "./tsconfig.app.json" }, 5 + { "path": "./tsconfig.node.json" } 6 + ] 7 + }
+26
react/tsconfig.node.json
··· 1 + { 2 + "compilerOptions": { 3 + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 4 + "target": "ES2023", 5 + "lib": ["ES2023"], 6 + "module": "ESNext", 7 + "types": ["@types/bun"], 8 + "skipLibCheck": true, 9 + 10 + /* Bundler mode */ 11 + "moduleResolution": "bundler", 12 + "allowImportingTsExtensions": true, 13 + "verbatimModuleSyntax": true, 14 + "moduleDetection": "force", 15 + "noEmit": true, 16 + 17 + /* Linting */ 18 + "strict": true, 19 + "noUnusedLocals": true, 20 + "noUnusedParameters": true, 21 + "erasableSyntaxOnly": true, 22 + "noFallthroughCasesInSwitch": true, 23 + "noUncheckedSideEffectImports": true 24 + }, 25 + "include": ["vite.config.ts"] 26 + }
+21
react/vite.config.ts
··· 1 + import { defineConfig } from "vite"; 2 + import react from "@vitejs/plugin-react"; 3 + import tailwindcss from "@tailwindcss/vite"; 4 + 5 + // https://vite.dev/config/ 6 + export default defineConfig({ 7 + define: { 8 + global: "globalThis", 9 + }, 10 + server: { 11 + allowedHosts: ["project.coded.codes"], 12 + }, 13 + plugins: [ 14 + react({ 15 + babel: { 16 + plugins: [["babel-plugin-react-compiler"]], 17 + }, 18 + }), 19 + tailwindcss(), 20 + ], 21 + });
+34
server/.gitignore
··· 1 + # dependencies (bun install) 2 + node_modules 3 + 4 + # output 5 + out 6 + dist 7 + *.tgz 8 + 9 + # code coverage 10 + coverage 11 + *.lcov 12 + 13 + # logs 14 + logs 15 + _.log 16 + report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json 17 + 18 + # dotenv environment variable files 19 + .env 20 + .env.development.local 21 + .env.test.local 22 + .env.production.local 23 + .env.local 24 + 25 + # caches 26 + .eslintcache 27 + .cache 28 + *.tsbuildinfo 29 + 30 + # IntelliJ based IDEs 31 + .idea 32 + 33 + # Finder (MacOS) folder config 34 + .DS_Store
+15
server/README.md
··· 1 + # server 2 + 3 + To install dependencies: 4 + 5 + ```bash 6 + bun install 7 + ``` 8 + 9 + To run: 10 + 11 + ```bash 12 + bun run index.ts 13 + ``` 14 + 15 + This project was created using `bun init` in bun v1.2.22. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
+1
server/books.json
··· 1 + [{"id":"9780553212471","title":"Frankenstein","author":"Mary Shelley"},{"id":"9780060935467","title":"To Kill a Mockingbird","author":"Harper Lee"},{"id":"9780141439518","title":"Pride and Prejudice","author":"Jane Austen"}]
+288
server/books.ts
··· 1 + import express, { 2 + type NextFunction, 3 + type Request, 4 + type Response, 5 + } from "express"; 6 + import { writeFile, readFile, exists } from "fs/promises"; 7 + 8 + const ISBN13 = 9 + /^(?:ISBN(?:-13)?:? )?(?=[0-9]{13}$|(?=(?:[0-9]+[- ]){4})[- 0-9]{17}$)[\d-]+$/; 10 + 11 + interface Book { 12 + id: string; 13 + title: string; 14 + author: string; 15 + } 16 + 17 + const initBooks: () => Promise<void> = async () => { 18 + await writeFile( 19 + "books.json", 20 + JSON.stringify([ 21 + { 22 + id: "9780553212471", 23 + title: "Frankenstein", 24 + author: "Mary Shelley", 25 + }, 26 + { 27 + id: "9780060935467", 28 + title: "To Kill a Mockingbird", 29 + author: "Harper Lee", 30 + }, 31 + { 32 + id: "9780141439518", 33 + title: "Pride and Prejudice", 34 + author: "Jane Austen", 35 + }, 36 + ]), 37 + ); 38 + }; 39 + 40 + enum ErrorType { 41 + NotFound, 42 + InvalidId, 43 + BadData, 44 + AlreadyExists, 45 + } 46 + 47 + class BookError extends Error { 48 + public readonly status: number; 49 + constructor(err: ErrorType) { 50 + let msg: string; 51 + let st: number; 52 + switch (err) { 53 + case ErrorType.NotFound: 54 + msg = "Book {{id}} not found"; 55 + st = 404; 56 + break; 57 + case ErrorType.InvalidId: 58 + msg = "Invalid book id ({{id}}) [must be ISBN-13 formatted]"; 59 + st = 400; 60 + break; 61 + case ErrorType.BadData: 62 + msg = "Invalid book data"; 63 + st = 400; 64 + break; 65 + case ErrorType.AlreadyExists: 66 + msg = "Book with id {{id}} already exists"; 67 + st = 409; 68 + break; 69 + } 70 + super(msg); 71 + this.name = "BookError"; 72 + this.status = st; 73 + } 74 + } 75 + 76 + const getBooks: () => Promise<Book[]> = async () => { 77 + if (!(await exists("books.json"))) { 78 + await initBooks(); 79 + } 80 + const file = await readFile("books.json", "utf-8"); 81 + if (file.length < 4) { 82 + await initBooks(); 83 + return await getBooks(); 84 + } 85 + return JSON.parse(file); 86 + }; 87 + 88 + const updateBook = async (task: Book): Promise<void> => { 89 + const books = await getBooks(); 90 + const index = books.findIndex((b) => b.id === task.id); 91 + if (index !== -1) { 92 + books[index] = task; 93 + } else { 94 + books.push(task); 95 + } 96 + await writeFile("books.json", JSON.stringify(books)); 97 + }; 98 + 99 + const removeBook = async (id: string): Promise<void> => { 100 + const books = await getBooks(); 101 + const index = books.findIndex((b) => b.id === id); 102 + if (index !== -1) { 103 + books.splice(index, 1); 104 + await writeFile("books.json", JSON.stringify(books)); 105 + } 106 + }; 107 + 108 + class BadDataIssues extends Error { 109 + missingKeys: string[]; 110 + extraKeys: string[]; 111 + badValues: [string, string][]; 112 + 113 + constructor( 114 + missingKeys: string[], 115 + extraKeys: string[], 116 + badValues: [string, string][], 117 + ) { 118 + super("Bad data issues"); 119 + this.missingKeys = missingKeys; 120 + this.extraKeys = extraKeys; 121 + this.badValues = badValues; 122 + } 123 + } 124 + 125 + const keyTypes = { 126 + id: "ISBN13 code", 127 + title: "string", 128 + author: "string", 129 + }; 130 + 131 + const validateBook = (task: { [key: string]: any }): Book => { 132 + let missingKeys = ["id", "title", "author"].filter( 133 + (key) => !Object.keys(task).includes(key), 134 + ); 135 + let extraKeys = Object.keys(task).filter( 136 + (key) => !["id", "title", "author"].includes(key), 137 + ); 138 + let badValues = Object.entries(task) 139 + .filter(([key, value]) => { 140 + if (key === "id") return typeof value !== "string" || !ISBN13.test(value); 141 + if (key === "title") return typeof value !== "string"; 142 + if (key === "author") return typeof value !== "string"; 143 + return false; 144 + }) 145 + .map( 146 + ([key, _value]) => 147 + [key, keyTypes[key as keyof typeof keyTypes]] as [string, string], 148 + ); 149 + if (missingKeys.length > 0 || extraKeys.length > 0 || badValues.length > 0) { 150 + throw new BadDataIssues(missingKeys, extraKeys, badValues); 151 + } 152 + return task as Book; 153 + }; 154 + 155 + const auth = async (req: Request, res: Response, next: NextFunction) => { 156 + if (req.method === "GET") { 157 + next(); 158 + return; 159 + } 160 + if (!req.headers.authorization) { 161 + res.status(401).json({ error: "Unauthorized" }); 162 + return; 163 + } 164 + let token = req.headers.authorization.split(" ")[1]; 165 + if (token !== "password1!") { 166 + res.status(401).json({ error: "Unauthorized" }); 167 + return; 168 + } 169 + next(); 170 + }; 171 + 172 + const errorHandler = ( 173 + err: Error, 174 + _req: Request, 175 + res: Response, 176 + _next: NextFunction, 177 + ) => { 178 + if (err instanceof BookError) { 179 + let msg = err.message.replace("{{id}}", res.locals.id ?? ""); 180 + 181 + let obj: Map<string, any> = new Map<string, any>([ 182 + ["error", `${err.name}: ${msg}`], 183 + ]); 184 + 185 + if (res.locals.bdi) { 186 + if (res.locals.bdi.missingKeys.length > 0) { 187 + obj.set("missingKeys", res.locals.bdi.missingKeys); 188 + } 189 + if (res.locals.bdi.extraKeys.length > 0) { 190 + obj.set("extraKeys", res.locals.bdi.extraKeys); 191 + } 192 + if (res.locals.bdi.badValues.length > 0) { 193 + obj.set("badValues", res.locals.bdi.badValues); 194 + } 195 + } 196 + 197 + res.status(err.status).json(Object.fromEntries(obj.entries())); 198 + } else { 199 + console.error(err.stack); 200 + res.status(500).json({ error: "Internal Server Error" }); 201 + } 202 + }; 203 + 204 + const router = express.Router(); 205 + 206 + router.use(express.json()); 207 + router.use((req, res, next) => { 208 + console.log(`Recieved a ${req.method} request to ${req.url}`); 209 + next(); 210 + }); 211 + router.use(auth); 212 + 213 + router.get("/", async (_req, res) => { 214 + res.json(await getBooks()); 215 + }); 216 + 217 + router.post("/", async (req, res) => { 218 + const books = await getBooks(); 219 + try { 220 + const bookData = validateBook(req.body); 221 + res.locals.id = bookData.id; 222 + if (books.filter((b) => b.id === bookData.id).length > 0) { 223 + throw new BookError(ErrorType.AlreadyExists); 224 + } 225 + await updateBook(bookData); 226 + res.status(201).json(bookData); 227 + } catch (err) { 228 + if (err instanceof BookError) { 229 + throw err; 230 + } else if (err instanceof BadDataIssues) { 231 + res.locals.bdi = err; 232 + throw new BookError(ErrorType.BadData); 233 + } else { 234 + res.status(500).json({ error: "Internal Server Error" }); 235 + } 236 + } 237 + }); 238 + 239 + router.get("/:id", async (req, res) => { 240 + res.locals.id = req.params.id; 241 + if (!ISBN13.test(req.params.id)) { 242 + throw new BookError(ErrorType.InvalidId); 243 + } 244 + const books = await getBooks(); 245 + const book = books.find((b) => b.id == req.params.id); 246 + if (!book) throw new BookError(ErrorType.NotFound); 247 + res.json(book); 248 + }); 249 + 250 + router.put("/:id", async (req, res) => { 251 + res.locals.id = req.params.id; 252 + if (!ISBN13.test(req.params.id)) { 253 + throw new BookError(ErrorType.InvalidId); 254 + } 255 + const books = await getBooks(); 256 + const book = books.find((b) => b.id == req.params.id); 257 + if (!book) throw new BookError(ErrorType.NotFound); 258 + const bookData = validateBook(req.body); 259 + await updateBook(bookData); 260 + res.sendStatus(204); 261 + }); 262 + 263 + router.delete("/reset", async (_req, res) => { 264 + await initBooks(); 265 + res.sendStatus(204); 266 + }); 267 + 268 + router.delete("/:id", async (req, res) => { 269 + res.locals.id = req.params.id; 270 + if (!ISBN13.test(req.params.id)) { 271 + throw new BookError(ErrorType.InvalidId); 272 + } 273 + const books = await getBooks(); 274 + const book = books.find((b) => b.id == req.params.id); 275 + if (!book) throw new BookError(ErrorType.NotFound); 276 + await removeBook(book.id); 277 + res.sendStatus(204); 278 + }); 279 + 280 + router.all("/{*splat}", async (req, res) => { 281 + res 282 + .status(404) 283 + .json({ error: `path: ${req.method} at /${req.params.splat} Not Found` }); 284 + }); 285 + 286 + router.use(errorHandler); 287 + 288 + export default router;
+177
server/bun.lock
··· 1 + { 2 + "lockfileVersion": 1, 3 + "workspaces": { 4 + "": { 5 + "name": "server", 6 + "dependencies": { 7 + "@types/express": "^5.0.6", 8 + "express": "^5.2.1", 9 + }, 10 + "devDependencies": { 11 + "@types/bun": "latest", 12 + }, 13 + "peerDependencies": { 14 + "typescript": "^5", 15 + }, 16 + }, 17 + }, 18 + "packages": { 19 + "@types/body-parser": ["@types/body-parser@1.19.6", "", { "dependencies": { "@types/connect": "*", "@types/node": "*" } }, "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g=="], 20 + 21 + "@types/bun": ["@types/bun@1.3.4", "", { "dependencies": { "bun-types": "1.3.4" } }, "sha512-EEPTKXHP+zKGPkhRLv+HI0UEX8/o+65hqARxLy8Ov5rIxMBPNTjeZww00CIihrIQGEQBYg+0roO5qOnS/7boGA=="], 22 + 23 + "@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="], 24 + 25 + "@types/express": ["@types/express@5.0.6", "", { "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^5.0.0", "@types/serve-static": "^2" } }, "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA=="], 26 + 27 + "@types/express-serve-static-core": ["@types/express-serve-static-core@5.1.0", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA=="], 28 + 29 + "@types/http-errors": ["@types/http-errors@2.0.5", "", {}, "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg=="], 30 + 31 + "@types/node": ["@types/node@24.10.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ=="], 32 + 33 + "@types/qs": ["@types/qs@6.14.0", "", {}, "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ=="], 34 + 35 + "@types/range-parser": ["@types/range-parser@1.2.7", "", {}, "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ=="], 36 + 37 + "@types/send": ["@types/send@1.2.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ=="], 38 + 39 + "@types/serve-static": ["@types/serve-static@2.2.0", "", { "dependencies": { "@types/http-errors": "*", "@types/node": "*" } }, "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ=="], 40 + 41 + "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], 42 + 43 + "body-parser": ["body-parser@2.2.1", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw=="], 44 + 45 + "bun-types": ["bun-types@1.3.4", "", { "dependencies": { "@types/node": "*" } }, "sha512-5ua817+BZPZOlNaRgGBpZJOSAQ9RQ17pkwPD0yR7CfJg+r8DgIILByFifDTa+IPDDxzf5VNhtNlcKqFzDgJvlQ=="], 46 + 47 + "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], 48 + 49 + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], 50 + 51 + "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], 52 + 53 + "content-disposition": ["content-disposition@1.0.1", "", {}, "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q=="], 54 + 55 + "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], 56 + 57 + "cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], 58 + 59 + "cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="], 60 + 61 + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], 62 + 63 + "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], 64 + 65 + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], 66 + 67 + "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], 68 + 69 + "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], 70 + 71 + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], 72 + 73 + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], 74 + 75 + "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], 76 + 77 + "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], 78 + 79 + "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], 80 + 81 + "express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="], 82 + 83 + "finalhandler": ["finalhandler@2.1.1", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA=="], 84 + 85 + "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], 86 + 87 + "fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], 88 + 89 + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], 90 + 91 + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], 92 + 93 + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], 94 + 95 + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], 96 + 97 + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], 98 + 99 + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], 100 + 101 + "http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="], 102 + 103 + "iconv-lite": ["iconv-lite@0.7.0", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ=="], 104 + 105 + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], 106 + 107 + "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], 108 + 109 + "is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="], 110 + 111 + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], 112 + 113 + "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], 114 + 115 + "merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="], 116 + 117 + "mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], 118 + 119 + "mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="], 120 + 121 + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], 122 + 123 + "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], 124 + 125 + "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], 126 + 127 + "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], 128 + 129 + "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], 130 + 131 + "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], 132 + 133 + "path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="], 134 + 135 + "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], 136 + 137 + "qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="], 138 + 139 + "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], 140 + 141 + "raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="], 142 + 143 + "router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="], 144 + 145 + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], 146 + 147 + "send": ["send@1.2.0", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="], 148 + 149 + "serve-static": ["serve-static@2.2.0", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ=="], 150 + 151 + "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], 152 + 153 + "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], 154 + 155 + "side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="], 156 + 157 + "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="], 158 + 159 + "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], 160 + 161 + "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], 162 + 163 + "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], 164 + 165 + "type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="], 166 + 167 + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], 168 + 169 + "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], 170 + 171 + "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], 172 + 173 + "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], 174 + 175 + "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], 176 + } 177 + }
+13
server/index.ts
··· 1 + import express from "express"; 2 + import tasks from "./tasks.ts"; 3 + import books from "./books.ts"; 4 + 5 + const app = express(); 6 + const port = process.env["NODE_PORT"] ?? 5173; 7 + 8 + app.use("/tasks", tasks); 9 + app.use("/books", books); 10 + 11 + app.listen(port, () => { 12 + console.log(`Server listening on port ${port}`); 13 + });
+16
server/package.json
··· 1 + { 2 + "name": "server", 3 + "module": "index.ts", 4 + "type": "module", 5 + "private": true, 6 + "devDependencies": { 7 + "@types/bun": "latest" 8 + }, 9 + "peerDependencies": { 10 + "typescript": "^5" 11 + }, 12 + "dependencies": { 13 + "@types/express": "^5.0.6", 14 + "express": "^5.2.1" 15 + } 16 + }
server/tasks.json

This is a binary file and will not be displayed.

+146
server/tasks.ts
··· 1 + import express from "express"; 2 + import { readFile, writeFile, exists } from "fs/promises"; 3 + 4 + const router = express.Router(); 5 + 6 + interface Task { 7 + id: string; 8 + title: string; 9 + completed: boolean; 10 + } 11 + 12 + const getTasks: () => Promise<Task[]> = async () => { 13 + if (!(await exists("tasks.json"))) { 14 + await writeFile("tasks.json", JSON.stringify([])); 15 + } 16 + const file = await readFile("tasks.json", "utf-8"); 17 + if (file.length === 0) { 18 + return []; 19 + } 20 + return JSON.parse(file); 21 + }; 22 + 23 + const updateTask = async (task: Task): Promise<void> => { 24 + const tasks = await getTasks(); 25 + const index = tasks.findIndex((t) => t.id === task.id); 26 + if (index !== -1) { 27 + tasks[index] = task; 28 + } else { 29 + tasks.push(task); 30 + } 31 + await writeFile("tasks.json", JSON.stringify(tasks)); 32 + }; 33 + 34 + const removeTask = async (id: string): Promise<void> => { 35 + const tasks = await getTasks(); 36 + const index = tasks.findIndex((t) => t.id === id); 37 + if (index !== -1) { 38 + tasks.splice(index, 1); 39 + await writeFile("tasks.json", JSON.stringify(tasks)); 40 + } 41 + }; 42 + 43 + router.use(express.json()); 44 + 45 + router.get("/", async (_req, res) => { 46 + res.json(await getTasks()); 47 + }); 48 + 49 + router.post("/", async (req, res) => { 50 + if (!(typeof req.body.title === "string")) { 51 + res.status(400).send("Invalid title"); 52 + return; 53 + } 54 + const newTask = { 55 + id: Math.random().toString(16).substring(2, 8), 56 + title: req.body.title, 57 + completed: false, 58 + }; 59 + await updateTask(newTask); 60 + res.json(newTask).status(201); 61 + }); 62 + 63 + router.get("/:id", async (req, res) => { 64 + const task = (await getTasks()).find((t) => t.id === req.params.id); 65 + if (!task) { 66 + res.status(404).send("Task not found"); 67 + } else { 68 + res.json(task); 69 + } 70 + }); 71 + 72 + router.put("/:id", async (req, res) => { 73 + const task = (await getTasks()).find((t) => t.id === req.params.id); 74 + if (!task) { 75 + res.status(404).send("Task not found"); 76 + } else { 77 + const missing = []; 78 + if (req.body.title === undefined) missing.push("title"); 79 + if (req.body.completed === undefined) missing.push("completed"); 80 + if (missing.length > 0) { 81 + res 82 + .status(400) 83 + .send( 84 + `Missing field${missing.length > 1 ? "s" : ""}: ${missing.join(", ")}`, 85 + ); 86 + } 87 + const badTypes = []; 88 + if (!(typeof req.body.title === "string")) badTypes.push("title"); 89 + if (!(typeof req.body.completed === "boolean")) badTypes.push("completed"); 90 + if (badTypes.length > 0) { 91 + res 92 + .status(400) 93 + .send( 94 + `Invalid type${badTypes.length > 1 ? "s" : ""}: ${badTypes.join(", ")}`, 95 + ); 96 + return; 97 + } 98 + task.title = req.body.title ?? task.title; 99 + task.completed = req.body.completed ?? task.completed; 100 + await updateTask(task); 101 + res.json(task); 102 + } 103 + }); 104 + 105 + router.patch("/:id", async (req, res) => { 106 + const task = (await getTasks()).find((t) => t.id === req.params.id); 107 + if (!task) { 108 + res.status(404).send("Task not found"); 109 + } else { 110 + const badTypes = []; 111 + if ( 112 + Object.keys(req.body).includes("title") && 113 + !(typeof req.body.title === "string") 114 + ) 115 + badTypes.push("title"); 116 + if ( 117 + Object.keys(req.body).includes("completed") && 118 + !(typeof req.body.completed === "boolean") 119 + ) 120 + badTypes.push("completed"); 121 + if (badTypes.length > 0) { 122 + res 123 + .status(400) 124 + .send( 125 + `Invalid type${badTypes.length > 1 ? "s" : ""}: ${badTypes.join(", ")}`, 126 + ); 127 + return; 128 + } 129 + task.title = req.body.title ?? task.title; 130 + task.completed = req.body.completed ?? task.completed; 131 + await updateTask(task); 132 + res.json(task); 133 + } 134 + }); 135 + 136 + router.delete("/:id", async (req, res) => { 137 + const task = (await getTasks()).find((t) => t.id === req.params.id); 138 + if (!task) { 139 + res.status(404).send("Task not found"); 140 + } else { 141 + await removeTask(task.id); 142 + res.status(204).send(); 143 + } 144 + }); 145 + 146 + export default router;
+29
server/tsconfig.json
··· 1 + { 2 + "compilerOptions": { 3 + // Environment setup & latest features 4 + "lib": ["ESNext"], 5 + "target": "ESNext", 6 + "module": "Preserve", 7 + "moduleDetection": "force", 8 + "jsx": "react-jsx", 9 + "allowJs": true, 10 + 11 + // Bundler mode 12 + "moduleResolution": "bundler", 13 + "allowImportingTsExtensions": true, 14 + "verbatimModuleSyntax": true, 15 + "noEmit": true, 16 + 17 + // Best practices 18 + "strict": true, 19 + "skipLibCheck": true, 20 + "noFallthroughCasesInSwitch": true, 21 + "noUncheckedIndexedAccess": true, 22 + "noImplicitOverride": true, 23 + 24 + // Some stricter flags (disabled by default) 25 + "noUnusedLocals": false, 26 + "noUnusedParameters": false, 27 + "noPropertyAccessFromIndexSignature": false 28 + } 29 + }
+36
ts/bun.lock
··· 1 + { 2 + "lockfileVersion": 1, 3 + "workspaces": { 4 + "": { 5 + "name": "ts", 6 + "dependencies": { 7 + "glob-to-regex.js": "^1.2.0", 8 + }, 9 + "devDependencies": { 10 + "@types/bun": "latest", 11 + }, 12 + "peerDependencies": { 13 + "typescript": "^5", 14 + }, 15 + }, 16 + }, 17 + "packages": { 18 + "@types/bun": ["@types/bun@1.3.0", "", { "dependencies": { "bun-types": "1.3.0" } }, "sha512-+lAGCYjXjip2qY375xX/scJeVRmZ5cY0wyHYyCYxNcdEXrQ4AOe3gACgd4iQ8ksOslJtW4VNxBJ8llUwc3a6AA=="], 19 + 20 + "@types/node": ["@types/node@24.8.1", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q=="], 21 + 22 + "@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="], 23 + 24 + "bun-types": ["bun-types@1.3.0", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-u8X0thhx+yJ0KmkxuEo9HAtdfgCBaM/aI9K90VQcQioAmkVp3SG3FkwWGibUFz3WdXAdcsqOcbU40lK7tbHdkQ=="], 25 + 26 + "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], 27 + 28 + "glob-to-regex.js": ["glob-to-regex.js@1.2.0", "", { "peerDependencies": { "tslib": "2" } }, "sha512-QMwlOQKU/IzqMUOAZWubUOT8Qft+Y0KQWnX9nK3ch0CJg0tTp4TvGZsTfudYKv2NzoQSyPcnA6TYeIQ3jGichQ=="], 29 + 30 + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], 31 + 32 + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], 33 + 34 + "undici-types": ["undici-types@7.14.0", "", {}, "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA=="], 35 + } 36 + }
+1
ts/index.ts
··· 1 + console.log("Nothing actually here");
+6
ts/oct21/collatz.ts
··· 1 + export const collatz = (n: number): number[] => { 2 + if (n <= 0) throw new Error("Input must be a positive integer"); 3 + if (n === 2) return [2, 1]; 4 + if (n % 2 === 0) return [n, ...collatz(n / 2)]; 5 + return [n, ...collatz(3 * n + 1)]; 6 + };
+8
ts/oct21/evenDigits.ts
··· 1 + export const evenDigits = (n: number): boolean => { 2 + while (n > 0) { 3 + const digit = n % 10; 4 + if (digit % 2 !== 0) return false; 5 + n = Math.floor(n / 10); 6 + } 7 + return true; 8 + };
+6
ts/oct21/fizzBuzz.ts
··· 1 + export const fizzBuzz = (n: number): string => { 2 + if (n % 3 === 0 && n % 5 === 0) return "fizzBuzz"; 3 + if (n % 3 === 0) return "fizz"; 4 + if (n % 5 === 0) return "buzz"; 5 + return n.toString(); 6 + };
+23
ts/oct21/index.test.ts
··· 1 + import { expect, test } from "bun:test"; 2 + 3 + import { fizzBuzz } from "./fizzBuzz"; 4 + import { collatz } from "./collatz"; 5 + import { evenDigits } from "./evenDigits"; 6 + 7 + test("FizzBuzz", () => { 8 + expect(fizzBuzz(1)).toBe("1"); 9 + expect(fizzBuzz(3)).toBe("fizz"); 10 + expect(fizzBuzz(5)).toBe("buzz"); 11 + expect(fizzBuzz(15)).toBe("fizzBuzz"); 12 + }); 13 + 14 + test("Collatz", () => { 15 + expect(collatz(3)).toEqual([3, 10, 5, 16, 8, 4, 2, 1]); 16 + expect(collatz(1)).toEqual([1, 4, 2, 1]); 17 + expect(collatz(4)).toEqual([4, 2, 1]); 18 + }); 19 + 20 + test("All Even Digits", () => { 21 + expect(evenDigits(2486)).toBe(true); 22 + expect(evenDigits(1234)).toBe(false); 23 + });
+15
ts/package.json
··· 1 + { 2 + "name": "ts", 3 + "module": "index.ts", 4 + "devDependencies": { 5 + "@types/bun": "latest" 6 + }, 7 + "peerDependencies": { 8 + "typescript": "^5" 9 + }, 10 + "private": true, 11 + "type": "module", 12 + "dependencies": { 13 + "glob-to-regex.js": "^1.2.0" 14 + } 15 + }
+48
ts/searchEngine/crawler.test.ts
··· 1 + import { describe, it, beforeEach, expect } from "bun:test"; 2 + import { SearchIndex } from "."; 3 + import { Crawler, RobotsParser } from "./crawler"; 4 + import { sleep } from "bun"; 5 + 6 + describe("Robots Parser", () => { 7 + it("should parse robots.txt file", () => { 8 + const robotsTxt = ` 9 + User-agent: * 10 + User-agent: crawl 11 + Disallow: /admin 12 + Allow: /public 13 + 14 + User-Agent: crawl 15 + Disallow: /no-robots 16 + `; 17 + const robotsParser = new RobotsParser(robotsTxt); 18 + const { allows, disallows } = robotsParser.getUrlsForUA("crawl"); 19 + const urls = { 20 + allows, 21 + disallows, 22 + }; 23 + expect(allows.has("/public")).toBe(true); 24 + expect(disallows.has("/admin")).toBe(true); 25 + expect(RobotsParser.checkUserAgent(urls, "/admin")).toBe(false); 26 + expect(RobotsParser.checkUserAgent(urls, "/public")).toBe(true); 27 + }); 28 + }); 29 + 30 + describe("Crawler", () => { 31 + let crawler: Crawler; 32 + beforeEach(() => { 33 + crawler = new Crawler("SmartFridge", new SearchIndex()); 34 + }); 35 + 36 + it("should crawl a page", () => { 37 + const url = new URL("https://google.com"); 38 + crawler.crawl(url); 39 + crawler.on("storePage", (url) => { 40 + console.log(`Page stored: ${url}`); 41 + sleep(4000).then(() => { 42 + crawler.emit("stop"); 43 + expect(crawler.index.size()).toBe(1); 44 + }); 45 + }); 46 + // expect(crawler.index).toBe(1); 47 + }); 48 + });
+211
ts/searchEngine/crawler.ts
··· 1 + import { SearchIndex } from "."; 2 + import { toRegex } from "glob-to-regex.js"; 3 + import { EventEmitter } from "node:events"; 4 + 5 + interface RobotUrls { 6 + allows: Set<string>; 7 + disallows: Set<string>; 8 + } 9 + 10 + export class RobotsParser { 11 + disallow: Map<string, Set<string>> = new Map(); 12 + allow: Map<string, Set<string>> = new Map(); 13 + 14 + constructor(text: string) { 15 + const lines = text 16 + .split("\n") 17 + .filter((l) => !/^\s*#.*$/.test(l)) // remove full-line comments 18 + .map((l) => l.replace(/\s*#.*$/, "")); // remove end-of-line comments 19 + lines.push(""); 20 + 21 + const blocks: Array<Array<string>> = []; 22 + let current_block: Array<string> = []; 23 + lines.forEach((line) => { 24 + if (line == "") { 25 + if (current_block.length == 0) return; // ignore consecutive empty lines 26 + blocks.push(current_block); 27 + current_block = new Array(); 28 + } else { 29 + current_block.push(line); 30 + } 31 + }); 32 + 33 + blocks.forEach((block) => { 34 + let uas: string[] = []; 35 + let disallows: string[] = []; 36 + let allows: string[] = []; 37 + block.forEach((line) => { 38 + line = line.trim().toLowerCase(); 39 + const fields: Array<string> = line.split(/\s*:\s*/); 40 + if (fields.length < 2) return; 41 + if (fields[0] == "user-agent") { 42 + uas.push(fields[1]!); 43 + } else if (fields[0] == "disallow") { 44 + disallows.push(fields[1]!); 45 + } else if (fields[0] == "allow") { 46 + allows.push(fields[1]!); 47 + } 48 + }); 49 + uas.forEach((ua) => { 50 + ua = ua.toLowerCase(); 51 + this.disallow.set( 52 + ua, 53 + new Set([...(this.disallow.get(ua) || []), ...disallows]), 54 + ); 55 + this.allow.set( 56 + ua, 57 + new Set([...(this.allow.get(ua) || []), ...allows]), 58 + ); 59 + }); 60 + }); 61 + } 62 + 63 + static checkUserAgent(urls: RobotUrls, url: string): boolean { 64 + const { allows, disallows } = urls; 65 + const allowed = allows 66 + .values() 67 + .map((allow) => { 68 + const regex = toRegex(allow); 69 + return regex.test(url); 70 + }) 71 + .reduce((acc, curr) => acc || curr, false); 72 + if (allowed) { 73 + return true; 74 + } 75 + const disallowed = disallows 76 + .values() 77 + .map((disallow) => { 78 + const regex = toRegex(disallow); 79 + return regex.test(url); 80 + }) 81 + .reduce((acc, curr) => acc || curr, false); 82 + return !disallowed; 83 + } 84 + 85 + getUrlsForUA(ua: string): RobotUrls { 86 + ua = ua.toLowerCase(); 87 + const allowUAs = this.allow 88 + .keys() 89 + .filter((key) => toRegex(key).test(ua)); 90 + const disallowUAs = this.disallow 91 + .keys() 92 + .filter((key) => toRegex(key).test(ua)); 93 + let allows = new Set<string>(); 94 + let disallows = new Set<string>(); 95 + 96 + allowUAs.forEach((ua) => { 97 + const allow = this.allow.get(ua); 98 + if (allow) { 99 + allows = allows.union(allow); 100 + } 101 + }); 102 + disallowUAs.forEach((ua) => { 103 + const disallow = this.disallow.get(ua); 104 + if (disallow) { 105 + disallows = disallows.union(disallow); 106 + } 107 + }); 108 + return { 109 + allows, 110 + disallows, 111 + }; 112 + } 113 + } 114 + 115 + const urlRegex = /https?:\/\/[^\s\"]+/g; 116 + export class Crawler extends EventEmitter { 117 + private robots: Map<string, RobotUrls> = new Map(); // hostname, robots allowed and disallowed for the sepcified UA 118 + private visited: Set<URL> = new Set(); // URLS 119 + 120 + constructor( 121 + private readonly UA: string, 122 + public index: SearchIndex, 123 + ) { 124 + super(); 125 + this.on("addURL", (url: URL) => { 126 + console.log(`Adding URL: ${url}`); 127 + void this.processPage(url); 128 + }); 129 + this.once("stop", () => { 130 + this.removeAllListeners(); 131 + }); 132 + } 133 + 134 + private async checkDisallowed(url: URL): Promise<boolean> { 135 + const robots = 136 + this.robots.get(url.hostname) || (await this.getRobotsTxt(url)); 137 + return !RobotsParser.checkUserAgent(robots, url.toString()); 138 + } 139 + 140 + private async getRobotsTxt(url: URL): Promise<RobotUrls> { 141 + const robotsTxtUrl = new URL( 142 + `${url.protocol}//${url.hostname}/robots.txt`, 143 + ); 144 + 145 + const response = await fetch(robotsTxtUrl, { 146 + headers: { 147 + "User-Agent": this.UA, 148 + }, 149 + }); 150 + if (response.status !== 200) 151 + return { allows: new Set(), disallows: new Set() }; 152 + if (!response.headers.get("content-type")?.startsWith("text/plain")) 153 + return { allows: new Set(), disallows: new Set() }; 154 + const robotsTxt = await response.text(); 155 + const parsed = new RobotsParser(robotsTxt); 156 + const forUA = parsed.getUrlsForUA(this.UA); 157 + this.robots.set(url.hostname, forUA); 158 + return forUA; 159 + } 160 + 161 + private async addOutlinks(html: string): Promise<void> { 162 + const links = html.matchAll(urlRegex); 163 + if (!links) return; 164 + for (const [link, ..._] of links) { 165 + console.log(link); 166 + const url = new URL(link); 167 + if (await this.checkDisallowed(url)) { 168 + this.emit("addURL", url); 169 + } 170 + } 171 + } 172 + 173 + // private getText(html: string): string { 174 + // const parser = new DOMParser(); 175 + // const doc = parser.parseFromString(html, "text/html"); 176 + // return doc.body.textContent || ""; 177 + // } 178 + 179 + private async getPage(url: URL) { 180 + if (this.visited.has(url)) return; 181 + if (await this.checkDisallowed(url)) return; 182 + const page = await fetch(url); 183 + this.visited.add(url); 184 + if (!page.ok) return; 185 + if (!page.headers.get("Content-Type")?.startsWith("text/html")) return; 186 + 187 + return await page.text(); 188 + } 189 + 190 + private async processPage(url: URL) { 191 + const page = await this.getPage(url); 192 + if (!page) return; 193 + await this.addOutlinks(page); 194 + this.index.addPage(url.toString(), page); 195 + this.emit("storePage", url); 196 + } 197 + 198 + crawl(url_str: string | URL) { 199 + this.emit("addURL", new URL(url_str)); 200 + } 201 + } 202 + 203 + let crawler = new Crawler("SmartFridge", new SearchIndex()); 204 + 205 + const url = new URL("https://example.com"); 206 + crawler.crawl(url); 207 + crawler.on("storePage", (url) => { 208 + console.log(`Page stored: ${url}`); 209 + console.log("entries:", crawler.index.size()); 210 + crawler.emit("stop"); 211 + });
+138
ts/searchEngine/index.test.ts
··· 1 + import { describe, it, beforeEach, expect } from "bun:test"; 2 + import { SearchIndex } from "."; 3 + import { Crawler } from "./crawler"; 4 + 5 + describe("Search Index", () => { 6 + let index: SearchIndex; 7 + beforeEach(() => { 8 + index = new SearchIndex(); 9 + }); 10 + 11 + it("should add a new page to the index", () => { 12 + index.addPage( 13 + "https://www.example.com", 14 + "This is a sample webpage about dogs", 15 + ); 16 + expect(index.getPagesForKeyword("dogs")).toContain( 17 + "https://www.example.com", 18 + ); 19 + }); 20 + it("should return an empty list for the keyword", () => { 21 + expect(index.getPagesForKeyword("pineapple")).toBeEmpty(); 22 + }); 23 + it("should update a page in the index", () => { 24 + index.addPage( 25 + "https://www.example.com", 26 + "This is a sample web page about dogs", 27 + ); 28 + index.updatePage( 29 + "https://www.example.com", 30 + "This is a sample web page about cats", 31 + ); 32 + expect(index.getPagesForKeyword("dogs")).not.toContain( 33 + "https://www.example.com", 34 + ); 35 + expect(index.getPagesForKeyword("cats")).toContain( 36 + "https://www.example.com", 37 + ); 38 + }); 39 + it("should remove a page from the index", () => { 40 + index.addPage( 41 + "https://www.example.com", 42 + "This is a sample web page about cats", 43 + ); 44 + index.removePage("https://www.example.com"); 45 + expect(index.getPagesForKeyword("cats")).not.toContain( 46 + "https://www.example.com", 47 + ); 48 + }); 49 + it("should return relevant pages for a keyword", () => { 50 + index.addPage( 51 + "https://www.example.com", 52 + "This is a sample web page about cats", 53 + ); 54 + expect(index.getPagesForKeyword("cats")).toContain( 55 + "https://www.example.com", 56 + ); 57 + }); 58 + it("should return multiple relavent pages that share a keyword", () => { 59 + index.addPage( 60 + "https://www.pineapple-world.com", 61 + "We have lots of pineapples. You've never seen this many pineapples before.", 62 + ); 63 + index.addPage( 64 + "https://www.pineapple-is-my-favorite-fruit.com", 65 + "I love pineapples, it's all I eat. I mean I REALLY LOVE PINEAPPLES", 66 + ); 67 + 68 + expect(index.getPagesForKeyword("pineapples")).toBeArrayOfSize(2); 69 + }); 70 + }); 71 + 72 + describe("Search Algorithm", () => { 73 + let index: SearchIndex; 74 + beforeEach(() => { 75 + index = new SearchIndex(); 76 + index.addPage( 77 + "https://www.beans.com", 78 + "beans beans beans beans beans beans beans beans beans beans beans beans beans beans beans beans beans beans beans beans beans beans beans beans beans beans", 79 + ); 80 + index.addPage("https://www.beans-are-ok.com", "beans are ok I guess"); 81 + index.addPage("https://testsite.com", "beans"); 82 + index.addPage( 83 + "https://www.example.com/cats", 84 + "This is a sample web page about cats", 85 + ); 86 + index.addPage( 87 + "https://www.example.com/dogs", 88 + "This is a sample web page about dogs and training", 89 + ); 90 + index.addPage( 91 + "https://www.training.com", 92 + "This is a general training website", 93 + ); 94 + index.addPage( 95 + "https://www.pineapple-world.com", 96 + "We have lots of pineapples. You've never seen this many pineapples before.", 97 + ); 98 + index.addPage( 99 + "https://www.pineapple-is-my-favorite-fruit.com", 100 + "I love pineapples, it's all I eat. I mean I REALLY LOVE PINEAPPLES", 101 + ); 102 + index.addPage( 103 + "https://www.example.com/ml", 104 + "This is a page about machine learning", 105 + ); 106 + }); 107 + 108 + it("should return relevant pages for a single keyword search", () => { 109 + const results = index.search("cats"); 110 + expect(results).toContain("https://www.example.com/cats"); 111 + }); 112 + 113 + it("should return relevant pages for a multi keyword search", () => { 114 + const results = index.search("dogs training"); 115 + expect(results).toContainAllValues([ 116 + "https://www.example.com/dogs", 117 + "https://www.training.com", 118 + ]); 119 + expect(results.indexOf("https://www.example.com/dogs")).toBe(0); 120 + expect(results.indexOf("https://www.training.com")).toBe(1); 121 + }); 122 + 123 + it("should return relevant pages for a phrase search", () => { 124 + const results = index.search("machine learning"); 125 + expect(results).toContain("https://www.example.com/ml"); 126 + }); 127 + 128 + it("should rank results properly by relevance", () => { 129 + const results = index.search("beans"); 130 + expect(results.indexOf("https://www.beans.com")).toBe(0); 131 + expect(results.indexOf("https://www.beans-are-ok.com")).toBe(1); 132 + expect(results.indexOf("https://testsite.com")).toBe(2); 133 + const results2 = index.search("beans beans"); 134 + expect(results2.indexOf("https://www.beans.com")).toBe(0); 135 + expect(results2.indexOf("https://www.beans-are-ok.com")).toBe(1); 136 + expect(results.indexOf("https://testsite.com")).toBe(2); 137 + }); 138 + });
+221
ts/searchEngine/index.ts
··· 1 + const articles = ["a", "an", "the", "this"]; 2 + 3 + const prepositions = [ 4 + "in", 5 + "on", 6 + "at", 7 + "to", 8 + "from", 9 + "by", 10 + "with", 11 + "for", 12 + "of", 13 + ]; 14 + 15 + const conjunctions = ["and", "or", "but", "yet", "so"]; 16 + 17 + const pronouns = ["i", "me", "he", "she", "it", "we", "they", "you"]; 18 + 19 + const auxiliaryVerbs = [ 20 + "is", 21 + "are", 22 + "am", 23 + "be", 24 + "been", 25 + "being", 26 + "has", 27 + "have", 28 + "had", 29 + "do", 30 + "does", 31 + "did", 32 + ]; 33 + 34 + const commonVerbs = ["go", "get", "make", "take", "see", "come", "think"]; 35 + 36 + const adverbs = ["very", "more", "most", "also", "just", "only"]; 37 + 38 + const otherCommon = [ 39 + "not", 40 + "no", 41 + "yes", 42 + "some", 43 + "any", 44 + "all", 45 + "each", 46 + "every", 47 + "what", 48 + "which", 49 + "who", 50 + "when", 51 + "where", 52 + "why", 53 + "how", 54 + ]; 55 + 56 + const contractions = [ 57 + "its", 58 + "youve", 59 + "youre", 60 + "weve", 61 + "were", 62 + "itd", 63 + "youd", 64 + "yall", 65 + ]; 66 + 67 + const stopWords = new Set([ 68 + ...articles, 69 + ...prepositions, 70 + ...adverbs, 71 + ...otherCommon, 72 + ...commonVerbs, 73 + ...conjunctions, 74 + ...pronouns, 75 + ...auxiliaryVerbs, 76 + ...contractions, 77 + ]); 78 + 79 + export class SearchIndex { 80 + private index: Map<string, [string, number][]>; 81 + 82 + constructor() { 83 + this.index = new Map<string, [string, number][]>(); 84 + } 85 + 86 + private getPhrases( 87 + words: string[], 88 + filter: boolean[], 89 + ): Map<string, number> { 90 + const wordGroups: string[][] = []; 91 + let currentSlice: string[] = []; 92 + for (const [index, val] of filter.entries()) { 93 + if (val) { 94 + currentSlice.push(words[index]!); 95 + continue; 96 + } 97 + if (currentSlice.length > 1) wordGroups.push(currentSlice); 98 + currentSlice = []; 99 + } 100 + const subPhrases: string[] = wordGroups.flatMap((group) => 101 + this.getSubPhrases(group), 102 + ); 103 + const subPhraseDict = new Map<string, number>(); 104 + for (const sp of subPhrases) { 105 + subPhraseDict.set(sp, (subPhraseDict.get(sp) || 0) + 1); 106 + } 107 + return subPhraseDict; 108 + } 109 + 110 + private getSubPhrases(phrase: string[]): string[] { 111 + const subPhrases: string[] = [phrase.join(" ")]; 112 + for (let i = 2; i < phrase.length; i++) { 113 + for (let offset = 0; offset + i < phrase.length + 1; offset++) { 114 + const subPhrase = phrase.slice(offset, offset + i).join(" "); 115 + subPhrases.push(subPhrase); 116 + } 117 + } 118 + return subPhrases; 119 + } 120 + 121 + private extractKeywords(pageContent: string): Map<string, number> { 122 + let words: string[] = pageContent 123 + .split(/\s+/) 124 + .map((str) => str.replaceAll(/[^\w]+/g, "").toLowerCase()) 125 + .filter((str) => str.length > 0); 126 + words = [...words, "a"]; 127 + const filter = words.map((word) => !stopWords.has(word)); 128 + const keywords = new Set<string>(words).difference(stopWords); 129 + const keywordMap = new Map<string, number>( 130 + keywords.values().map((kw) => [kw, 0]), 131 + ); 132 + 133 + for (let word of words) { 134 + if (keywords.has(word)) { 135 + keywordMap.set(word, (keywordMap.get(word) || 0) + 1); 136 + } 137 + } 138 + const phrases = this.getPhrases(words, filter); 139 + return new Map([...keywordMap, ...phrases]); 140 + } 141 + 142 + addPage(url: string, pageContent: string): void { 143 + let keywords = this.extractKeywords(pageContent); 144 + for (let [kw, count] of keywords.entries()) { 145 + if (this.index.has(kw)) { 146 + let prev = this.index.get(kw)!; 147 + prev.push([url, count]); 148 + this.index.set(kw, prev); 149 + } else { 150 + this.index.set(kw, [[url, count]]); 151 + } 152 + } 153 + } 154 + 155 + updatePage(url: string, pageContent: string): void { 156 + this.removePage(url); 157 + this.addPage(url, pageContent); 158 + } 159 + 160 + removePage(url: string): void { 161 + this.index.entries().forEach(([keyword, urls]) => { 162 + const index = urls.findIndex(([u, _]) => u === url); 163 + if (index >= 0) { 164 + urls.splice(index, 1); 165 + if (urls.length === 0) { 166 + this.index.delete(keyword); 167 + } 168 + } 169 + }); 170 + } 171 + 172 + checkPage(search: string): boolean { 173 + for (const urls of this.index.values()) { 174 + for (const [url, _] of urls) { 175 + if (search === url) { 176 + return true; 177 + } 178 + } 179 + } 180 + return false; 181 + } 182 + 183 + size() { 184 + return this.index.size; 185 + } 186 + 187 + getPagesForKeyword(keyword: string): string[] { 188 + const pages = this.index.get(keyword); 189 + if (!pages) { 190 + return []; 191 + } 192 + return Array.from(pages) 193 + .sort((a, b) => a[1] - b[1]) 194 + .map(([url, _]) => url); 195 + } 196 + 197 + search(query: string): string[] { 198 + const urls = new Map<string, number>(); 199 + const keys = this.extractKeywords(query); 200 + for (const [key, count] of keys.entries()) { 201 + const pages = this.index.get(key); 202 + if (!pages) continue; 203 + for (const [url, v] of pages) { 204 + urls.set( 205 + url, 206 + urls.has(url) 207 + ? (urls.get(url) || 0) + v * count 208 + : v * count, 209 + ); 210 + } 211 + } 212 + urls.forEach((value, key) => { 213 + if (key.includes(query)) { 214 + value += 10; 215 + } 216 + }); 217 + return Array.from(urls.entries()) 218 + .sort((a, b) => b[1] - a[1]) 219 + .map(([url, _]) => url); 220 + } 221 + }
ts/searchEngine/mainLoop.plan

This is a binary file and will not be displayed.

+29
ts/tsconfig.json
··· 1 + { 2 + "compilerOptions": { 3 + // Environment setup & latest features 4 + "lib": ["ESNext"], 5 + "target": "ESNext", 6 + "module": "Preserve", 7 + "moduleDetection": "force", 8 + "jsx": "react-jsx", 9 + "allowJs": true, 10 + 11 + // Bundler mode 12 + "moduleResolution": "bundler", 13 + "allowImportingTsExtensions": true, 14 + "verbatimModuleSyntax": true, 15 + "noEmit": true, 16 + 17 + // Best practices 18 + "strict": true, 19 + "skipLibCheck": true, 20 + "noFallthroughCasesInSwitch": true, 21 + "noUncheckedIndexedAccess": true, 22 + "noImplicitOverride": true, 23 + 24 + // Some stricter flags (disabled by default) 25 + "noUnusedLocals": false, 26 + "noUnusedParameters": false, 27 + "noPropertyAccessFromIndexSignature": false 28 + } 29 + }