init commit

This commit is contained in:
2025-04-19 17:09:13 +02:00
commit 5ff83ecaeb
39 changed files with 2020 additions and 0 deletions

35
README.md Normal file
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

4
frontend/.env.example Normal file
View 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
View File

@@ -0,0 +1,4 @@
{
"plugins": ["prettier-plugin-svelte"],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
}

28
frontend/Dockerfile Normal file
View 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
View 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
View 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"
}
}

Binary file not shown.

View 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
View 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> &nbsp; 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>

View 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>

View 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>

View 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>

View 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>

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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
View File

@@ -0,0 +1,7 @@
import App from "./App.svelte";
const app = new App({
target: document.getElementById("app"),
});
export default app;

View 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],
];

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@@ -0,0 +1 @@
Flask==3.1.0