init commit
							
								
								
									
										35
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,35 @@ | |||||||
|  | # PATLITE light tower controller | ||||||
|  |  | ||||||
|  | ## frontend | ||||||
|  |  | ||||||
|  | setup | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | cp .env.exmaple .env | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | build | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | cd frontend | ||||||
|  | yarn | ||||||
|  | yarn build | ||||||
|  |  | ||||||
|  | # docker build | ||||||
|  | build -t patlite-light-tower-controller . | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ## server | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | cd server | ||||||
|  | virtualenv env | ||||||
|  | source env/bin/activate | ||||||
|  |  | ||||||
|  | pip3 install -r requirements.txt | ||||||
|  | python3 main.py | ||||||
|  |  | ||||||
|  | or | ||||||
|  |  | ||||||
|  | python3 --server main.py | ||||||
|  | ``` | ||||||
							
								
								
									
										
											BIN
										
									
								
								assets/screenshot.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 121 KiB | 
							
								
								
									
										4
									
								
								frontend/.env.example
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,4 @@ | |||||||
|  | VITE_APP_TITLE=Patlite Status Light Controller | ||||||
|  | VITE_DEVICE_URL=http://localhost:5000 | ||||||
|  | VITE_DEVICE_PATH=/api/ | ||||||
|  | VITE_GITHUB_SOURCE=https://github.com/kevinmidboe/patlite-controller | ||||||
							
								
								
									
										4
									
								
								frontend/.prettierrc
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,4 @@ | |||||||
|  | { | ||||||
|  |   "plugins": ["prettier-plugin-svelte"], | ||||||
|  |   "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] | ||||||
|  | } | ||||||
							
								
								
									
										28
									
								
								frontend/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,28 @@ | |||||||
|  | # Stage 1: Build the frontend | ||||||
|  | FROM node:18 AS builder | ||||||
|  |  | ||||||
|  | # Set working directory | ||||||
|  | WORKDIR /app | ||||||
|  |  | ||||||
|  | # Copy required config and lock files | ||||||
|  | COPY package.json yarn.lock svelte.config.js vite.config.js ./ | ||||||
|  |  | ||||||
|  | # Install dependencies | ||||||
|  | RUN yarn install | ||||||
|  |  | ||||||
|  | # Copy the rest of the source files | ||||||
|  | COPY . . | ||||||
|  |  | ||||||
|  | # Build the frontend | ||||||
|  | RUN yarn build | ||||||
|  |  | ||||||
|  | # Stage 2: Serve with Caddy | ||||||
|  | FROM caddy:2-alpine | ||||||
|  |  | ||||||
|  | # Set working directory | ||||||
|  | WORKDIR /usr/share/caddy | ||||||
|  |  | ||||||
|  | # Copy the build output from the previous stage | ||||||
|  | COPY --from=builder /app/dist /usr/share/caddy | ||||||
|  |  | ||||||
|  | CMD ["caddy", "file-server", "--root", "/usr/share/caddy", "--listen", ":80"] | ||||||
							
								
								
									
										14
									
								
								frontend/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,14 @@ | |||||||
|  | <!doctype html> | ||||||
|  | <html lang="en"> | ||||||
|  |   <head> | ||||||
|  |     <meta charset="UTF-8" /> | ||||||
|  |     <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||||||
|  |     <title>Svelte App</title> | ||||||
|  |  | ||||||
|  |     <link rel="stylesheet" href="./style.scss" /> | ||||||
|  |   </head> | ||||||
|  |   <body> | ||||||
|  |     <div id="app"></div> | ||||||
|  |     <script type="module" src="/src/main.js"></script> | ||||||
|  |   </body> | ||||||
|  | </html> | ||||||
							
								
								
									
										19
									
								
								frontend/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,19 @@ | |||||||
|  | { | ||||||
|  |   "name": "my-svelte-app", | ||||||
|  |   "type": "module", | ||||||
|  |   "version": "1.0.0", | ||||||
|  |   "scripts": { | ||||||
|  |     "dev": "vite", | ||||||
|  |     "build": "vite build", | ||||||
|  |     "preview": "vite preview" | ||||||
|  |   }, | ||||||
|  |   "devDependencies": { | ||||||
|  |     "@sveltejs/vite-plugin-svelte": "^2.0.0", | ||||||
|  |     "prettier": "^3.5.3", | ||||||
|  |     "prettier-plugin-svelte": "^3.3.3", | ||||||
|  |     "sass": "^1.86.3", | ||||||
|  |     "svelte": "5.28.1", | ||||||
|  |     "svelte-preprocess": "^6.0.3", | ||||||
|  |     "vite": "^5.0.0" | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										
											BIN
										
									
								
								frontend/public/fonts/IBMPlexSerif-SemiBoldItalic.ttf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										66
									
								
								frontend/public/style.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,66 @@ | |||||||
|  | @font-face { | ||||||
|  |   font-family: 'ibm-plex'; | ||||||
|  |   src: url('./fonts/IBMPlexSerif-SemiBoldItalic.ttf') format('truetype'); | ||||||
|  |   font-weight: 500; | ||||||
|  |   font-style: italic; | ||||||
|  |   font-display: swap; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | body { | ||||||
|  |   font-family: Arial, sans-serif; | ||||||
|  |   background-color: #f0f0f0; | ||||||
|  |   margin: 0; | ||||||
|  |   padding: 0; | ||||||
|  |   display: flex; | ||||||
|  |   justify-content: center; | ||||||
|  |   align-items: center; | ||||||
|  |   min-height: 100vh; | ||||||
|  |   height: 100%; | ||||||
|  |   position: relative; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .container { | ||||||
|  |   display: flex; | ||||||
|  |   flex-direction: column; | ||||||
|  |   justify-content: space-between; | ||||||
|  |   align-items: center; | ||||||
|  |   text-align: center; | ||||||
|  |   background-color: #fff; | ||||||
|  |   padding: 2rem; | ||||||
|  |   border-radius: 10px; | ||||||
|  |   touch-action: manipulation; | ||||||
|  |   margin: 2rem; | ||||||
|  |  | ||||||
|  |   @media screen and (max-width: 750px) { | ||||||
|  |     min-height: 100vh; | ||||||
|  |     margin: 0; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | hr { | ||||||
|  |   border-color: lightgrey; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | h1 { | ||||||
|  |   color: #333; | ||||||
|  |   margin-top: 0; | ||||||
|  |   font-size: 4rem; | ||||||
|  |   font-family: 'ibm-plex'; | ||||||
|  |   text-transform: uppercase; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | footer { | ||||||
|  |   position: absolute; | ||||||
|  |   bottom: 0; | ||||||
|  |   left: 0; | ||||||
|  |   height: 3rem; | ||||||
|  |   width: 100%; | ||||||
|  |   display: grid; | ||||||
|  |   place-items: center; | ||||||
|  |  | ||||||
|  |   a { | ||||||
|  |     display: inline-block; | ||||||
|  |     vertical-align: middle; | ||||||
|  |     height: 1.5rem; | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										129
									
								
								frontend/src/App.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,129 @@ | |||||||
|  | <script lang="js"> | ||||||
|  |   import { onMount } from "svelte"; | ||||||
|  |   import Tools from "./components/Tools.svelte"; | ||||||
|  |   import Light from "./components/Light.svelte"; | ||||||
|  |   import ErrorPage from "./components/ErrorPage.svelte"; | ||||||
|  |   import ControlButton from "./components/ControlButton.svelte"; | ||||||
|  |   import Github from "./icons/github.svelte"; | ||||||
|  |   import { getState, toggle, setupApi } from "./utils/tower.js"; | ||||||
|  |  | ||||||
|  |   const { VITE_APP_TITLE, VITE_DEVICE_URL, VITE_DEVICE_PATH, VITE_GITHUB_SOURCE } = import.meta.env; | ||||||
|  |  | ||||||
|  |   const title = | ||||||
|  |     VITE_APP_TITLE?.length > 0 | ||||||
|  |       ? VITE_APP_TITLE | ||||||
|  |       : "Patlite Tower Light Controller"; | ||||||
|  |   setupApi(VITE_DEVICE_URL, VITE_DEVICE_PATH); | ||||||
|  |  | ||||||
|  |   // light tower state, seeded from API | ||||||
|  |   // & used as APP state | ||||||
|  |   let state = { a: 0, b: 0, c: 0 }; | ||||||
|  |   let error; | ||||||
|  |  | ||||||
|  |   async function toggleLight(color, value) { | ||||||
|  |     return toggle(color) | ||||||
|  |       .then(() => (state[color] = !value)) | ||||||
|  |       .catch((error) => console.log("error while toggling light:\n", error)); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   onMount(() => | ||||||
|  |     getState() | ||||||
|  |       .then((s) => (state = s)) | ||||||
|  |       .catch((err) => (error = err)), | ||||||
|  |   ); | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | {#if error} | ||||||
|  |   <ErrorPage {error} /> | ||||||
|  | {/if} | ||||||
|  |  | ||||||
|  | <main class="container"> | ||||||
|  |   <h1>{title}</h1> | ||||||
|  |  | ||||||
|  |   <div class="tower"> | ||||||
|  |     {#each Object.entries(state || {}) as [color, value] (color)} | ||||||
|  |       <Light {color} state={value} onclick={() => toggleLight(color, value)} /> | ||||||
|  |     {/each} | ||||||
|  |     <div class="leg"></div> | ||||||
|  |   </div> | ||||||
|  |  | ||||||
|  |   <div class="actions"> | ||||||
|  |     <Tools updateState={(_state) => (state = _state)} /> | ||||||
|  |  | ||||||
|  |     <div class="controls"> | ||||||
|  |       {#each Object.entries(state || {}) as [color, value] (color)} | ||||||
|  |         <ControlButton | ||||||
|  |           {color} | ||||||
|  |           state={value} | ||||||
|  |           onclick={() => toggleLight(color, value)} | ||||||
|  |         /> | ||||||
|  |       {/each} | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | </main> | ||||||
|  |  | ||||||
|  | <footer> | ||||||
|  |   <span><a href={VITE_GITHUB_SOURCE || '/'}><Github /></a>   with svelte ❤️</span> | ||||||
|  | </footer> | ||||||
|  |  | ||||||
|  | <style lang="scss"> | ||||||
|  |   h1 { | ||||||
|  |     max-width: 800px; | ||||||
|  |     font-size: 3rem; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .tower { | ||||||
|  |     margin: 20px 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   :global(.tower > .light:first-of-type::before) { | ||||||
|  |     position: absolute; | ||||||
|  |     content: ""; | ||||||
|  |     --height: 10px; | ||||||
|  |     --whitespace: 8%; | ||||||
|  |     height: var(--height); | ||||||
|  |     width: calc(100% - var(--whitespace)); | ||||||
|  |     top: calc((var(--height) * -2) + 5px); | ||||||
|  |     left: calc(var(--whitespace) / 2); | ||||||
|  |     background-color: grey; | ||||||
|  |     border-top-left-radius: 6px; | ||||||
|  |     border-top-right-radius: 6px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   :global(.tower > .light:nth-of-type(3)::after) { | ||||||
|  |     position: absolute; | ||||||
|  |     content: ""; | ||||||
|  |     --height: 16px; | ||||||
|  |     --whitespace: 10%; | ||||||
|  |     height: var(--height); | ||||||
|  |     width: calc(100% - var(--whitespace)); | ||||||
|  |     bottom: calc(-1 * var(--height) - 5px); | ||||||
|  |     left: calc(var(--whitespace) / 2); | ||||||
|  |     background-color: grey; | ||||||
|  |     border-bottom-left-radius: 6px; | ||||||
|  |     border-bottom-right-radius: 6px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .leg { | ||||||
|  |     height: 4rem; | ||||||
|  |     width: 2rem; | ||||||
|  |     margin: 0 auto; | ||||||
|  |     background-color: grey; | ||||||
|  |  | ||||||
|  |     border-bottom-left-radius: 6px; | ||||||
|  |     border-bottom-right-radius: 6px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .actions { | ||||||
|  |     width: 100%; | ||||||
|  |     max-width: 450px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .controls { | ||||||
|  |     display: flex; | ||||||
|  |     justify-content: space-around; | ||||||
|  |     flex-wrap: wrap; | ||||||
|  |     gap: 0.5rem; | ||||||
|  |     margin-bottom: 1rem; | ||||||
|  |   } | ||||||
|  | </style> | ||||||
							
								
								
									
										76
									
								
								frontend/src/components/ControlButton.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,76 @@ | |||||||
|  | <script> | ||||||
|  |   import Lamp from "../icons/lamp.svelte"; | ||||||
|  |   import LampBright from "../icons/lamp-bright.svelte"; | ||||||
|  |  | ||||||
|  |   let { color, state, onclick } = $props(); | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <button class={`control-btn ${color}-btn`} class:active={state} {onclick}> | ||||||
|  |   <svelte:component this={state ? LampBright : Lamp} /> | ||||||
|  | </button> | ||||||
|  |  | ||||||
|  | <style lang="scss"> | ||||||
|  |   .control-btn { | ||||||
|  |     margin-top: 2rem; | ||||||
|  |     padding: 1rem; | ||||||
|  |     display: flex; | ||||||
|  |     flex: 1; | ||||||
|  |     justify-content: center; | ||||||
|  |     align-items: center; | ||||||
|  |     font-size: 1rem; | ||||||
|  |     font-weight: bold; | ||||||
|  |     color: white; | ||||||
|  |     border: none; | ||||||
|  |     border-radius: 1rem; | ||||||
|  |     cursor: pointer; | ||||||
|  |     max-height: 5rem; | ||||||
|  |     transition: | ||||||
|  |       transform 0.2s ease, | ||||||
|  |       box-shadow 0.3s ease, | ||||||
|  |       background-color 0.3s ease; | ||||||
|  |  | ||||||
|  |     &:hover { | ||||||
|  |       transform: scale(1.1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     &:focus { | ||||||
|  |       outline: none; | ||||||
|  |       box-shadow: 0 0 15px rgba(0, 0, 0, 0.1); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   :global(.control-btn svg) { | ||||||
|  |     max-height: 40px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /* Individual Button Colors */ | ||||||
|  |   .green-btn { | ||||||
|  |     background-color: #2ecc71; | ||||||
|  |     box-shadow: 0 0 10px rgba(46, 204, 113, 0.6); | ||||||
|  |  | ||||||
|  |     &.active { | ||||||
|  |       background-color: #27ae60; | ||||||
|  |       box-shadow: 0 0 25px rgba(39, 174, 96, 0.9); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .orange-btn { | ||||||
|  |     background-color: #f39c12; | ||||||
|  |     box-shadow: 0 0 10px rgba(243, 156, 18, 0.6); | ||||||
|  |  | ||||||
|  |     &.active { | ||||||
|  |       background-color: #e67e22; | ||||||
|  |       box-shadow: 0 0 25px rgba(230, 126, 34, 0.9); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .red-btn { | ||||||
|  |     background-color: #e74c3c; | ||||||
|  |     box-shadow: 0 0 10px rgba(231, 76, 60, 0.6); | ||||||
|  |  | ||||||
|  |     &.active { | ||||||
|  |       background-color: #c0392b; | ||||||
|  |       box-shadow: 0 0 25px rgba(192, 57, 43, 0.9); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </style> | ||||||
							
								
								
									
										84
									
								
								frontend/src/components/ErrorPage.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,84 @@ | |||||||
|  | <script> | ||||||
|  |   let { error, title = "Whoops! A error occured" } = $props(); | ||||||
|  |  | ||||||
|  |   const importantEnvironmentVariables = { | ||||||
|  |     VITE_DEVICE_URL: "", | ||||||
|  |     VITE_DEVICE_PATH: "", | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   const env = { ...importantEnvironmentVariables, ...import.meta.env }; | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <article> | ||||||
|  |   <h1>{title}</h1> | ||||||
|  |   <p> | ||||||
|  |     it is sad when the application does not work, but below is a stack trace and | ||||||
|  |     current environment variables for deugging. | ||||||
|  |   </p> | ||||||
|  |  | ||||||
|  |   <div> | ||||||
|  |     <label>Stack trace</label> | ||||||
|  |     <code> | ||||||
|  |       <p>Error occured and returned message: "{error}"</p> | ||||||
|  |  | ||||||
|  |       <p>{error?.stack}</p> | ||||||
|  |     </code> | ||||||
|  |  | ||||||
|  |     <label>Environment variables</label> | ||||||
|  |     <code> | ||||||
|  |       {#each Object.entries(env) as [key, value] (key)} | ||||||
|  |         <span>{key}: {value}<br /></span> | ||||||
|  |       {/each} | ||||||
|  |     </code> | ||||||
|  |   </div> | ||||||
|  | </article> | ||||||
|  |  | ||||||
|  | <style style="scss"> | ||||||
|  |   article { | ||||||
|  |     display: flex; | ||||||
|  |     flex-direction: column; | ||||||
|  |     justify-content: center; | ||||||
|  |     --margin: 1rem; | ||||||
|  |     width: calc(100% - var(--margin) * 4); | ||||||
|  |     max-width: 800px; | ||||||
|  |     margin: var(--margin); | ||||||
|  |     padding: var(--margin); | ||||||
|  |     border: 4px dashed #ff8800; | ||||||
|  |     border-radius: 0.5rem; | ||||||
|  |  | ||||||
|  |     @media screen and (max-width: 750px) { | ||||||
|  |       width: unset; | ||||||
|  |       border: none; | ||||||
|  |       margin: 0; | ||||||
|  |       padding: 0.5rem; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     > div { | ||||||
|  |       display: flex; | ||||||
|  |       flex-direction: column; | ||||||
|  |       justify-content: space-between; | ||||||
|  |       width: 100%; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     > p { | ||||||
|  |       font-size: 1.2rem; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   label { | ||||||
|  |     font-weight: bold; | ||||||
|  |     margin-bottom: 0.5rem; | ||||||
|  |     margin-top: 2rem; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   code { | ||||||
|  |     overflow: scroll; | ||||||
|  |     max-width: 90vw; | ||||||
|  |     background-color: #1c1819; | ||||||
|  |     max-height: calc(90vh - 10rem); | ||||||
|  |     color: #fff; | ||||||
|  |     border-radius: 0.75rem; | ||||||
|  |     padding: 1rem; | ||||||
|  |     line-height: 1.4; | ||||||
|  |   } | ||||||
|  | </style> | ||||||
							
								
								
									
										59
									
								
								frontend/src/components/Light.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,59 @@ | |||||||
|  | <script> | ||||||
|  |   let { color, state, onclick } = $props(); | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <button class={`light ${color}`} class:active={state} {onclick} /> | ||||||
|  |  | ||||||
|  | <style style="scss"> | ||||||
|  |   .light { | ||||||
|  |     position: relative; | ||||||
|  |     height: 1.875rem; | ||||||
|  |     height: 10vh; | ||||||
|  |     aspect-ratio: 3 / 1; | ||||||
|  |     margin: 10px auto; | ||||||
|  |     border-radius: 1rem; | ||||||
|  |     background-color: #ccc; | ||||||
|  |     cursor: pointer; | ||||||
|  |     transition: | ||||||
|  |       transform 0.1s ease, | ||||||
|  |       box-shadow 0.2s ease, | ||||||
|  |       background-color 0.2s ease; | ||||||
|  |  | ||||||
|  |     border: none; | ||||||
|  |     display: block; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .green { | ||||||
|  |     background-color: #2ecc71; | ||||||
|  |  | ||||||
|  |     &.active { | ||||||
|  |       background-color: #2ecc71; | ||||||
|  |       box-shadow: | ||||||
|  |         0 0 25px rgba(46, 204, 113, 0.9), | ||||||
|  |         0 0 20px rgba(46, 204, 113, 0.5); | ||||||
|  |       transform: scale(1.1); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   .orange { | ||||||
|  |     background-color: #f39c12; | ||||||
|  |  | ||||||
|  |     &.active { | ||||||
|  |       background-color: #f39c12; | ||||||
|  |       box-shadow: | ||||||
|  |         0 0 25px rgba(243, 156, 18, 0.9), | ||||||
|  |         0 0 20px rgba(243, 156, 18, 0.5); | ||||||
|  |       transform: scale(1.1); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   .red { | ||||||
|  |     background-color: #e74c3c; | ||||||
|  |  | ||||||
|  |     &.active { | ||||||
|  |       background-color: #e74c3c; | ||||||
|  |       box-shadow: | ||||||
|  |         0 0 25px rgba(231, 76, 60, 0.9), | ||||||
|  |         0 0 20px rgba(231, 76, 60, 0.5); | ||||||
|  |       transform: scale(1.1); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </style> | ||||||
							
								
								
									
										209
									
								
								frontend/src/components/Tools.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,209 @@ | |||||||
|  | <script> | ||||||
|  |   import { setTower } from "../utils/tower.js"; | ||||||
|  |   import { warningSeq, errorSeq, trafficSeq, sleep } from "../utils/actions.js"; | ||||||
|  |  | ||||||
|  |   // action icons | ||||||
|  |   import RubberDuck from "../icons/rubber-duck.svelte"; | ||||||
|  |   import Warning from "../icons/warning.svelte"; | ||||||
|  |   import Siren from "../icons/siren.svelte"; | ||||||
|  |   import SirenBright from "../icons/siren-bright.svelte"; | ||||||
|  |   import TrafficLights from "../icons/traffic-lights.svelte"; | ||||||
|  |   import Bell from "../icons/bell.svelte"; | ||||||
|  |   import FireHazard from "../icons/fire-hazard.svelte"; | ||||||
|  |  | ||||||
|  |   let { updateState } = $props(); | ||||||
|  |  | ||||||
|  |   let active = $state(""); | ||||||
|  |   let seqRunning = $state(false); | ||||||
|  |   let iterator = $state(0); | ||||||
|  |   let iteratorSelector = 1; | ||||||
|  |   const ACTIONS = [ | ||||||
|  |     { | ||||||
|  |       label: "siren", | ||||||
|  |       icons: [Siren, SirenBright], | ||||||
|  |       color: "#F63C3D", | ||||||
|  |       sequence: errorSeq, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: "warning", | ||||||
|  |       icons: [Warning], | ||||||
|  |       color: "#FFEF10", | ||||||
|  |       sequence: warningSeq, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: "traffic", | ||||||
|  |       icons: [TrafficLights], | ||||||
|  |       color: "#828C8A", | ||||||
|  |       sequence: trafficSeq, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: "fire", | ||||||
|  |       icons: [FireHazard], | ||||||
|  |       color: "#FF8800", | ||||||
|  |       sequence: warningSeq, | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: "duck", | ||||||
|  |       icons: [RubberDuck], | ||||||
|  |       color: "#F8CE4C", | ||||||
|  |       sequence: [ | ||||||
|  |         [0, 1, 0, 10], | ||||||
|  |         [0, 0, 0, 0], | ||||||
|  |       ], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       label: "bell", | ||||||
|  |       icons: [Bell], | ||||||
|  |       color: "#CDB376", | ||||||
|  |       sequence: warningSeq, | ||||||
|  |     }, | ||||||
|  |   ]; | ||||||
|  |  | ||||||
|  |   async function runSequence(sequence) { | ||||||
|  |     iterator = iteratorSelector; | ||||||
|  |  | ||||||
|  |     while (iterator > 0) { | ||||||
|  |       for (let seq in sequence) { | ||||||
|  |         const value = sequence[seq]; | ||||||
|  |         const [green, orange, red, timeout] = value; | ||||||
|  |  | ||||||
|  |         await setTower(value.slice(0, 3)); | ||||||
|  |         updateState({ green, orange, red }); | ||||||
|  |         await sleep(timeout); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       iterator -= 1; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     await setTower([0, 0, 0]); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   function toggleAction(action) { | ||||||
|  |     // abort if currently running | ||||||
|  |     if (active?.length > 0 || seqRunning) return; | ||||||
|  |  | ||||||
|  |     seqRunning = true; | ||||||
|  |     active = action.label; | ||||||
|  |  | ||||||
|  |     runSequence(action?.sequence).then(() => { | ||||||
|  |       seqRunning = false; | ||||||
|  |       active = null; | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <details class="tools"> | ||||||
|  |   <summary> | ||||||
|  |     <label | ||||||
|  |       >Actions <input | ||||||
|  |         bind:value={iteratorSelector} | ||||||
|  |         type="number" | ||||||
|  |         min="1" | ||||||
|  |       /></label | ||||||
|  |     > | ||||||
|  |     <p>Select modes for quick actions</p> | ||||||
|  |   </summary> | ||||||
|  |  | ||||||
|  |   <div> | ||||||
|  |     {#each ACTIONS as action (action)} | ||||||
|  |       <button | ||||||
|  |         class:active={action.label === active} | ||||||
|  |         style={`--hover-bg: ${action?.color};`} | ||||||
|  |         on:click={() => toggleAction(action)} | ||||||
|  |       > | ||||||
|  |         {#if action?.icons?.length > 1 && action.label === active} | ||||||
|  |           <svelte:component this={action.icons[1]} /> | ||||||
|  |         {:else} | ||||||
|  |           <svelte:component this={action.icons[0]} /> | ||||||
|  |         {/if} | ||||||
|  |       </button> | ||||||
|  |     {/each} | ||||||
|  |   </div> | ||||||
|  |  | ||||||
|  |   <footer> | ||||||
|  |     {#if seqRunning} | ||||||
|  |       <p> | ||||||
|  |         Currently running: {active}, {1 + iteratorSelector - iterator} of {iteratorSelector} | ||||||
|  |       </p> | ||||||
|  |     {/if} | ||||||
|  |   </footer> | ||||||
|  | </details> | ||||||
|  |  | ||||||
|  | <style lang="scss"> | ||||||
|  |   .tools { | ||||||
|  |     background-color: #f0f0f0; | ||||||
|  |     border-radius: 0.5rem; | ||||||
|  |     padding: 1rem; | ||||||
|  |  | ||||||
|  |     > div { | ||||||
|  |       display: flex; | ||||||
|  |       flex-wrap: wrap; | ||||||
|  |       justify-content: space-evenly; | ||||||
|  |       margin-top: 1rem; | ||||||
|  |       gap: 0.5rem; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     summary { | ||||||
|  |       width: 100%; | ||||||
|  |       text-align: left; | ||||||
|  |       cursor: pointer; | ||||||
|  |       -webkit-user-select: none; | ||||||
|  |       user-select: none; | ||||||
|  |  | ||||||
|  |       &::-webkit-details-marker, | ||||||
|  |       &::marker { | ||||||
|  |         display: none; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       label, | ||||||
|  |       p { | ||||||
|  |         width: 100%; | ||||||
|  |         text-align: left; | ||||||
|  |         margin: 0; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       label { | ||||||
|  |         font-size: 1.2rem; | ||||||
|  |         font-weight: 600; | ||||||
|  |  | ||||||
|  |         input { | ||||||
|  |           width: 2rem; | ||||||
|  |           padding: 0.5rem 0.5rem 0.5rem 0.25rem; | ||||||
|  |           font-size: 1.2rem; | ||||||
|  |           float: right; | ||||||
|  |           text-align: right; | ||||||
|  |           border-radius: 0.5rem; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     button { | ||||||
|  |       width: 8rem; | ||||||
|  |       height: 5rem; | ||||||
|  |       background-color: white; | ||||||
|  |       padding: 0.5rem; | ||||||
|  |       border: none; | ||||||
|  |       border-radius: 0.5rem; | ||||||
|  |       box-shadow: 0 0 15px rgba(0, 0, 0, 0.2); | ||||||
|  |       transition: all 0.2s ease; | ||||||
|  |       cursor: pointer; | ||||||
|  |  | ||||||
|  |       &:hover, | ||||||
|  |       &.active { | ||||||
|  |         scale: 1.1; | ||||||
|  |         background-color: var(--hover-bg, rgba(0, 0, 0, 0.7)); | ||||||
|  |         fill: white; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   footer { | ||||||
|  |     p { | ||||||
|  |       margin-bottom: 0; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   :global(.tools button svg) { | ||||||
|  |     max-height: 64px; | ||||||
|  |   } | ||||||
|  | </style> | ||||||
							
								
								
									
										15
									
								
								frontend/src/icons/bell.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,15 @@ | |||||||
|  | <!-- Generated by IcoMoon.io --> | ||||||
|  | <svg | ||||||
|  |   version="1.1" | ||||||
|  |   xmlns="http://www.w3.org/2000/svg" | ||||||
|  |   width="100%" | ||||||
|  |   height="100%" | ||||||
|  |   viewBox="0 0 768 768" | ||||||
|  | > | ||||||
|  |   <g id="icomoon-ignore"> </g> | ||||||
|  |   <path | ||||||
|  |     d="M116.9 546c34.2-12.6 53.3-36.8 64-80.8 11.1-45.9 11.1-106.7 11.1-177.2 0-51.3 20-99.5 56.2-135.8 20.7-20.7 45.4-36.1 72.2-45.5 0.8-14.8 2.9-29.6 8.4-41.8 9.8-21.8 28.3-32.9 55.2-32.9s45.4 11.1 55.2 32.9c5.5 12.2 7.6 27 8.4 41.8 26.9 9.4 51.5 24.8 72.2 45.5 36.2 36.3 56.2 84.5 56.2 135.8 0 70.5 0 131.3 11.1 177.2 10.7 44 29.8 68.2 64 80.8 12.6 4.6 20.9 16.6 20.9 30v64c0 17.7-14.3 32-32 32h-192c0 35.3-28.7 64-64 64s-64-28.7-64-64h-192c-17.7 0-32-14.3-32-32v-64c0-13.4 8.4-25.4 20.9-30zM384 64c-18.5 0-27.6 5.9-30.7 34.4 10-1.6 20.3-2.4 30.7-2.4s20.7 0.8 30.7 2.4c-3.1-28.5-12.2-34.4-30.7-34.4zM384 704c17.6 0 32-14.4 32-32h-64c0 17.6 14.4 32 32 32zM160 608h448v-11.3c-42.3-22.3-69.6-60.6-83.1-116.5-12.9-53.2-12.9-117.6-12.9-192.2 0-70.6-57.4-128-128-128s-128 57.4-128 128c0 74.6 0 139-12.9 192.3-13.5 55.9-40.8 94.2-83.1 116.5v11.2z" | ||||||
|  |   ></path> | ||||||
|  |   <path d="M384 192v32c-35.3 0-64 28.7-64 64v64h-32v-64c0-52.9 43.1-96 96-96z" | ||||||
|  |   ></path> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 1.1 KiB | 
							
								
								
									
										16
									
								
								frontend/src/icons/cactus.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,16 @@ | |||||||
|  | <!-- Generated by IcoMoon.io --> | ||||||
|  | <svg | ||||||
|  |   version="1.1" | ||||||
|  |   xmlns="http://www.w3.org/2000/svg" | ||||||
|  |   width="100%" | ||||||
|  |   height="100%" | ||||||
|  |   viewBox="0 0 768 768" | ||||||
|  | > | ||||||
|  |   <g id="icomoon-ignore"> </g> | ||||||
|  |   <path d="M352 128h32v32h-32v-32z"></path> | ||||||
|  |   <path d="M384 256h32v32h-32v-32z"></path> | ||||||
|  |   <path d="M352 384h32v32h-32v-32z"></path> | ||||||
|  |   <path | ||||||
|  |     d="M768 384v-32h-33.1c0.7-10.5 1.1-21.2 1.1-32 0-41.7-26.8-77.3-64-90.5v-37.5h-32v32c-20.7 0-39.9 6.6-55.6 17.8l-24.4-24.4-22.6 22.6 24.4 24.4c-11.2 15.7-17.8 34.9-17.8 55.6 0 44-6.3 94.3-32 116.5v-308.5c0-12.6-1.8-24.7-5.2-36.2l43.8-43.8-22.6-22.6-35.2 35.2c-22.6-36.4-62.9-60.6-108.8-60.6-37.7 0-71.6 16.4-95 42.3l-17-17-22.6 22.7 21 21c-9.2 17.7-14.4 37.7-14.4 59v148.5c-25.7-22.2-32-72.5-32-116.5 0-37.1-21.2-69.4-52-85.3l26.6-26.7-22.6-22.6-39 39c-2.9-0.3-5.9-0.4-9-0.4-11.2 0-22 1.9-32 5.5v-37.5h-32v56.5c-19.6 17.6-32 43.1-32 71.5h-32v32h33.1c3.3 49.4 14.5 95.6 32.5 135.8l-40.2 40.2 22.6 22.6 32.9-32.9c5.1 8.7 10.5 17 16.3 24.9 15.3 20.9 32.9 38.6 52.5 53l-28.3 28.4 22.6 22.6 33.5-33.5c0.3 0.2 0.6 0.3 1 0.5 24 12.7 50 20.8 77.6 24.3v258h-64v32h384v-32h-64v-98c27.6-3.5 53.6-11.7 77.6-24.3 0.3-0.2 0.6-0.3 1-0.5l33.5 33.5 22.6-22.6-28.3-28.3c19.6-14.4 37.2-32.2 52.5-53 5.8-7.9 11.2-16.2 16.3-24.9l32.9 32.9 22.6-22.6-40.2-40.2c14.1-31.4 23.9-66.5 29.2-103.8h36.2zM619.2 504.7c-34.3 46.6-82.4 71.3-139.2 71.3-17.7 0-32 14.3-32 32v128h-128v-288c0-17.7-14.3-32-32-32-56.8 0-104.9-24.7-139.2-71.3-34.1-46.3-52.8-111.9-52.8-184.7 0-17.6 14.4-32 32-32s32 14.4 32 32c0 53.1 8.5 96.1 25.1 128 10.4 19.8 24 35.4 40.5 46.2 18 11.8 39 17.8 62.4 17.8 17.7 0 32-14.3 32-32v-192c0-35.3 28.7-64 64-64s64 28.7 64 64v352c0 17.7 14.3 32 32 32 23.4 0 44.4-6 62.4-17.8 16.5-10.8 30.1-26.4 40.5-46.2 16.7-31.9 25.1-74.9 25.1-128 0-17.6 14.4-32 32-32s32 14.4 32 32c0 72.8-18.7 138.4-52.8 184.7z" | ||||||
|  |   ></path> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 1.8 KiB | 
							
								
								
									
										21
									
								
								frontend/src/icons/fire-hazard-active.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,21 @@ | |||||||
|  | <svg | ||||||
|  |   version="1.1" | ||||||
|  |   xmlns="http://www.w3.org/2000/svg" | ||||||
|  |   width="100%" | ||||||
|  |   height="100%" | ||||||
|  |   viewBox="0 0 768 768" | ||||||
|  | > | ||||||
|  |   <g id="icomoon-ignore"> </g> | ||||||
|  |   <path | ||||||
|  |     fill="#F63C3D" | ||||||
|  |     d="M761.2 675.3l-320-639.9c-10.8-21.8-32.8-35.4-57.2-35.4-24.5 0-46.4 13.6-57.2 35.4l-320 639.9c-4.4 8.8-6.8 18.7-6.8 28.7 0 35.3 28.7 64 64 64h640c35.3 0 64-28.7 64-64 0-10-2.4-19.9-6.8-28.7zM64 704l320-640c0 0 0 0 0 0l320 640h-640zM704 704c0 0 0 0 0 0s0.1 0 0 0c0.1 0 0 0 0 0z" | ||||||
|  |   ></path> | ||||||
|  |   <path | ||||||
|  |     fill="#FFE016" | ||||||
|  |     d="M384 608c35.3 0 64-28.7 64-64 0-54-35.2-89.8-36.7-91.3-4.9-4.9-12.3-6.1-18.5-3-3 1.5-72.8 37.1-72.8 94.3 0 35.3 28.7 64 64 64zM396.3 484.7c8 11.3 19.7 32.4 19.7 59.3 0 17.6-14.4 32-32 32s-32-14.4-32-32c0-25.2 26.2-47.6 44.3-59.3z" | ||||||
|  |   ></path> | ||||||
|  |   <path | ||||||
|  |     fill="#F63C3D" | ||||||
|  |     d="M355.3 290c-5 2.8-8.2 8.2-8.2 14 0 71.4-25.6 108.2-50.3 143.8-24.9 35.8-48.4 69.7-38.5 129 0 0.2 0.1 0.4 0.1 0.6 6.4 30.8 25.2 57.3 53 74.6 21.2 13.2 46.1 20 72 20 7.5 0 15-0.6 22.5-1.7 0.1 0 0.2 0 0.3 0 33.4-5.7 62.1-23.3 80.9-49.6 21.3-29.9 29.2-69.9 22.7-115.9 0-0.1 0-0.2 0-0.3-11.7-74.1-48.5-128.3-77.3-160.7-31.2-35.1-59.8-52.7-61-53.4-5-3.1-11.2-3.2-16.2-0.4zM478.1 509.3c11.7 83.6-32.2 121.6-77.2 129.4-52.7 8-101.4-21.6-111.1-67.4-7.6-46.3 10.5-72.3 33.3-105.2 21.6-31.1 47.8-68.8 54.5-131.2 31.5 26.7 86.4 84.8 100.5 174.4z" | ||||||
|  |   ></path> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 1.3 KiB | 
							
								
								
									
										19
									
								
								frontend/src/icons/fire-hazard.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,19 @@ | |||||||
|  | <!-- Generated by IcoMoon.io --> | ||||||
|  | <svg | ||||||
|  |   version="1.1" | ||||||
|  |   xmlns="http://www.w3.org/2000/svg" | ||||||
|  |   width="100%" | ||||||
|  |   height="100%" | ||||||
|  |   viewBox="0 0 768 768" | ||||||
|  | > | ||||||
|  |   <g id="icomoon-ignore"> </g> | ||||||
|  |   <path | ||||||
|  |     d="M761.2 675.3l-320-639.9c-10.8-21.8-32.8-35.4-57.2-35.4-24.5 0-46.4 13.6-57.2 35.4l-320 639.9c-4.4 8.8-6.8 18.7-6.8 28.7 0 35.3 28.7 64 64 64h640c35.3 0 64-28.7 64-64 0-10-2.4-19.9-6.8-28.7zM64 704l320-640c0 0 0 0 0 0l320 640h-640zM704 704c0 0 0 0 0 0s0.1 0 0 0c0.1 0 0 0 0 0z" | ||||||
|  |   ></path> | ||||||
|  |   <path | ||||||
|  |     d="M384 608c35.3 0 64-28.7 64-64 0-54-35.2-89.8-36.7-91.3-4.9-4.9-12.3-6.1-18.5-3-3 1.5-72.8 37.1-72.8 94.3 0 35.3 28.7 64 64 64zM396.3 484.7c8 11.3 19.7 32.4 19.7 59.3 0 17.6-14.4 32-32 32s-32-14.4-32-32c0-25.2 26.2-47.6 44.3-59.3z" | ||||||
|  |   ></path> | ||||||
|  |   <path | ||||||
|  |     d="M355.3 290c-5 2.8-8.2 8.2-8.2 14 0 71.4-25.6 108.2-50.3 143.8-24.9 35.8-48.4 69.7-38.5 129 0 0.2 0.1 0.4 0.1 0.6 6.4 30.8 25.2 57.3 53 74.6 21.2 13.2 46.1 20 72 20 7.5 0 15-0.6 22.5-1.7 0.1 0 0.2 0 0.3 0 33.4-5.7 62.1-23.3 80.9-49.6 21.3-29.9 29.2-69.9 22.7-115.9 0-0.1 0-0.2 0-0.3-11.7-74.1-48.5-128.3-77.3-160.7-31.2-35.1-59.8-52.7-61-53.4-5-3.1-11.2-3.2-16.2-0.4zM478.1 509.3c11.7 83.6-32.2 121.6-77.2 129.4-52.7 8-101.4-21.6-111.1-67.4-7.6-46.3 10.5-72.3 33.3-105.2 21.6-31.1 47.8-68.8 54.5-131.2 31.5 26.7 86.4 84.8 100.5 174.4z" | ||||||
|  |   ></path> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 1.3 KiB | 
							
								
								
									
										13
									
								
								frontend/src/icons/flower.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,13 @@ | |||||||
|  | <!-- Generated by IcoMoon.io --> | ||||||
|  | <svg | ||||||
|  |   version="1.1" | ||||||
|  |   xmlns="http://www.w3.org/2000/svg" | ||||||
|  |   width="100%" | ||||||
|  |   height="100%" | ||||||
|  |   viewBox="0 0 768 768" | ||||||
|  | > | ||||||
|  |   <g id="icomoon-ignore"> </g> | ||||||
|  |   <path | ||||||
|  |     d="M768.2 384c0-57.1-37.6-105.6-89.3-122 9.4-18 14.4-38.2 14.4-59.1 0-34.2-13.3-66.3-37.5-90.5s-56.3-37.5-90.5-37.5c-20.9 0-41 5-59.1 14.4-16.4-51.7-64.9-89.3-122-89.3-57.2-0.1-105.7 37.5-122.2 89.3-48.2-25-109.2-17.3-149.6 23.1s-48.1 101.4-23.1 149.6c-51.7 16.4-89.3 64.9-89.3 122s37.6 105.6 89.4 122.1c-25 48.2-17.3 109.2 23.1 149.6s101.3 48.1 149.6 23.1c16.4 51.8 64.9 89.4 122.1 89.4 57.1 0 105.6-37.6 122-89.3 18 9.4 38.2 14.4 59.1 14.4 34.2 0 66.3-13.3 90.5-37.5s37.5-56.3 37.5-90.5c0-20.9-5-41-14.4-59.1 51.7-16.6 89.3-65.1 89.3-122.2zM506.7 167.9c0.6-0.4 1.3-0.9 1.8-1.2 3.1-2.1 7.4-5 11.4-9 25-25 65.6-25 90.5 0 25 25 25 65.6 0 90.5-4 4-6.7 8-8.9 11.3-0.4 0.6-1 1.4-1.4 2-6.3 5.2-10.1 12.5-11.2 20.3l-93.8 38.9c-11.4-19.9-27.9-36.5-47.8-47.8l38.9-93.7c7.9-1.1 15.2-5 20.5-11.3zM384 448c-35.3 0-64-28.7-64-64s28.7-64 64-64c35.3 0 64 28.7 64 64s-28.7 64-64 64zM318.4 142.4c0.7-3.7 1.7-8.8 1.7-14.5 0-35.3 28.7-64 64-64s64 28.7 64 64c0 5.7 1 10.7 1.7 14.4 0.1 0.7 0.3 1.6 0.4 2.3-0.7 8.1 1.7 16 6.4 22.3l-38.9 93.7c-10.8-3-22.1-4.5-33.8-4.5s-23 1.6-33.8 4.5l-38.7-93.6c4.8-6.3 7.3-14.2 6.6-22.4 0.1-0.7 0.3-1.5 0.4-2.2zM157.7 157.6c25-25 65.6-25 90.5 0 4 4 8 6.7 11.3 8.9 0.6 0.4 1.4 1 2 1.4 5.2 6.2 12.5 10.1 20.2 11.2l38.9 93.7c-19.9 11.4-36.5 27.9-47.8 47.8l-93.6-38.8c-1-7.8-4.9-15.2-11.2-20.4-0.4-0.6-0.9-1.2-1.2-1.8-2.1-3.1-5-7.4-9-11.4-25-25-25-65.6-0.1-90.6zM64 384c0-35.3 28.7-64 64-64 5.7 0 10.7-1 14.4-1.7 0.7-0.1 1.6-0.3 2.3-0.4 8.1 0.7 16.1-1.7 22.3-6.5l93.6 38.8c-3 10.8-4.5 22.1-4.5 33.8s1.6 23 4.5 33.8l-93.6 38.8c-6.2-4.8-14.1-7.2-22.3-6.5-0.7-0.1-1.5-0.3-2.2-0.4-3.7-0.7-8.8-1.7-14.5-1.7-35.3 0-64-28.7-64-64zM261.5 600.1c-0.6 0.4-1.2 0.9-1.8 1.2-3.1 2.1-7.4 5-11.4 9-25 25-65.6 25-90.5 0-25-25-25-65.6 0-90.5 4-4 6.7-8 8.9-11.3 0.4-0.6 1-1.4 1.4-2 6.3-5.2 10.1-12.6 11.2-20.4l93.6-38.8c11.4 19.9 27.9 36.5 47.8 47.8l-38.9 93.7c-7.8 1.2-15.1 5.1-20.3 11.3zM449.8 625.6c-0.7 3.7-1.7 8.8-1.7 14.5 0 35.3-28.7 64-64 64s-64-28.7-64-64c0-5.7-1-10.7-1.7-14.4-0.1-0.7-0.3-1.6-0.4-2.3 0.7-8.2-1.7-16.2-6.6-22.4l38.8-93.6c10.8 3 22.1 4.5 33.8 4.5s23-1.6 33.8-4.5l38.9 93.7c-4.7 6.2-7.2 14.1-6.5 22.2-0.1 0.8-0.3 1.6-0.4 2.3zM610.5 610.4c-25 25-65.6 25-90.5 0-4-4-8-6.7-11.3-8.9-0.6-0.4-1.4-1-2-1.4-5.3-6.3-12.6-10.2-20.4-11.2l-38.9-93.7c19.9-11.4 36.5-27.9 47.8-47.8l93.8 38.9c1.1 7.8 4.9 15.1 11.2 20.3 0.4 0.6 0.9 1.3 1.2 1.8 2.1 3.1 5 7.4 9 11.4 25 25 25 65.6 0.1 90.6zM640.2 448c-5.7 0-10.7 1-14.4 1.7-0.7 0.1-1.6 0.3-2.3 0.4-8.2-0.7-16.1 1.7-22.4 6.5l-93.7-38.9c3-10.8 4.5-22.1 4.5-33.8s-1.6-23-4.5-33.8l93.7-38.9c6.2 4.8 14.2 7.3 22.3 6.5 0.7 0.1 1.5 0.3 2.2 0.4 3.7 0.7 8.8 1.7 14.5 1.7 35.3 0 64 28.7 64 64 0.1 35.5-28.6 64.2-63.9 64.2z" | ||||||
|  |   ></path> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 2.8 KiB | 
							
								
								
									
										1
									
								
								frontend/src/icons/github.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | |||||||
|  | <svg width="100%" height="100%" viewBox="0 0 96 98" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="#24292f"/></svg> | ||||||
| After Width: | Height: | Size: 988 B | 
							
								
								
									
										28
									
								
								frontend/src/icons/lamp-bright.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,28 @@ | |||||||
|  | <!-- Generated by IcoMoon.io --> | ||||||
|  | <svg | ||||||
|  |   version="1.1" | ||||||
|  |   xmlns="http://www.w3.org/2000/svg" | ||||||
|  |   width="100%" | ||||||
|  |   height="100%" | ||||||
|  |   viewBox="0 0 768 768" | ||||||
|  | > | ||||||
|  |   <g id="icomoon-ignore"> </g> | ||||||
|  |   <path | ||||||
|  |     d="M542.4 66.6c-42.3-42.8-98.3-66.4-157.7-66.6-0.2 0-0.4 0-0.6 0-59.7 0-115.8 23.2-158.2 65.4-42.5 42.4-65.9 98.7-65.9 158.6 0 99.7 34.7 143.5 62.7 178.7 19.3 24.4 33.3 42 33.3 77.3v96c0 35.3 28.7 64 64 64h128c35.3 0 64-28.7 64-64v-96c0-35.2 14-52.9 33.3-77.2 27.5-34.6 61.8-77.6 62.7-174.7 0.3-30.6-5.5-60.5-17.2-88.7-11.4-27.3-27.6-51.8-48.4-72.8zM544 227.5c-0.7 75-24.1 104.4-48.8 135.4 0 0 0 0 0 0-22.1 27.9-47.2 59.5-47.2 117v96h-128v-96c0-57.5-25.1-89.2-47.2-117.1-25.1-31.5-48.8-61.4-48.8-138.8 0-42.8 16.7-83 47.1-113.2 30.2-30.2 70.3-46.8 112.9-46.8 0.2 0 0.3 0 0.5 0 42.2 0.1 82.1 17 112.3 47.6 30.9 31.2 47.6 72.3 47.2 115.9z" | ||||||
|  |   ></path> | ||||||
|  |   <path d="M288 672h192v32h-192v-32z"></path> | ||||||
|  |   <path d="M352 736h64v32h-64v-32z"></path> | ||||||
|  |   <path d="M672 224h96v32h-96v-32z"></path> | ||||||
|  |   <path | ||||||
|  |     d="M634.493 72.858l92.659-46.33 14.311 28.621-92.66 46.33-14.311-28.621z" | ||||||
|  |   ></path> | ||||||
|  |   <path | ||||||
|  |     d="M634.494 407.159l14.311-28.621 92.659 46.33-14.311 28.621-92.66-46.33z" | ||||||
|  |   ></path> | ||||||
|  |   <path d="M0 224h96v32h-96v-32z"></path> | ||||||
|  |   <path d="M26.512 55.147l14.311-28.621 92.66 46.33-14.311 28.621-92.66-46.33z" | ||||||
|  |   ></path> | ||||||
|  |   <path | ||||||
|  |     d="M26.503 424.848l92.659-46.33 14.311 28.621-92.66 46.33-14.311-28.621z" | ||||||
|  |   ></path> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 1.4 KiB | 
							
								
								
									
										15
									
								
								frontend/src/icons/lamp.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,15 @@ | |||||||
|  | <!-- Generated by IcoMoon.io --> | ||||||
|  | <svg | ||||||
|  |   version="1.1" | ||||||
|  |   xmlns="http://www.w3.org/2000/svg" | ||||||
|  |   width="100%" | ||||||
|  |   height="100%" | ||||||
|  |   viewBox="0 0 768 768" | ||||||
|  | > | ||||||
|  |   <g id="icomoon-ignore"> </g> | ||||||
|  |   <path | ||||||
|  |     d="M590.8 139.4c-11.3-27.3-27.6-51.8-48.4-72.8-42.3-42.8-98.3-66.4-157.7-66.6-0.2 0-0.4 0-0.6 0-59.7 0-115.8 23.2-158.2 65.4-42.5 42.4-65.9 98.7-65.9 158.6 0 99.7 34.7 143.5 62.7 178.7 19.3 24.4 33.3 42 33.3 77.3v96c0 35.3 28.7 64 64 64h128c35.3 0 64-28.7 64-64v-96c0-35.2 14-52.9 33.3-77.2 27.5-34.6 61.8-77.6 62.7-174.7 0.3-30.6-5.5-60.5-17.2-88.7zM544 227.5c-0.7 75-24.1 104.4-48.8 135.4 0 0 0 0 0 0-22.1 27.9-47.2 59.5-47.2 117v96h-128v-96c0-57.5-25.1-89.2-47.2-117.1-25.1-31.5-48.8-61.4-48.8-138.8 0-42.8 16.7-83 47.1-113.2 30.2-30.2 70.3-46.8 112.9-46.8 0.2 0 0.3 0 0.5 0 42.2 0.1 82.1 17 112.3 47.6 30.9 31.2 47.6 72.3 47.2 115.9z" | ||||||
|  |   ></path> | ||||||
|  |   <path d="M288 672h192v32h-192v-32z"></path> | ||||||
|  |   <path d="M352 736h64v32h-64v-32z"></path> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 938 B | 
							
								
								
									
										14
									
								
								frontend/src/icons/no-connection.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,14 @@ | |||||||
|  | <svg | ||||||
|  |   version="1.1" | ||||||
|  |   xmlns="http://www.w3.org/2000/svg" | ||||||
|  |   width="100%" | ||||||
|  |   height="100%" | ||||||
|  |   viewBox="0 0 768 768" | ||||||
|  | > | ||||||
|  |   <g id="icomoon-ignore"> </g> | ||||||
|  |   <path | ||||||
|  |     d="M704 384h-128v-32h144c26.5 0 48-21.5 48-48 0-7.5-1.8-14.9-5.1-21.5l-128-255.9c-8-16.2-24.8-26.6-42.9-26.6s-34.9 10.4-42.9 26.5l-50.7 101.5h-82.4v-64c0-35.3-28.7-64-64-64h-288c-35.3 0-64 28.7-64 64v160c0 35.3 28.7 64 64 64h42.2l-9.8 58.7c-1.5 9.3 1.1 18.8 7.1 25.9s15 11.3 24.4 11.3h160c9.4 0 18.3-4.1 24.4-11.3s8.7-16.7 7.1-25.9l-9.8-58.7h42.4c35.3 0 64-28.7 64-64v-64h66.4l-61.2 122.5c-3.3 6.6-5.1 14-5.1 21.5 0 26.5 21.5 48 48 48h80v32h-128.1c-35.3 0-64 28.7-64 64v160c0 35.3 28.7 64 64 64h42.2l-9.8 58.7c-1.5 9.3 1.1 18.8 7.1 25.9 6.1 7.2 15 11.3 24.4 11.3h160c9.4 0 18.3-4.1 24.4-11.3s8.7-16.7 7.1-25.9l-9.8-58.7h42.4c35.3 0 64-28.7 64-64v-160c0-35.3-28.7-64-64-64zM255.6 352h-95.1l10.7-64h73.8l10.6 64zM352 224h-288v-160h288v160c0 0 0 0 0 0zM448 304c0-2.5 0.6-4.9 1.6-7l128.1-256.2c2.6-5.3 8.2-8.8 14.3-8.8s11.6 3.5 14.3 8.9l128.1 256.1c1.1 2.1 1.6 4.5 1.6 7 0 8.8-7.2 16-16 16h-256c-8.8 0-16-7.2-16-16zM607.6 736h-95.1l10.7-64h73.8l10.6 64zM704 608h-288v-160h288v160c0 0 0 0 0 0z" | ||||||
|  |   ></path> | ||||||
|  |   <path d="M576 256h32v32h-32v-32z"></path> | ||||||
|  |   <path d="M576 96h32v128h-32v-128z"></path> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 1.2 KiB | 
							
								
								
									
										16
									
								
								frontend/src/icons/rubber-duck.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,16 @@ | |||||||
|  | <!-- Generated by IcoMoon.io --> | ||||||
|  | <svg | ||||||
|  |   version="1.1" | ||||||
|  |   xmlns="http://www.w3.org/2000/svg" | ||||||
|  |   width="100%" | ||||||
|  |   height="100%" | ||||||
|  |   viewBox="0 0 768 768" | ||||||
|  | > | ||||||
|  |   <g id="icomoon-ignore"> </g> | ||||||
|  |   <path | ||||||
|  |     d="M731.1 164.5c-3.2-3.1-7.5-4.7-11.9-4.5-22.7 1.1-59 0.3-84.8-5-0.4-1.3-0.7-2.5-1.1-3.8-12.7-41.1-39.7-75.6-75.9-97.1-38.1-22.5-82.6-28.2-125.5-16-40 11.4-73 38.5-92.9 76.1-20.7 39.1-24.5 85.8-10.5 128.2 9.1 30.5 24.3 47.2 36.5 60.7 12.6 13.8 18.9 20.8 18.9 43.5 0 21.1-28.1 34.3-55.8 36.5-3.2 0.3-6.5 0.4-9.7 0.4-30.9 0-62.6-11.3-88.3-31.8-36.1-28.7-60.1-74.7-69.3-133-2.1-13.1-12.1-23.6-25.1-26.3s-26.4 2.9-33.5 14.2c-39.7 62.4-62.5 126.8-67.8 191.5-5.1 62.6 7.1 122.9 35.4 174.4 56.8 103.9 171.7 163.5 314.9 163.5 117.2 0 184.8-45 220.9-82.8 41.3-43.3 65-101.2 65-158.9 0-65-31.6-110.4-76.9-110.4-8.3 0-13.7-0.6-17-1.3 0.6-2.6 1.7-6.4 3.8-11.7 4-10.5 10.2-23.2 16.7-36.6 4.2-8.6 8.6-17.7 13-27.3 36.2-10.3 65.2-25.6 86.5-45.5 25.3-23.5 38.9-53.1 39.3-85.4 0.1-4.3-1.7-8.6-4.9-11.6zM593.5 447.9c1.4 0.8 6.5 6 10 19.6 4.2 16.5 4.1 37.2-0.3 58.2-7.1 34.3-44.2 146.3-218.5 146.3-119.2 0-213.5-47.4-259-130.2-36.5-66.4-37.6-149.5-5.1-231.9 16.5 37.4 39.9 68.6 69.5 92 41 32.6 93.1 49 142.9 45.1 67.6-5.3 114.8-46.5 114.8-100.3 0-47.5-19.7-69.2-35.6-86.6-9.9-10.9-17.7-19.5-22.6-36.2-0.1-0.4-0.2-0.7-0.3-1.1-8.7-26.1-6.4-54.7 6.2-78.7 11.7-22.1 30.8-37.9 53.9-44.5 58.1-16.6 108 22.8 122.7 70.4 13.1 42.5-11.1 92.3-32.5 136.2-8.9 18.4-17.4 35.8-22.5 51.7-2.9 9-11.6 36.4 3.2 60 18.7 29.9 59.5 30 73.2 30zM626.1 267.8c8.7-25.1 14.6-52 13.5-79.4 22.5 3.5 46.3 4.1 62.5 4-7 32.2-33.5 58.2-76 75.4z" | ||||||
|  |   ></path> | ||||||
|  |   <path | ||||||
|  |     d="M544 192c0-17.6-14.4-32-32-32s-32 14.4-32 32 14.4 32 32 32 32-14.4 32-32zM512 192c0 0 0 0 0 0v0z" | ||||||
|  |   ></path> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 1.7 KiB | 
							
								
								
									
										33
									
								
								frontend/src/icons/siren-bright.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,33 @@ | |||||||
|  | <!-- Generated by IcoMoon.io --> | ||||||
|  | <svg | ||||||
|  |   version="1.1" | ||||||
|  |   xmlns="http://www.w3.org/2000/svg" | ||||||
|  |   width="100%" | ||||||
|  |   height="100%" | ||||||
|  |   viewBox="0 0 768 768" | ||||||
|  | > | ||||||
|  |   <g id="icomoon-ignore"> </g> | ||||||
|  |   <path | ||||||
|  |     d="M634.493 296.859l92.659-46.33 14.311 28.621-92.659 46.33-14.311-28.621z" | ||||||
|  |   ></path> | ||||||
|  |   <path | ||||||
|  |     d="M569.332 176.029l86.62-86.62 22.627 22.627-86.62 86.62-22.628-22.627z" | ||||||
|  |   ></path> | ||||||
|  |   <path | ||||||
|  |     d="M443.744 154.11l42.118-126.367 30.358 10.118-42.118 126.367-30.358-10.118z" | ||||||
|  |   ></path> | ||||||
|  |   <path | ||||||
|  |     d="M26.506 279.143l14.311-28.621 92.66 46.33-14.311 28.621-92.659-46.33z" | ||||||
|  |   ></path> | ||||||
|  |   <path d="M89.339 111.968l22.627-22.627 86.62 86.62-22.628 22.628-86.62-86.62z" | ||||||
|  |   ></path> | ||||||
|  |   <path | ||||||
|  |     d="M251.764 37.886l30.358-10.118 42.118 126.367-30.359 10.118-42.118-126.367z" | ||||||
|  |   ></path> | ||||||
|  |   <path | ||||||
|  |     d="M640 576h-5.3l-59.2-325.7c-1.3-7-4.9-13.4-10.2-18.2-40.7-36.2-140.4-40.1-181.3-40.1s-140.6 3.9-181.3 40.1c-5.3 4.8-8.9 11.2-10.2 18.2l-59.2 325.7h-5.3c-35.3 0-64 28.7-64 64v112c0 8.8 7.2 16 16 16h608c8.8 0 16-7.2 16-16v-112c0-35.3-28.7-64-64-64zM253 275.2c6.9-3.3 19.3-7.8 40.4-11.7 25.7-4.8 57.9-7.5 90.6-7.5s64.9 2.6 90.6 7.5c21.1 3.9 33.4 8.4 40.4 11.7l54.7 300.8h-371.4l54.7-300.8zM128 736v-96h512v96h-512z" | ||||||
|  |   ></path> | ||||||
|  |   <path | ||||||
|  |     d="M445.174 323.446l31.379-6.275 38.279 191.413-31.379 6.275-38.279-191.413z" | ||||||
|  |   ></path> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 1.3 KiB | 
							
								
								
									
										16
									
								
								frontend/src/icons/siren.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,16 @@ | |||||||
|  | <!-- Generated by IcoMoon.io --> | ||||||
|  | <svg | ||||||
|  |   version="1.1" | ||||||
|  |   xmlns="http://www.w3.org/2000/svg" | ||||||
|  |   width="100%" | ||||||
|  |   height="100%" | ||||||
|  |   viewBox="0 0 768 768" | ||||||
|  | > | ||||||
|  |   <g id="icomoon-ignore"> </g> | ||||||
|  |   <path | ||||||
|  |     d="M640 480h-5.3l-59.2-325.7c-1.3-7-4.9-13.4-10.2-18.2-40.7-36.2-140.4-40.1-181.3-40.1s-140.6 3.9-181.3 40.1c-5.3 4.8-8.9 11.2-10.2 18.2l-59.2 325.7h-5.3c-35.3 0-64 28.7-64 64v112c0 8.8 7.2 16 16 16h608c8.8 0 16-7.2 16-16v-112c0-35.3-28.7-64-64-64zM253 179.2c6.9-3.3 19.3-7.8 40.4-11.7 25.7-4.8 57.9-7.5 90.6-7.5s64.9 2.6 90.6 7.5c21.1 3.9 33.4 8.4 40.4 11.7l54.7 300.8h-371.4l54.7-300.8zM128 640v-96h512v96h-512z" | ||||||
|  |   ></path> | ||||||
|  |   <path | ||||||
|  |     d="M445.175 227.444l31.379-6.275 38.279 191.413-31.379 6.275-38.279-191.413z" | ||||||
|  |   ></path> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 725 B | 
							
								
								
									
										22
									
								
								frontend/src/icons/traffic-lights.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,22 @@ | |||||||
|  | <!-- Generated by IcoMoon.io --> | ||||||
|  | <svg | ||||||
|  |   version="1.1" | ||||||
|  |   xmlns="http://www.w3.org/2000/svg" | ||||||
|  |   width="100%" | ||||||
|  |   height="100%" | ||||||
|  |   viewBox="0 0 768 768" | ||||||
|  | > | ||||||
|  |   <g id="icomoon-ignore"> </g> | ||||||
|  |   <path | ||||||
|  |     d="M384 96c-35.3 0-64 28.7-64 64s28.7 64 64 64c35.3 0 64-28.7 64-64s-28.7-64-64-64zM384 192c-17.6 0-32-14.4-32-32s14.4-32 32-32c17.6 0 32 14.4 32 32s-14.4 32-32 32z" | ||||||
|  |   ></path> | ||||||
|  |   <path | ||||||
|  |     d="M384 256c-35.3 0-64 28.7-64 64s28.7 64 64 64c35.3 0 64-28.7 64-64s-28.7-64-64-64zM384 352c-17.6 0-32-14.4-32-32s14.4-32 32-32c17.6 0 32 14.4 32 32s-14.4 32-32 32z" | ||||||
|  |   ></path> | ||||||
|  |   <path | ||||||
|  |     d="M384 416c-35.3 0-64 28.7-64 64s28.7 64 64 64c35.3 0 64-28.7 64-64s-28.7-64-64-64zM384 512c-17.6 0-32-14.4-32-32s14.4-32 32-32c17.6 0 32 14.4 32 32s-14.4 32-32 32z" | ||||||
|  |   ></path> | ||||||
|  |   <path | ||||||
|  |     d="M663.9 157.9c5-2.8 8.1-8.2 8.1-13.9v-32c0-8.8-7.2-16-16-16h-80v-32c0-35.3-28.7-64-64-64h-256c-35.3 0-64 28.7-64 64v32h-80c-8.8 0-16 7.2-16 16v32c0 5.7 3.1 11 8.1 13.9l87.9 50.3v47.8h-80c-8.8 0-16 7.2-16 16v32c0 5.7 3.1 11 8.1 13.9l87.9 50.3v47.8h-80c-8.8 0-16 7.2-16 16v32c0 5.7 3.1 11 8.1 13.9l87.9 50.3v47.8c0 35.3 28.7 64 64 64h32v112c0 8.8 7.2 16 16 16h160c8.8 0 16-7.2 16-16v-112h32c35.3 0 64-28.7 64-64v-47.9l87.9-50.3c5-2.8 8.1-8.2 8.1-13.9v-32c0-8.8-7.2-16-16-16h-80v-47.9l87.9-50.3c5-2.8 8.1-8.2 8.1-13.9v-32c0-8.8-7.2-16-16-16h-80v-47.9l87.9-50zM128 134.7v-6.7h64v43.3l-64-36.6zM128 294.7v-6.7h64v43.3l-64-36.6zM128 454.7v-6.7h64v43.3l-64-36.6zM640 128v6.7l-64 36.6v-43.3h64zM416 736h-64v-96h64v96zM512 576h-256v-512h256v512c0.1 0 0 0 0 0zM640 448v6.7l-64 36.6v-43.3h64zM640 288v6.7l-64 36.6v-43.3h64z" | ||||||
|  |   ></path> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 1.6 KiB | 
							
								
								
									
										18
									
								
								frontend/src/icons/warning.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,18 @@ | |||||||
|  | <!-- Generated by IcoMoon.io --> | ||||||
|  | <svg | ||||||
|  |   version="1.1" | ||||||
|  |   xmlns="http://www.w3.org/2000/svg" | ||||||
|  |   width="100%" | ||||||
|  |   height="100%" | ||||||
|  |   viewBox="0 0 768 768" | ||||||
|  | > | ||||||
|  |   <g id="icomoon-ignore"> </g> | ||||||
|  |   <path | ||||||
|  |     d="M761.2 675.3l-320-639.9c-10.8-21.8-32.8-35.4-57.2-35.4-24.5 0-46.4 13.6-57.2 35.4l-320 639.9c-4.4 8.8-6.8 18.7-6.8 28.7 0 35.3 28.7 64 64 64h640c35.3 0 64-28.7 64-64 0-10-2.4-19.9-6.8-28.7zM64 704l320-640c0 0 0 0 0 0l320 640h-640zM704 704c0 0 0 0 0 0s0.1 0 0 0c0.1 0 0 0 0 0z" | ||||||
|  |   ></path> | ||||||
|  |   <path | ||||||
|  |     d="M369.7 164.1l-242.3 484.7c-2.5 5-2.2 10.8 0.7 15.6 2.9 4.7 8.1 7.6 13.6 7.6h146.3v-32h-120.4l216.4-432.9 216.4 432.9h-120.4v32h146.3c5.5 0 10.7-2.9 13.6-7.6s3.2-10.6 0.7-15.6l-242.3-484.7c-2.7-5.4-8.3-8.8-14.3-8.8-6.1 0-11.6 3.4-14.3 8.8z" | ||||||
|  |   ></path> | ||||||
|  |   <path d="M352 352h64v224h-64v-224z"></path> | ||||||
|  |   <path d="M352 608h64v64h-64v-64z"></path> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 845 B | 
							
								
								
									
										22
									
								
								frontend/src/icons/weight-1kg.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,22 @@ | |||||||
|  | <!-- Generated by IcoMoon.io --> | ||||||
|  | <svg | ||||||
|  |   version="1.1" | ||||||
|  |   xmlns="http://www.w3.org/2000/svg" | ||||||
|  |   width="100%" | ||||||
|  |   height="100%" | ||||||
|  |   viewBox="0 0 768 768" | ||||||
|  | > | ||||||
|  |   <g id="icomoon-ignore"> </g> | ||||||
|  |   <path | ||||||
|  |     d="M480 192c0-52.9-43.1-96-96-96s-96 43.1-96 96 43.1 96 96 96 96-43.1 96-96zM320 192c0-35.3 28.7-64 64-64s64 28.7 64 64-28.7 64-64 64c-35.3 0-64-28.7-64-64z" | ||||||
|  |   ></path> | ||||||
|  |   <path | ||||||
|  |     d="M764 683.5l-118.4-351.9c-8.6-26.1-32.9-43.6-60.6-43.6h-34.7c1.7-2.9 3.3-5.8 4.8-8.8 13.7-26.8 20.9-57 20.9-87.2 0-50.9-19.7-98.8-55.4-134.9s-83.3-56.4-134.1-57.1c-51.3-0.7-99.9 18.8-136.8 55-36.9 36.1-57.4 84.2-57.7 135.5-0.2 30.5 6.9 61 20.6 88.1 1.6 3.2 3.3 6.3 5.1 9.4h-34.7c-27.4 0-51.8 17.5-60.6 43.6l-118.5 351.8c-6.6 19.5-3.4 41.1 8.6 57.8s31.4 26.7 52 26.7h638.9c20.6 0 40-10 52-26.7s15.2-38.3 8.6-57.7zM585 352c0 0 0 0 0 0v0zM64.5 703.9l118.5-352h105c13.8 0 26-8.8 30.4-21.9s-0.1-27.5-11.2-35.7c-32.8-24.6-51.5-62.3-51.2-103.4 0.2-34.1 13.9-66.1 38.5-90.2 24.2-23.7 55.9-36.7 89.4-36.7 0.6 0 1.2 0 1.8 0 69.6 1 126.3 58.4 126.3 128 0 40.7-18.7 78-51.2 102.4-11 8.3-15.5 22.7-11.1 35.7s16.5 21.9 30.3 21.9h104.9l118.5 351.9h-638.9z" | ||||||
|  |   ></path> | ||||||
|  |   <path | ||||||
|  |     d="M358.6 494.6l-24-21.2-46.6 52.7v-110.1h-32v192h32v-33.5l3.7-4.2 44.3 44.3 22.6-22.6-45.7-45.7z" | ||||||
|  |   ></path> | ||||||
|  |   <path | ||||||
|  |     d="M480 488.6c-9.4-5.5-20.4-8.6-32-8.6-35.3 0-64 28.7-64 64s28.7 64 64 64c11.6 0 22.6-3.1 32-8.6v8.6c0 17.6-14.4 32-32 32h-64v32h64c35.3 0 64-28.7 64-64v-128h-32v8.6zM448 576c-17.6 0-32-14.4-32-32s14.4-32 32-32 32 14.4 32 32-14.4 32-32 32z" | ||||||
|  |   ></path> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 1.5 KiB | 
							
								
								
									
										7
									
								
								frontend/src/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,7 @@ | |||||||
|  | import App from "./App.svelte"; | ||||||
|  |  | ||||||
|  | const app = new App({ | ||||||
|  |   target: document.getElementById("app"), | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | export default app; | ||||||
							
								
								
									
										39
									
								
								frontend/src/utils/actions.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,39 @@ | |||||||
|  | export function sleep(hundredSeconds) { | ||||||
|  |   return new Promise((resolve) => setTimeout(resolve, hundredSeconds * 100)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const errorSeq = [ | ||||||
|  |   [0, 0, 1, 1], | ||||||
|  |   [0, 0, 0, 1], | ||||||
|  |   [0, 0, 1, 1], | ||||||
|  |   [0, 0, 0, 1], | ||||||
|  |   [0, 0, 1, 1], | ||||||
|  |   [0, 0, 0, 6], | ||||||
|  |   [0, 0, 1, 2], | ||||||
|  |   [0, 0, 0, 2], | ||||||
|  |   [0, 0, 1, 2], | ||||||
|  |   [0, 0, 0, 2], | ||||||
|  |   [0, 0, 1, 2], | ||||||
|  |   [0, 0, 0, 6], | ||||||
|  |   [0, 0, 1, 1], | ||||||
|  |   [0, 0, 0, 1], | ||||||
|  |   [0, 0, 1, 1], | ||||||
|  |   [0, 0, 0, 1], | ||||||
|  |   [0, 0, 1, 1], | ||||||
|  |   [0, 0, 0, 20], | ||||||
|  | ]; | ||||||
|  |  | ||||||
|  | export const trafficSeq = [ | ||||||
|  |   [0, 0, 1, 15], | ||||||
|  |   [0, 1, 1, 15], | ||||||
|  |   [1, 0, 0, 50], | ||||||
|  |   [0, 1, 0, 15], | ||||||
|  |   [0, 0, 1, 20], | ||||||
|  | ]; | ||||||
|  |  | ||||||
|  | export const warningSeq = [ | ||||||
|  |   [0, 1, 0, 3], | ||||||
|  |   [0, 0, 0, 3], | ||||||
|  |   [0, 1, 0, 3], | ||||||
|  |   [0, 0, 0, 10], | ||||||
|  | ]; | ||||||
							
								
								
									
										32
									
								
								frontend/src/utils/tower.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,32 @@ | |||||||
|  | let BASE_URL, BASE_PATH; | ||||||
|  |  | ||||||
|  | export function setupApi(url, path) { | ||||||
|  |   BASE_URL = url; | ||||||
|  |   BASE_PATH = path; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export async function getState() { | ||||||
|  |   const url = `${BASE_URL}${BASE_PATH}state`; | ||||||
|  |  | ||||||
|  |   return fetch(url).then((resp) => resp.json()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export async function toggle(color) { | ||||||
|  |   const url = `${BASE_URL}${BASE_PATH}toggle/${color}`; | ||||||
|  |   const options = { method: "POST" }; | ||||||
|  |  | ||||||
|  |   return fetch(url, options); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export async function setTower(colorStates) { | ||||||
|  |   const url = `${BASE_URL}${BASE_PATH}state/set`; | ||||||
|  |   const options = { | ||||||
|  |     method: "POST", | ||||||
|  |     header: { | ||||||
|  |       "Content-Type": "plain/text", | ||||||
|  |     }, | ||||||
|  |     body: colorStates.join(","), | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   return fetch(url, options); | ||||||
|  | } | ||||||
							
								
								
									
										15
									
								
								frontend/svelte.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,15 @@ | |||||||
|  | import preprocess from "svelte-preprocess"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   preprocess: preprocess({ | ||||||
|  |     scss: { | ||||||
|  |       // Optional: includePaths: ['src/styles'] | ||||||
|  |     }, | ||||||
|  |   }), | ||||||
|  |   compilerOptions: { | ||||||
|  |     dev: true, | ||||||
|  |     compatibility: { | ||||||
|  |       componentApi: 4, // 👈 This enables `new App()` to work | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  | }; | ||||||
							
								
								
									
										8
									
								
								frontend/vite.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,8 @@ | |||||||
|  | import { defineConfig } from "vite"; | ||||||
|  | import { svelte } from "@sveltejs/vite-plugin-svelte"; | ||||||
|  |  | ||||||
|  | export default defineConfig({ | ||||||
|  |   plugins: [svelte()], | ||||||
|  |   root: "./", | ||||||
|  |   publicDir: "public", | ||||||
|  | }); | ||||||
							
								
								
									
										687
									
								
								frontend/yarn.lock
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,687 @@ | |||||||
|  | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. | ||||||
|  | # yarn lockfile v1 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | "@ampproject/remapping@^2.3.0": | ||||||
|  |   version "2.3.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" | ||||||
|  |   integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== | ||||||
|  |   dependencies: | ||||||
|  |     "@jridgewell/gen-mapping" "^0.3.5" | ||||||
|  |     "@jridgewell/trace-mapping" "^0.3.24" | ||||||
|  |  | ||||||
|  | "@esbuild/aix-ppc64@0.21.5": | ||||||
|  |   version "0.21.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" | ||||||
|  |   integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ== | ||||||
|  |  | ||||||
|  | "@esbuild/android-arm64@0.21.5": | ||||||
|  |   version "0.21.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" | ||||||
|  |   integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A== | ||||||
|  |  | ||||||
|  | "@esbuild/android-arm@0.21.5": | ||||||
|  |   version "0.21.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" | ||||||
|  |   integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg== | ||||||
|  |  | ||||||
|  | "@esbuild/android-x64@0.21.5": | ||||||
|  |   version "0.21.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" | ||||||
|  |   integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA== | ||||||
|  |  | ||||||
|  | "@esbuild/darwin-arm64@0.21.5": | ||||||
|  |   version "0.21.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" | ||||||
|  |   integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== | ||||||
|  |  | ||||||
|  | "@esbuild/darwin-x64@0.21.5": | ||||||
|  |   version "0.21.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" | ||||||
|  |   integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw== | ||||||
|  |  | ||||||
|  | "@esbuild/freebsd-arm64@0.21.5": | ||||||
|  |   version "0.21.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" | ||||||
|  |   integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g== | ||||||
|  |  | ||||||
|  | "@esbuild/freebsd-x64@0.21.5": | ||||||
|  |   version "0.21.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" | ||||||
|  |   integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ== | ||||||
|  |  | ||||||
|  | "@esbuild/linux-arm64@0.21.5": | ||||||
|  |   version "0.21.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" | ||||||
|  |   integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q== | ||||||
|  |  | ||||||
|  | "@esbuild/linux-arm@0.21.5": | ||||||
|  |   version "0.21.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" | ||||||
|  |   integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA== | ||||||
|  |  | ||||||
|  | "@esbuild/linux-ia32@0.21.5": | ||||||
|  |   version "0.21.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" | ||||||
|  |   integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg== | ||||||
|  |  | ||||||
|  | "@esbuild/linux-loong64@0.21.5": | ||||||
|  |   version "0.21.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" | ||||||
|  |   integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg== | ||||||
|  |  | ||||||
|  | "@esbuild/linux-mips64el@0.21.5": | ||||||
|  |   version "0.21.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" | ||||||
|  |   integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg== | ||||||
|  |  | ||||||
|  | "@esbuild/linux-ppc64@0.21.5": | ||||||
|  |   version "0.21.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" | ||||||
|  |   integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w== | ||||||
|  |  | ||||||
|  | "@esbuild/linux-riscv64@0.21.5": | ||||||
|  |   version "0.21.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" | ||||||
|  |   integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA== | ||||||
|  |  | ||||||
|  | "@esbuild/linux-s390x@0.21.5": | ||||||
|  |   version "0.21.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" | ||||||
|  |   integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A== | ||||||
|  |  | ||||||
|  | "@esbuild/linux-x64@0.21.5": | ||||||
|  |   version "0.21.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" | ||||||
|  |   integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== | ||||||
|  |  | ||||||
|  | "@esbuild/netbsd-x64@0.21.5": | ||||||
|  |   version "0.21.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" | ||||||
|  |   integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg== | ||||||
|  |  | ||||||
|  | "@esbuild/openbsd-x64@0.21.5": | ||||||
|  |   version "0.21.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" | ||||||
|  |   integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow== | ||||||
|  |  | ||||||
|  | "@esbuild/sunos-x64@0.21.5": | ||||||
|  |   version "0.21.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" | ||||||
|  |   integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg== | ||||||
|  |  | ||||||
|  | "@esbuild/win32-arm64@0.21.5": | ||||||
|  |   version "0.21.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" | ||||||
|  |   integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A== | ||||||
|  |  | ||||||
|  | "@esbuild/win32-ia32@0.21.5": | ||||||
|  |   version "0.21.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" | ||||||
|  |   integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA== | ||||||
|  |  | ||||||
|  | "@esbuild/win32-x64@0.21.5": | ||||||
|  |   version "0.21.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" | ||||||
|  |   integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== | ||||||
|  |  | ||||||
|  | "@jridgewell/gen-mapping@^0.3.5": | ||||||
|  |   version "0.3.8" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz#4f0e06362e01362f823d348f1872b08f666d8142" | ||||||
|  |   integrity sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA== | ||||||
|  |   dependencies: | ||||||
|  |     "@jridgewell/set-array" "^1.2.1" | ||||||
|  |     "@jridgewell/sourcemap-codec" "^1.4.10" | ||||||
|  |     "@jridgewell/trace-mapping" "^0.3.24" | ||||||
|  |  | ||||||
|  | "@jridgewell/resolve-uri@^3.1.0": | ||||||
|  |   version "3.1.2" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" | ||||||
|  |   integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== | ||||||
|  |  | ||||||
|  | "@jridgewell/set-array@^1.2.1": | ||||||
|  |   version "1.2.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" | ||||||
|  |   integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== | ||||||
|  |  | ||||||
|  | "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15", "@jridgewell/sourcemap-codec@^1.5.0": | ||||||
|  |   version "1.5.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" | ||||||
|  |   integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== | ||||||
|  |  | ||||||
|  | "@jridgewell/trace-mapping@^0.3.24": | ||||||
|  |   version "0.3.25" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" | ||||||
|  |   integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== | ||||||
|  |   dependencies: | ||||||
|  |     "@jridgewell/resolve-uri" "^3.1.0" | ||||||
|  |     "@jridgewell/sourcemap-codec" "^1.4.14" | ||||||
|  |  | ||||||
|  | "@parcel/watcher-android-arm64@2.5.1": | ||||||
|  |   version "2.5.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz#507f836d7e2042f798c7d07ad19c3546f9848ac1" | ||||||
|  |   integrity sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA== | ||||||
|  |  | ||||||
|  | "@parcel/watcher-darwin-arm64@2.5.1": | ||||||
|  |   version "2.5.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz#3d26dce38de6590ef79c47ec2c55793c06ad4f67" | ||||||
|  |   integrity sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw== | ||||||
|  |  | ||||||
|  | "@parcel/watcher-darwin-x64@2.5.1": | ||||||
|  |   version "2.5.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz#99f3af3869069ccf774e4ddfccf7e64fd2311ef8" | ||||||
|  |   integrity sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg== | ||||||
|  |  | ||||||
|  | "@parcel/watcher-freebsd-x64@2.5.1": | ||||||
|  |   version "2.5.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz#14d6857741a9f51dfe51d5b08b7c8afdbc73ad9b" | ||||||
|  |   integrity sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ== | ||||||
|  |  | ||||||
|  | "@parcel/watcher-linux-arm-glibc@2.5.1": | ||||||
|  |   version "2.5.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz#43c3246d6892381db473bb4f663229ad20b609a1" | ||||||
|  |   integrity sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA== | ||||||
|  |  | ||||||
|  | "@parcel/watcher-linux-arm-musl@2.5.1": | ||||||
|  |   version "2.5.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz#663750f7090bb6278d2210de643eb8a3f780d08e" | ||||||
|  |   integrity sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q== | ||||||
|  |  | ||||||
|  | "@parcel/watcher-linux-arm64-glibc@2.5.1": | ||||||
|  |   version "2.5.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz#ba60e1f56977f7e47cd7e31ad65d15fdcbd07e30" | ||||||
|  |   integrity sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w== | ||||||
|  |  | ||||||
|  | "@parcel/watcher-linux-arm64-musl@2.5.1": | ||||||
|  |   version "2.5.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz#f7fbcdff2f04c526f96eac01f97419a6a99855d2" | ||||||
|  |   integrity sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg== | ||||||
|  |  | ||||||
|  | "@parcel/watcher-linux-x64-glibc@2.5.1": | ||||||
|  |   version "2.5.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz#4d2ea0f633eb1917d83d483392ce6181b6a92e4e" | ||||||
|  |   integrity sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A== | ||||||
|  |  | ||||||
|  | "@parcel/watcher-linux-x64-musl@2.5.1": | ||||||
|  |   version "2.5.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz#277b346b05db54f55657301dd77bdf99d63606ee" | ||||||
|  |   integrity sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg== | ||||||
|  |  | ||||||
|  | "@parcel/watcher-win32-arm64@2.5.1": | ||||||
|  |   version "2.5.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz#7e9e02a26784d47503de1d10e8eab6cceb524243" | ||||||
|  |   integrity sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw== | ||||||
|  |  | ||||||
|  | "@parcel/watcher-win32-ia32@2.5.1": | ||||||
|  |   version "2.5.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz#2d0f94fa59a873cdc584bf7f6b1dc628ddf976e6" | ||||||
|  |   integrity sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ== | ||||||
|  |  | ||||||
|  | "@parcel/watcher-win32-x64@2.5.1": | ||||||
|  |   version "2.5.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz#ae52693259664ba6f2228fa61d7ee44b64ea0947" | ||||||
|  |   integrity sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA== | ||||||
|  |  | ||||||
|  | "@parcel/watcher@^2.4.1": | ||||||
|  |   version "2.5.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.5.1.tgz#342507a9cfaaf172479a882309def1e991fb1200" | ||||||
|  |   integrity sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg== | ||||||
|  |   dependencies: | ||||||
|  |     detect-libc "^1.0.3" | ||||||
|  |     is-glob "^4.0.3" | ||||||
|  |     micromatch "^4.0.5" | ||||||
|  |     node-addon-api "^7.0.0" | ||||||
|  |   optionalDependencies: | ||||||
|  |     "@parcel/watcher-android-arm64" "2.5.1" | ||||||
|  |     "@parcel/watcher-darwin-arm64" "2.5.1" | ||||||
|  |     "@parcel/watcher-darwin-x64" "2.5.1" | ||||||
|  |     "@parcel/watcher-freebsd-x64" "2.5.1" | ||||||
|  |     "@parcel/watcher-linux-arm-glibc" "2.5.1" | ||||||
|  |     "@parcel/watcher-linux-arm-musl" "2.5.1" | ||||||
|  |     "@parcel/watcher-linux-arm64-glibc" "2.5.1" | ||||||
|  |     "@parcel/watcher-linux-arm64-musl" "2.5.1" | ||||||
|  |     "@parcel/watcher-linux-x64-glibc" "2.5.1" | ||||||
|  |     "@parcel/watcher-linux-x64-musl" "2.5.1" | ||||||
|  |     "@parcel/watcher-win32-arm64" "2.5.1" | ||||||
|  |     "@parcel/watcher-win32-ia32" "2.5.1" | ||||||
|  |     "@parcel/watcher-win32-x64" "2.5.1" | ||||||
|  |  | ||||||
|  | "@rollup/rollup-android-arm-eabi@4.40.0": | ||||||
|  |   version "4.40.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.0.tgz#d964ee8ce4d18acf9358f96adc408689b6e27fe3" | ||||||
|  |   integrity sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg== | ||||||
|  |  | ||||||
|  | "@rollup/rollup-android-arm64@4.40.0": | ||||||
|  |   version "4.40.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.0.tgz#9b5e130ecc32a5fc1e96c09ff371743ee71a62d3" | ||||||
|  |   integrity sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w== | ||||||
|  |  | ||||||
|  | "@rollup/rollup-darwin-arm64@4.40.0": | ||||||
|  |   version "4.40.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.0.tgz#ef439182c739b20b3c4398cfc03e3c1249ac8903" | ||||||
|  |   integrity sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ== | ||||||
|  |  | ||||||
|  | "@rollup/rollup-darwin-x64@4.40.0": | ||||||
|  |   version "4.40.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.0.tgz#d7380c1531ab0420ca3be16f17018ef72dd3d504" | ||||||
|  |   integrity sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA== | ||||||
|  |  | ||||||
|  | "@rollup/rollup-freebsd-arm64@4.40.0": | ||||||
|  |   version "4.40.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.0.tgz#cbcbd7248823c6b430ce543c59906dd3c6df0936" | ||||||
|  |   integrity sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg== | ||||||
|  |  | ||||||
|  | "@rollup/rollup-freebsd-x64@4.40.0": | ||||||
|  |   version "4.40.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.0.tgz#96bf6ff875bab5219c3472c95fa6eb992586a93b" | ||||||
|  |   integrity sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw== | ||||||
|  |  | ||||||
|  | "@rollup/rollup-linux-arm-gnueabihf@4.40.0": | ||||||
|  |   version "4.40.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.0.tgz#d80cd62ce6d40f8e611008d8dbf03b5e6bbf009c" | ||||||
|  |   integrity sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA== | ||||||
|  |  | ||||||
|  | "@rollup/rollup-linux-arm-musleabihf@4.40.0": | ||||||
|  |   version "4.40.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.0.tgz#75440cfc1e8d0f87a239b4c31dfeaf4719b656b7" | ||||||
|  |   integrity sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg== | ||||||
|  |  | ||||||
|  | "@rollup/rollup-linux-arm64-gnu@4.40.0": | ||||||
|  |   version "4.40.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.0.tgz#ac527485ecbb619247fb08253ec8c551a0712e7c" | ||||||
|  |   integrity sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg== | ||||||
|  |  | ||||||
|  | "@rollup/rollup-linux-arm64-musl@4.40.0": | ||||||
|  |   version "4.40.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.0.tgz#74d2b5cb11cf714cd7d1682e7c8b39140e908552" | ||||||
|  |   integrity sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ== | ||||||
|  |  | ||||||
|  | "@rollup/rollup-linux-loongarch64-gnu@4.40.0": | ||||||
|  |   version "4.40.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.0.tgz#a0a310e51da0b5fea0e944b0abd4be899819aef6" | ||||||
|  |   integrity sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg== | ||||||
|  |  | ||||||
|  | "@rollup/rollup-linux-powerpc64le-gnu@4.40.0": | ||||||
|  |   version "4.40.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.0.tgz#4077e2862b0ac9f61916d6b474d988171bd43b83" | ||||||
|  |   integrity sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw== | ||||||
|  |  | ||||||
|  | "@rollup/rollup-linux-riscv64-gnu@4.40.0": | ||||||
|  |   version "4.40.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.0.tgz#5812a1a7a2f9581cbe12597307cc7ba3321cf2f3" | ||||||
|  |   integrity sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA== | ||||||
|  |  | ||||||
|  | "@rollup/rollup-linux-riscv64-musl@4.40.0": | ||||||
|  |   version "4.40.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.0.tgz#973aaaf4adef4531375c36616de4e01647f90039" | ||||||
|  |   integrity sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ== | ||||||
|  |  | ||||||
|  | "@rollup/rollup-linux-s390x-gnu@4.40.0": | ||||||
|  |   version "4.40.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.0.tgz#9bad59e907ba5bfcf3e9dbd0247dfe583112f70b" | ||||||
|  |   integrity sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw== | ||||||
|  |  | ||||||
|  | "@rollup/rollup-linux-x64-gnu@4.40.0": | ||||||
|  |   version "4.40.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.0.tgz#68b045a720bd9b4d905f462b997590c2190a6de0" | ||||||
|  |   integrity sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ== | ||||||
|  |  | ||||||
|  | "@rollup/rollup-linux-x64-musl@4.40.0": | ||||||
|  |   version "4.40.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.0.tgz#8e703e2c2ad19ba7b2cb3d8c3a4ad11d4ee3a282" | ||||||
|  |   integrity sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw== | ||||||
|  |  | ||||||
|  | "@rollup/rollup-win32-arm64-msvc@4.40.0": | ||||||
|  |   version "4.40.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.0.tgz#c5bee19fa670ff5da5f066be6a58b4568e9c650b" | ||||||
|  |   integrity sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ== | ||||||
|  |  | ||||||
|  | "@rollup/rollup-win32-ia32-msvc@4.40.0": | ||||||
|  |   version "4.40.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.0.tgz#846e02c17044bd922f6f483a3b4d36aac6e2b921" | ||||||
|  |   integrity sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA== | ||||||
|  |  | ||||||
|  | "@rollup/rollup-win32-x64-msvc@4.40.0": | ||||||
|  |   version "4.40.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.0.tgz#fd92d31a2931483c25677b9c6698106490cbbc76" | ||||||
|  |   integrity sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ== | ||||||
|  |  | ||||||
|  | "@sveltejs/acorn-typescript@^1.0.5": | ||||||
|  |   version "1.0.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz#f518101d1b2e12ce80854f1cd850d3b9fb91d710" | ||||||
|  |   integrity sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ== | ||||||
|  |  | ||||||
|  | "@sveltejs/vite-plugin-svelte-inspector@^1.0.4": | ||||||
|  |   version "1.0.4" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-1.0.4.tgz#c99fcb73aaa845a3e2c0563409aeb3ee0b863add" | ||||||
|  |   integrity sha512-zjiuZ3yydBtwpF3bj0kQNV0YXe+iKE545QGZVTaylW3eAzFr+pJ/cwK8lZEaRp4JtaJXhD5DyWAV4AxLh6DgaQ== | ||||||
|  |   dependencies: | ||||||
|  |     debug "^4.3.4" | ||||||
|  |  | ||||||
|  | "@sveltejs/vite-plugin-svelte@^2.0.0": | ||||||
|  |   version "2.5.3" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-2.5.3.tgz#23f810d0c38d159491845175c2566a51639be3fc" | ||||||
|  |   integrity sha512-erhNtXxE5/6xGZz/M9eXsmI7Pxa6MS7jyTy06zN3Ck++ldrppOnOlJwHHTsMC7DHDQdgUp4NAc4cDNQ9eGdB/w== | ||||||
|  |   dependencies: | ||||||
|  |     "@sveltejs/vite-plugin-svelte-inspector" "^1.0.4" | ||||||
|  |     debug "^4.3.4" | ||||||
|  |     deepmerge "^4.3.1" | ||||||
|  |     kleur "^4.1.5" | ||||||
|  |     magic-string "^0.30.3" | ||||||
|  |     svelte-hmr "^0.15.3" | ||||||
|  |     vitefu "^0.2.4" | ||||||
|  |  | ||||||
|  | "@types/estree@1.0.7", "@types/estree@^1.0.5", "@types/estree@^1.0.6": | ||||||
|  |   version "1.0.7" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.7.tgz#4158d3105276773d5b7695cd4834b1722e4f37a8" | ||||||
|  |   integrity sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ== | ||||||
|  |  | ||||||
|  | acorn@^8.12.1: | ||||||
|  |   version "8.14.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.1.tgz#721d5dc10f7d5b5609a891773d47731796935dfb" | ||||||
|  |   integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg== | ||||||
|  |  | ||||||
|  | aria-query@^5.3.1: | ||||||
|  |   version "5.3.2" | ||||||
|  |   resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.2.tgz#93f81a43480e33a338f19163a3d10a50c01dcd59" | ||||||
|  |   integrity sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw== | ||||||
|  |  | ||||||
|  | axobject-query@^4.1.0: | ||||||
|  |   version "4.1.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-4.1.0.tgz#28768c76d0e3cff21bc62a9e2d0b6ac30042a1ee" | ||||||
|  |   integrity sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ== | ||||||
|  |  | ||||||
|  | braces@^3.0.3: | ||||||
|  |   version "3.0.3" | ||||||
|  |   resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" | ||||||
|  |   integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== | ||||||
|  |   dependencies: | ||||||
|  |     fill-range "^7.1.1" | ||||||
|  |  | ||||||
|  | chokidar@^4.0.0: | ||||||
|  |   version "4.0.3" | ||||||
|  |   resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30" | ||||||
|  |   integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA== | ||||||
|  |   dependencies: | ||||||
|  |     readdirp "^4.0.1" | ||||||
|  |  | ||||||
|  | clsx@^2.1.1: | ||||||
|  |   version "2.1.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" | ||||||
|  |   integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== | ||||||
|  |  | ||||||
|  | debug@^4.3.4: | ||||||
|  |   version "4.4.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" | ||||||
|  |   integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== | ||||||
|  |   dependencies: | ||||||
|  |     ms "^2.1.3" | ||||||
|  |  | ||||||
|  | deepmerge@^4.3.1: | ||||||
|  |   version "4.3.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" | ||||||
|  |   integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== | ||||||
|  |  | ||||||
|  | detect-libc@^1.0.3: | ||||||
|  |   version "1.0.3" | ||||||
|  |   resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" | ||||||
|  |   integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== | ||||||
|  |  | ||||||
|  | esbuild@^0.21.3: | ||||||
|  |   version "0.21.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d" | ||||||
|  |   integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw== | ||||||
|  |   optionalDependencies: | ||||||
|  |     "@esbuild/aix-ppc64" "0.21.5" | ||||||
|  |     "@esbuild/android-arm" "0.21.5" | ||||||
|  |     "@esbuild/android-arm64" "0.21.5" | ||||||
|  |     "@esbuild/android-x64" "0.21.5" | ||||||
|  |     "@esbuild/darwin-arm64" "0.21.5" | ||||||
|  |     "@esbuild/darwin-x64" "0.21.5" | ||||||
|  |     "@esbuild/freebsd-arm64" "0.21.5" | ||||||
|  |     "@esbuild/freebsd-x64" "0.21.5" | ||||||
|  |     "@esbuild/linux-arm" "0.21.5" | ||||||
|  |     "@esbuild/linux-arm64" "0.21.5" | ||||||
|  |     "@esbuild/linux-ia32" "0.21.5" | ||||||
|  |     "@esbuild/linux-loong64" "0.21.5" | ||||||
|  |     "@esbuild/linux-mips64el" "0.21.5" | ||||||
|  |     "@esbuild/linux-ppc64" "0.21.5" | ||||||
|  |     "@esbuild/linux-riscv64" "0.21.5" | ||||||
|  |     "@esbuild/linux-s390x" "0.21.5" | ||||||
|  |     "@esbuild/linux-x64" "0.21.5" | ||||||
|  |     "@esbuild/netbsd-x64" "0.21.5" | ||||||
|  |     "@esbuild/openbsd-x64" "0.21.5" | ||||||
|  |     "@esbuild/sunos-x64" "0.21.5" | ||||||
|  |     "@esbuild/win32-arm64" "0.21.5" | ||||||
|  |     "@esbuild/win32-ia32" "0.21.5" | ||||||
|  |     "@esbuild/win32-x64" "0.21.5" | ||||||
|  |  | ||||||
|  | esm-env@^1.2.1: | ||||||
|  |   version "1.2.2" | ||||||
|  |   resolved "https://registry.yarnpkg.com/esm-env/-/esm-env-1.2.2.tgz#263c9455c55861f41618df31b20cb571fc20b75e" | ||||||
|  |   integrity sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA== | ||||||
|  |  | ||||||
|  | esrap@^1.4.6: | ||||||
|  |   version "1.4.6" | ||||||
|  |   resolved "https://registry.yarnpkg.com/esrap/-/esrap-1.4.6.tgz#d203ce1ee397aa2a6a716a3a2dc8619f83208c6a" | ||||||
|  |   integrity sha512-F/D2mADJ9SHY3IwksD4DAXjTt7qt7GWUf3/8RhCNWmC/67tyb55dpimHmy7EplakFaflV0R/PC+fdSPqrRHAQw== | ||||||
|  |   dependencies: | ||||||
|  |     "@jridgewell/sourcemap-codec" "^1.4.15" | ||||||
|  |  | ||||||
|  | fill-range@^7.1.1: | ||||||
|  |   version "7.1.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" | ||||||
|  |   integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== | ||||||
|  |   dependencies: | ||||||
|  |     to-regex-range "^5.0.1" | ||||||
|  |  | ||||||
|  | fsevents@~2.3.2, fsevents@~2.3.3: | ||||||
|  |   version "2.3.3" | ||||||
|  |   resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" | ||||||
|  |   integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== | ||||||
|  |  | ||||||
|  | immutable@^5.0.2: | ||||||
|  |   version "5.1.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/immutable/-/immutable-5.1.1.tgz#d4cb552686f34b076b3dcf23c4384c04424d8354" | ||||||
|  |   integrity sha512-3jatXi9ObIsPGr3N5hGw/vWWcTkq6hUYhpQz4k0wLC+owqWi/LiugIw9x0EdNZ2yGedKN/HzePiBvaJRXa0Ujg== | ||||||
|  |  | ||||||
|  | is-extglob@^2.1.1: | ||||||
|  |   version "2.1.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" | ||||||
|  |   integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== | ||||||
|  |  | ||||||
|  | is-glob@^4.0.3: | ||||||
|  |   version "4.0.3" | ||||||
|  |   resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" | ||||||
|  |   integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== | ||||||
|  |   dependencies: | ||||||
|  |     is-extglob "^2.1.1" | ||||||
|  |  | ||||||
|  | is-number@^7.0.0: | ||||||
|  |   version "7.0.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" | ||||||
|  |   integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== | ||||||
|  |  | ||||||
|  | is-reference@^3.0.3: | ||||||
|  |   version "3.0.3" | ||||||
|  |   resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-3.0.3.tgz#9ef7bf9029c70a67b2152da4adf57c23d718910f" | ||||||
|  |   integrity sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw== | ||||||
|  |   dependencies: | ||||||
|  |     "@types/estree" "^1.0.6" | ||||||
|  |  | ||||||
|  | kleur@^4.1.5: | ||||||
|  |   version "4.1.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780" | ||||||
|  |   integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ== | ||||||
|  |  | ||||||
|  | locate-character@^3.0.0: | ||||||
|  |   version "3.0.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/locate-character/-/locate-character-3.0.0.tgz#0305c5b8744f61028ef5d01f444009e00779f974" | ||||||
|  |   integrity sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA== | ||||||
|  |  | ||||||
|  | magic-string@^0.30.11, magic-string@^0.30.3: | ||||||
|  |   version "0.30.17" | ||||||
|  |   resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453" | ||||||
|  |   integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA== | ||||||
|  |   dependencies: | ||||||
|  |     "@jridgewell/sourcemap-codec" "^1.5.0" | ||||||
|  |  | ||||||
|  | micromatch@^4.0.5: | ||||||
|  |   version "4.0.8" | ||||||
|  |   resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" | ||||||
|  |   integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== | ||||||
|  |   dependencies: | ||||||
|  |     braces "^3.0.3" | ||||||
|  |     picomatch "^2.3.1" | ||||||
|  |  | ||||||
|  | ms@^2.1.3: | ||||||
|  |   version "2.1.3" | ||||||
|  |   resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" | ||||||
|  |   integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== | ||||||
|  |  | ||||||
|  | nanoid@^3.3.8: | ||||||
|  |   version "3.3.11" | ||||||
|  |   resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" | ||||||
|  |   integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== | ||||||
|  |  | ||||||
|  | node-addon-api@^7.0.0: | ||||||
|  |   version "7.1.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558" | ||||||
|  |   integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ== | ||||||
|  |  | ||||||
|  | picocolors@^1.1.1: | ||||||
|  |   version "1.1.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" | ||||||
|  |   integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== | ||||||
|  |  | ||||||
|  | picomatch@^2.3.1: | ||||||
|  |   version "2.3.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" | ||||||
|  |   integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== | ||||||
|  |  | ||||||
|  | postcss@^8.4.43: | ||||||
|  |   version "8.5.3" | ||||||
|  |   resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.3.tgz#1463b6f1c7fb16fe258736cba29a2de35237eafb" | ||||||
|  |   integrity sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A== | ||||||
|  |   dependencies: | ||||||
|  |     nanoid "^3.3.8" | ||||||
|  |     picocolors "^1.1.1" | ||||||
|  |     source-map-js "^1.2.1" | ||||||
|  |  | ||||||
|  | prettier-plugin-svelte@^3.3.3: | ||||||
|  |   version "3.3.3" | ||||||
|  |   resolved "https://registry.yarnpkg.com/prettier-plugin-svelte/-/prettier-plugin-svelte-3.3.3.tgz#49d5c025a1516063ac7ef026806f880caa310424" | ||||||
|  |   integrity sha512-yViK9zqQ+H2qZD1w/bH7W8i+bVfKrD8GIFjkFe4Thl6kCT9SlAsXVNmt3jCvQOCsnOhcvYgsoVlRV/Eu6x5nNw== | ||||||
|  |  | ||||||
|  | prettier@^3.5.3: | ||||||
|  |   version "3.5.3" | ||||||
|  |   resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.5.3.tgz#4fc2ce0d657e7a02e602549f053b239cb7dfe1b5" | ||||||
|  |   integrity sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw== | ||||||
|  |  | ||||||
|  | readdirp@^4.0.1: | ||||||
|  |   version "4.1.2" | ||||||
|  |   resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.1.2.tgz#eb85801435fbf2a7ee58f19e0921b068fc69948d" | ||||||
|  |   integrity sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg== | ||||||
|  |  | ||||||
|  | rollup@^4.20.0: | ||||||
|  |   version "4.40.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.40.0.tgz#13742a615f423ccba457554f006873d5a4de1920" | ||||||
|  |   integrity sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w== | ||||||
|  |   dependencies: | ||||||
|  |     "@types/estree" "1.0.7" | ||||||
|  |   optionalDependencies: | ||||||
|  |     "@rollup/rollup-android-arm-eabi" "4.40.0" | ||||||
|  |     "@rollup/rollup-android-arm64" "4.40.0" | ||||||
|  |     "@rollup/rollup-darwin-arm64" "4.40.0" | ||||||
|  |     "@rollup/rollup-darwin-x64" "4.40.0" | ||||||
|  |     "@rollup/rollup-freebsd-arm64" "4.40.0" | ||||||
|  |     "@rollup/rollup-freebsd-x64" "4.40.0" | ||||||
|  |     "@rollup/rollup-linux-arm-gnueabihf" "4.40.0" | ||||||
|  |     "@rollup/rollup-linux-arm-musleabihf" "4.40.0" | ||||||
|  |     "@rollup/rollup-linux-arm64-gnu" "4.40.0" | ||||||
|  |     "@rollup/rollup-linux-arm64-musl" "4.40.0" | ||||||
|  |     "@rollup/rollup-linux-loongarch64-gnu" "4.40.0" | ||||||
|  |     "@rollup/rollup-linux-powerpc64le-gnu" "4.40.0" | ||||||
|  |     "@rollup/rollup-linux-riscv64-gnu" "4.40.0" | ||||||
|  |     "@rollup/rollup-linux-riscv64-musl" "4.40.0" | ||||||
|  |     "@rollup/rollup-linux-s390x-gnu" "4.40.0" | ||||||
|  |     "@rollup/rollup-linux-x64-gnu" "4.40.0" | ||||||
|  |     "@rollup/rollup-linux-x64-musl" "4.40.0" | ||||||
|  |     "@rollup/rollup-win32-arm64-msvc" "4.40.0" | ||||||
|  |     "@rollup/rollup-win32-ia32-msvc" "4.40.0" | ||||||
|  |     "@rollup/rollup-win32-x64-msvc" "4.40.0" | ||||||
|  |     fsevents "~2.3.2" | ||||||
|  |  | ||||||
|  | sass@^1.86.3: | ||||||
|  |   version "1.86.3" | ||||||
|  |   resolved "https://registry.yarnpkg.com/sass/-/sass-1.86.3.tgz#0a0d9ea97cb6665e73f409639f8533ce057464c9" | ||||||
|  |   integrity sha512-iGtg8kus4GrsGLRDLRBRHY9dNVA78ZaS7xr01cWnS7PEMQyFtTqBiyCrfpTYTZXRWM94akzckYjh8oADfFNTzw== | ||||||
|  |   dependencies: | ||||||
|  |     chokidar "^4.0.0" | ||||||
|  |     immutable "^5.0.2" | ||||||
|  |     source-map-js ">=0.6.2 <2.0.0" | ||||||
|  |   optionalDependencies: | ||||||
|  |     "@parcel/watcher" "^2.4.1" | ||||||
|  |  | ||||||
|  | "source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.2.1: | ||||||
|  |   version "1.2.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" | ||||||
|  |   integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== | ||||||
|  |  | ||||||
|  | svelte-hmr@^0.15.3: | ||||||
|  |   version "0.15.3" | ||||||
|  |   resolved "https://registry.yarnpkg.com/svelte-hmr/-/svelte-hmr-0.15.3.tgz#df54ccde9be3f091bf5f18fc4ef7b8eb6405fbe6" | ||||||
|  |   integrity sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ== | ||||||
|  |  | ||||||
|  | svelte-preprocess@^6.0.3: | ||||||
|  |   version "6.0.3" | ||||||
|  |   resolved "https://registry.yarnpkg.com/svelte-preprocess/-/svelte-preprocess-6.0.3.tgz#fdc1f9dc41b6f22bf8b1f059e9f21eaaae181eeb" | ||||||
|  |   integrity sha512-PLG2k05qHdhmRG7zR/dyo5qKvakhm8IJ+hD2eFRQmMLHp7X3eJnjeupUtvuRpbNiF31RjVw45W+abDwHEmP5OA== | ||||||
|  |  | ||||||
|  | svelte@5.28.1: | ||||||
|  |   version "5.28.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/svelte/-/svelte-5.28.1.tgz#4a0cd28c92ea23f4d5caa8eaf0e8d0af6c83c397" | ||||||
|  |   integrity sha512-iOa9WmfNG95lSOSJdMhdjJ4Afok7IRAQYXpbnxhd5EINnXseG0GVa9j6WPght4eX78XfFez45Fi+uRglGKPV/Q== | ||||||
|  |   dependencies: | ||||||
|  |     "@ampproject/remapping" "^2.3.0" | ||||||
|  |     "@jridgewell/sourcemap-codec" "^1.5.0" | ||||||
|  |     "@sveltejs/acorn-typescript" "^1.0.5" | ||||||
|  |     "@types/estree" "^1.0.5" | ||||||
|  |     acorn "^8.12.1" | ||||||
|  |     aria-query "^5.3.1" | ||||||
|  |     axobject-query "^4.1.0" | ||||||
|  |     clsx "^2.1.1" | ||||||
|  |     esm-env "^1.2.1" | ||||||
|  |     esrap "^1.4.6" | ||||||
|  |     is-reference "^3.0.3" | ||||||
|  |     locate-character "^3.0.0" | ||||||
|  |     magic-string "^0.30.11" | ||||||
|  |     zimmerframe "^1.1.2" | ||||||
|  |  | ||||||
|  | to-regex-range@^5.0.1: | ||||||
|  |   version "5.0.1" | ||||||
|  |   resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" | ||||||
|  |   integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== | ||||||
|  |   dependencies: | ||||||
|  |     is-number "^7.0.0" | ||||||
|  |  | ||||||
|  | vite@^5.0.0: | ||||||
|  |   version "5.4.18" | ||||||
|  |   resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.18.tgz#b5af357f9d5ebb2e0c085779b7a37a77f09168a4" | ||||||
|  |   integrity sha512-1oDcnEp3lVyHCuQ2YFelM4Alm2o91xNoMncRm1U7S+JdYfYOvbiGZ3/CxGttrOu2M/KcGz7cRC2DoNUA6urmMA== | ||||||
|  |   dependencies: | ||||||
|  |     esbuild "^0.21.3" | ||||||
|  |     postcss "^8.4.43" | ||||||
|  |     rollup "^4.20.0" | ||||||
|  |   optionalDependencies: | ||||||
|  |     fsevents "~2.3.3" | ||||||
|  |  | ||||||
|  | vitefu@^0.2.4: | ||||||
|  |   version "0.2.5" | ||||||
|  |   resolved "https://registry.yarnpkg.com/vitefu/-/vitefu-0.2.5.tgz#c1b93c377fbdd3e5ddd69840ea3aa70b40d90969" | ||||||
|  |   integrity sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q== | ||||||
|  |  | ||||||
|  | zimmerframe@^1.1.2: | ||||||
|  |   version "1.1.2" | ||||||
|  |   resolved "https://registry.yarnpkg.com/zimmerframe/-/zimmerframe-1.1.2.tgz#5b75f1fa83b07ae2a428d51e50f58e2ae6855e5e" | ||||||
|  |   integrity sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w== | ||||||
							
								
								
									
										62
									
								
								server/database.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,62 @@ | |||||||
|  | import sqlite3 | ||||||
|  | from contextlib import closing | ||||||
|  |  | ||||||
|  | DB_FILE = 'lights.db' | ||||||
|  | DEFAULT_LIGHTS = ['green', 'orange', 'red'] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def connect(): | ||||||
|  |     """Get a new connection to the database.""" | ||||||
|  |     return sqlite3.connect(DB_FILE) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def setup_database(): | ||||||
|  |     """Initializes the database and sets default states for lights.""" | ||||||
|  |     with closing(connect()) as conn: | ||||||
|  |         with conn: | ||||||
|  |             conn.execute(''' | ||||||
|  |                 CREATE TABLE IF NOT EXISTS light_state ( | ||||||
|  |                     name TEXT PRIMARY KEY, | ||||||
|  |                     state INTEGER NOT NULL CHECK (state IN (0, 1)) | ||||||
|  |                 ) | ||||||
|  |             ''') | ||||||
|  |  | ||||||
|  |             # Insert default lights with state=0 if they do not exist | ||||||
|  |             for light in DEFAULT_LIGHTS: | ||||||
|  |                 conn.execute(''' | ||||||
|  |                     INSERT OR IGNORE INTO light_state (name, state) | ||||||
|  |                     VALUES (?, 0) | ||||||
|  |                 ''', (light,)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def ensure_database(): | ||||||
|  |     """Ensures the DB is initialized. Safe to call multiple times.""" | ||||||
|  |     setup_database() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def set_light_state(name, state): | ||||||
|  |     ensure_database() | ||||||
|  |     with closing(connect()) as conn: | ||||||
|  |         with conn: | ||||||
|  |             conn.execute(''' | ||||||
|  |                 INSERT INTO light_state (name, state) | ||||||
|  |                 VALUES (?, ?) | ||||||
|  |                 ON CONFLICT(name) DO UPDATE SET state = excluded.state | ||||||
|  |             ''', (name, state)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def get_light_state(name): | ||||||
|  |     ensure_database() | ||||||
|  |     with closing(connect()) as conn: | ||||||
|  |         cur = conn.cursor() | ||||||
|  |         cur.execute('SELECT state FROM light_state WHERE name = ?', (name,)) | ||||||
|  |         row = cur.fetchone() | ||||||
|  |         return row[0] if row else 0 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def get_all_states(): | ||||||
|  |     ensure_database() | ||||||
|  |     with closing(connect()) as conn: | ||||||
|  |         cur = conn.cursor() | ||||||
|  |         cur.execute('SELECT name, state FROM light_state') | ||||||
|  |         return dict(cur.fetchall()) | ||||||
							
								
								
									
										73
									
								
								server/light.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,73 @@ | |||||||
|  | import RPi.GPIO as GPIO | ||||||
|  | import time | ||||||
|  | import database | ||||||
|  |  | ||||||
|  | FUNCTIONS = ['green', 'orange', 'red'] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Light: | ||||||
|  |     def __init__(self, pin, name): | ||||||
|  |         self.pin = pin | ||||||
|  |         self.name = name | ||||||
|  |         self.state = database.get_light_state(name) | ||||||
|  |         self.setup() | ||||||
|  |  | ||||||
|  |     def setup(self): | ||||||
|  |         GPIO.setmode(GPIO.BCM) | ||||||
|  |         GPIO.setup(self.pin, GPIO.OUT) | ||||||
|  |         self._set(self.state) | ||||||
|  |  | ||||||
|  |     def _set(self, state): | ||||||
|  |         if state == self.state: | ||||||
|  |             print('%s is equal %s' % (state, self.state,)) | ||||||
|  |  | ||||||
|  |         print('setting %s state to: %s' % (self.name, state,)) | ||||||
|  |         GPIO.output(self.pin, GPIO.LOW if state == GPIO.HIGH else GPIO.HIGH) | ||||||
|  |         self.state = state | ||||||
|  |         database.set_light_state(self.name, state) | ||||||
|  |  | ||||||
|  |     def on(self): | ||||||
|  |         self._set(GPIO.HIGH) | ||||||
|  |  | ||||||
|  |     def off(self): | ||||||
|  |         self._set(GPIO.LOW) | ||||||
|  |  | ||||||
|  |     def flash(self, count=2, interval=0.2): | ||||||
|  |         for _ in range(count): | ||||||
|  |             self.on() | ||||||
|  |             time.sleep(interval) | ||||||
|  |             self.off() | ||||||
|  |             time.sleep(interval) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Tower: | ||||||
|  |     def __init__(self, pinList): | ||||||
|  |         self.pins = pinList | ||||||
|  |         self.setupLights() | ||||||
|  |         self.green: Light | ||||||
|  |         self.orange: Light | ||||||
|  |         self.red: Light | ||||||
|  |  | ||||||
|  |     def setupLights(self): | ||||||
|  |         if len(FUNCTIONS) != len(self.pins): | ||||||
|  |             raise ValueError("only %s pins provided, but %s available" % | ||||||
|  |                              (len(self.pins), len(FUNCTIONS))) | ||||||
|  |  | ||||||
|  |         for pin in self.pins: | ||||||
|  |             light = Light(pin['pin'], pin['name']) | ||||||
|  |             if light.name == 'green': | ||||||
|  |                 self.green = light | ||||||
|  |             elif light.name == 'orange': | ||||||
|  |                 self.orange = light | ||||||
|  |             elif light.name == 'red': | ||||||
|  |                 self.red = light | ||||||
|  |  | ||||||
|  |     def on(self): | ||||||
|  |         self.green.on() | ||||||
|  |         self.orange.on() | ||||||
|  |         self.red.on() | ||||||
|  |  | ||||||
|  |     def off(self): | ||||||
|  |         self.green.off() | ||||||
|  |         self.orange.off() | ||||||
|  |         self.red.off() | ||||||
							
								
								
									
										100
									
								
								server/main.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,100 @@ | |||||||
|  | import time | ||||||
|  | import argparse | ||||||
|  | import RPi.GPIO as GPIO | ||||||
|  | from light import Tower | ||||||
|  | import database | ||||||
|  | from flask import Flask, jsonify, request | ||||||
|  |  | ||||||
|  | # Pins configuration (order: green, orange, red) | ||||||
|  | GPIO_PINS = [{'name': 'green', 'pin': 22}, | ||||||
|  |              {'name': 'orange', 'pin': 17}, | ||||||
|  |              {'name': 'red', 'pin': 27}] | ||||||
|  |  | ||||||
|  | # Create a Flask app | ||||||
|  | app = Flask(__name__) | ||||||
|  |  | ||||||
|  | # Initialize the database | ||||||
|  | database.ensure_database() | ||||||
|  |  | ||||||
|  | # Initialize the tower (lights) | ||||||
|  | tower = Tower(GPIO_PINS) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @app.after_request | ||||||
|  | def add_cors_headers(response): | ||||||
|  |     response.headers['Access-Control-Allow-Origin'] = '*' | ||||||
|  |     response.headers['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS' | ||||||
|  |     response.headers['Access-Control-Allow-Headers'] = 'Content-Type' | ||||||
|  |     return response | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @app.route('/api/state/set', methods=['POST']) | ||||||
|  | def set_state(): | ||||||
|  |     data = request.data.decode('utf-8') | ||||||
|  |     state = [int(n.strip()) for n in data.split(',') if n.strip().isdigit()] | ||||||
|  |     """Endpoint to get the current state of all lights.""" | ||||||
|  |     tower.green.on() if state[0] else tower.green.off() | ||||||
|  |     tower.orange.on() if state[1] else tower.orange.off() | ||||||
|  |     tower.red.on() if state[2] else tower.red.off() | ||||||
|  |  | ||||||
|  |     return jsonify(state) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @app.route('/api/state', methods=['GET']) | ||||||
|  | def get_state(): | ||||||
|  |     """Endpoint to get the current state of all lights.""" | ||||||
|  |     state = database.get_all_states() | ||||||
|  |     return jsonify(state) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @app.route('/api/toggle/<color>', methods=['POST']) | ||||||
|  | def toggle_light(color): | ||||||
|  |     """Endpoint to toggle the state of a specified light.""" | ||||||
|  |     if color not in ['green', 'orange', 'red']: | ||||||
|  |         return jsonify({'error': 'Invalid color'}), 404 | ||||||
|  |  | ||||||
|  |     # Get the light object based on the color | ||||||
|  |     light = getattr(tower, color) | ||||||
|  |  | ||||||
|  |     # Toggle light state (on/off) | ||||||
|  |     new_state = GPIO.LOW if light.state == GPIO.HIGH else GPIO.HIGH | ||||||
|  |     light._set(new_state)  # Update the light state in the system | ||||||
|  |  | ||||||
|  |     return jsonify({color: new_state}) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def run(tower): | ||||||
|  |     """Run the tower with manual light control.""" | ||||||
|  |     try: | ||||||
|  |         time.sleep(0.5) | ||||||
|  |         while True: | ||||||
|  |             print('on') | ||||||
|  |             tower.green.on() | ||||||
|  |             tower.red.off() | ||||||
|  |             tower.orange.off() | ||||||
|  |  | ||||||
|  |             time.sleep(10) | ||||||
|  |     except KeyboardInterrupt: | ||||||
|  |         print("\nInterrupted by user. Cleaning up...") | ||||||
|  |     finally: | ||||||
|  |         GPIO.cleanup() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def main(): | ||||||
|  |     parser = argparse.ArgumentParser( | ||||||
|  |         description="Control lights or run server.") | ||||||
|  |     parser.add_argument('--server', action='store_true', | ||||||
|  |                         help='Run the Flask server to control lights via API') | ||||||
|  |  | ||||||
|  |     args = parser.parse_args() | ||||||
|  |  | ||||||
|  |     if args.server: | ||||||
|  |         print("Starting Flask server...") | ||||||
|  |         app.run(host='0.0.0.0', port=5000) | ||||||
|  |     else: | ||||||
|  |         print("Running tower control manually...") | ||||||
|  |         run(tower) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | if __name__ == '__main__': | ||||||
|  |     main() | ||||||
							
								
								
									
										1
									
								
								server/requirements.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | |||||||
|  | Flask==3.1.0 | ||||||