Compare commits

..

6 Commits

Author SHA1 Message Date
bdd1cae5ae fix(dashboard): fix temperature gauge positioning when low temp is 0
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 1m6s
2025-11-19 10:34:47 +00:00
Ona
3af86d80c7 fix(backend): add token expiration handling for beszel auth
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 1m18s
- Track token expiry time to prevent using expired tokens
- Set token lifetime to 50 minutes (safe margin before 1hr expiry)
- Add comprehensive logging for auth events and errors
- Improve error responses with status text
- Fixes system tiles stopping after ~1 hour of operation

Co-authored-by: Ona <no-reply@ona.com>
2025-11-17 22:48:48 +00:00
8093f563f9 fix(dashboard): make kuromi wider
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 1m5s
2025-11-01 01:29:06 +00:00
0db96869e1 feat(dashboard): add kuromi animation
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 2m0s
2025-11-01 01:12:57 +00:00
96d59c763d fix(dashboard): light control text color
Co-authored-by: Ona <no-reply@ona.com>
2025-11-01 01:12:40 +00:00
b70d768eee fix(dashboard): northern line label color 2025-10-31 23:28:18 +00:00
7 changed files with 635 additions and 6 deletions

View File

@@ -32,6 +32,7 @@ beszel.get("/systems", async (c) => {
const token = c.get("beszelToken")
if (!beszelHost) {
console.error("[Beszel API] BESZEL_HOST environment variable not set")
return c.json({ error: "BESZEL_HOST environment variable not set" }, 500)
}
@@ -42,10 +43,17 @@ beszel.get("/systems", async (c) => {
})
if (!response.ok) {
const errorText = await response.text()
console.error(
`[Beszel API] Failed to fetch systems: ${response.status} ${response.statusText}`,
errorText ? `- ${errorText}` : "",
)
return new Response(
JSON.stringify({
error: "Failed to fetch Beszel data",
status: response.status,
statusText: response.statusText,
}),
{
status: response.status,
@@ -66,12 +74,15 @@ beszel.get("/systems", async (c) => {
},
}))
console.log(`[Beszel API] Successfully fetched ${systems.length} systems`)
return c.json({
lastUpdated: new Date().toISOString(),
systems,
totalSystems: systems.length,
})
} catch (error) {
console.error("[Beszel API] Internal server error:", error)
return c.json({ error: "Internal server error", message: String(error) }, 500)
}
})

View File

@@ -6,12 +6,26 @@ interface BeszelAuthResponse {
export function beszelAuth(): MiddlewareHandler {
let cachedToken: string | null = null
let tokenExpiry: number | null = null
// Token lifetime: 50 minutes (tokens typically expire after 1 hour, refresh before that)
const TOKEN_LIFETIME_MS = 50 * 60 * 1000
const authenticate = async (): Promise<string> => {
if (cachedToken) {
const now = Date.now()
// Return cached token if it exists and hasn't expired
if (cachedToken && tokenExpiry && now < tokenExpiry) {
return cachedToken
}
// Log re-authentication for debugging
if (cachedToken && tokenExpiry && now >= tokenExpiry) {
console.log("[Beszel Auth] Token expired, re-authenticating...")
} else {
console.log("[Beszel Auth] Initial authentication...")
}
const beszelHost = process.env.BESZEL_HOST
const beszelEmail = process.env.BESZEL_EMAIL
const beszelPassword = process.env.BESZEL_PASSWORD
@@ -34,11 +48,16 @@ export function beszelAuth(): MiddlewareHandler {
})
if (!response.ok) {
const errorText = await response.text()
console.error(`[Beszel Auth] Authentication failed: ${response.status} - ${errorText}`)
throw new Error(`Beszel authentication failed: ${response.status}`)
}
const data = (await response.json()) as BeszelAuthResponse
cachedToken = data.token
tokenExpiry = now + TOKEN_LIFETIME_MS
console.log(`[Beszel Auth] Authentication successful, token valid until ${new Date(tokenExpiry).toISOString()}`)
return cachedToken
}
@@ -49,6 +68,7 @@ export function beszelAuth(): MiddlewareHandler {
c.set("beszelToken", token)
await next()
} catch (error) {
console.error("[Beszel Auth] Middleware error:", error)
return c.json({ error: "Authentication failed", message: String(error) }, 500)
}
}

View File

@@ -7,6 +7,7 @@ import { useEffect, useLayoutEffect, useRef, useState } from "react"
import { beszelSystemsQuery } from "./beszel"
import cn from "./components/lib/cn"
import { Tile } from "./components/tile"
import { Kuromi } from "./kuromi"
import {
LightControlTile,
type LightSceneConfig,
@@ -26,6 +27,21 @@ import {
weatherDescriptionQuery,
} from "./weather"
const kuromi = `
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⣀⣀⢠⠋⠉⠉⠒⠲⢤⣀⣠⡀
⠀⠀⠀⠀⠀⠀⣀⣀⣀⢀⡠⠖⠋⠉⠀⠀⠀⠀⠉⠉⠢⣄⠀⠀⠀⢀⠼⠤⠇
⠀⠀⠀⣀⠔⠊⠁⠀⢨⠏⠀⠀⠀⣠⣶⣶⣦⠀⠀⠀⠀⠀⠱⣄⡴⠃⠀⠀⠀⠀
⢸⣉⠿⣁⠀⠀⠀⢀⡇⠀⠀⠀⠀⢿⣽⣿⣼⡠⠤⢄⣀⠀⠀⢱⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠑⢦⡀⢸⠀⠀⠀⡠⠒⠒⠚⠛⠉⠀⢠⣀⡌⠳⡀⡌⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠉⠉⣆⠀⢰⠁⣀⣀⠀⠀⣀⠀⠈⡽⣧⢀⡷⠁⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⡤⢄⠀⠈⠢⣸⣄⢽⣞⡂⠀⠈⠁⣀⡜⠁⣩⡷⠿⠆⠀⠀⠀⠀⠀
⠀⠀⠀⠀⢯⣁⡸⠀⠀⠀⡬⣽⣿⡀⠙⣆⡸⠛⠠⢧⠀⡿⠯⠆⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⣀⡀⠀⠀⡤⠤⣵⠁⢸⣻⡤⠏⠀⠀⠀⠀⢹⠀⠀⠀⡊⠱⣀⠀⠀⠀
⠀⠀⢀⠜⠀⢘⠀⠀⠱⠲⢜⣢⣤⣧⠀⠀⠀⠀⠀⢴⠇⠀⠀⠀⠧⠠⠜⠀⠀⠀
⠀⠀⠘⠤⠤⠚⠀⠀⠀⠀⠀⠀⢸⠁⠁⠀⣀⠎⠀⠻⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠣⣀⣀⡴⠤⠄⠴⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀
`
function App() {
const wsProtocol = window.location.protocol === "https:" ? "wss:" : "ws:"
const wsHost = import.meta.env.VITE_API_HOST || window.location.host
@@ -142,7 +158,9 @@ function App() {
}}
/>
<Tile className="row-start-5 col-span-2 row-span-1" />
<Tile className="row-start-5 col-start-3 col-span-2 row-span-1 flex items-center justify-center overflow-hidden">
<Kuromi />
</Tile>
</div>
</div>
)
@@ -233,7 +251,11 @@ function WeatherTile() {
const temperature = Math.round(currentWeather.temperature)
const lowTemp = Math.round(dailyForecastData?.forecastDaily?.days[0].temperatureMin ?? 0)
const highTemp = Math.round(dailyForecastData?.forecastDaily?.days[0].temperatureMax ?? 0)
const percentage = lowTemp && highTemp ? (temperature - lowTemp) / (highTemp - lowTemp) : 0
// Calculate percentage: handle case where lowTemp might be 0 (falsy) by checking for valid numbers
const tempRange = highTemp - lowTemp
const percentage = tempRange !== 0 && !Number.isNaN(tempRange)
? Math.max(0, Math.min(1, (temperature - lowTemp) / tempRange))
: 0
const highlightIndexStart = Math.floor((1 - percentage) * 23)
const WeatherIcon = getWeatherIcon(currentWeather.conditionCode)
@@ -425,7 +447,7 @@ function TFLDistruptionItem({ lineId, reason, severity }: { lineId: TubeLine; re
lineStyleClass = "bg-purple-800"
break
case "northern":
lineStyleClass = "bg-black dark:bg-neutral-200 text-black"
lineStyleClass = "bg-black text-neutral-200 dark:bg-neutral-200 dark:text-black"
break
case "piccadilly":
lineStyleClass = "bg-blue-900"

View File

@@ -0,0 +1,550 @@
[
[
" ",
" ",
" ",
" #*++*# ",
" *=.....= ",
" *-.......= ",
" %*.........* ",
" #-.........* ",
" #..........+ ",
" #..........* ",
" *+.........* ",
" %*........+# ",
" #*......=# ",
" #*+::=**# ",
" @%******# ",
" *******# ",
" %********# ",
" **********# ",
" ****..-****# ",
" #***-....+***# ",
" #***......=***# ",
" ***-.......:***# ",
" @***..........***% ",
" #**-...........*** ",
" ***.............+** ",
" **+..............=** ",
" %**................-** ",
" ***.................:** ",
" **-..................:** ",
" %**.....................** ",
" #*+.......:..............** ",
" **........-...............** ",
" **........=..-.............*# ",
" %*=........+.+...............+# ##*#% ",
" #*.......-+**.................+% *:...=*% ",
" *+.....:-+***-:................+# =.......*% ",
" *-........**+...................*% #........:* ",
" %*........+:*-:...................** :.........* ",
" *+.......=..=.:....................* ..........+# ",
" *:......:...-.......................* :.........+# ",
" %*...........:.......................-# %##+.........*@ ",
" %+.......:...:........................=% ###****+=--:*.........* ",
" *........:.............................+% *:---...............:*.......*% ",
" *........=..............................* +-.........................-*:...=*% ",
" +.......=+.......................:-=+++******##% @#****-:.............................:*#***# ",
" #:.....:-+++:................-+**+++==-----::--=+****#% %**+=...................................*% ",
" #.........+..............-**+--------------::.......:+***%% **.......................................* ",
" *.........:...........-*+::----------------::...........:+**% @*.......................................=# ",
" *.........:.........=+:.--------------------:..............:+*## #+.......................................* ",
" +.................+=.-----------------------:.................-**% *.......................................-* ",
" -................:.-------------------------::..................:** *.......................................*# ",
" #-...................:-----------------------::.....................*+.......................................* ",
" %:.....................::---------------------::....................:-......................................+# ",
" *........................:-------------------::....................=.......................................* ",
" *:.......+................::-----------------::...................+......................................+* ",
" #=.....+..................::=+++=-----------::...................+.....................................:* ",
" %*..:+..................=**#%%%#**+---------::........................................................+* ",
" #=+.................-*#%%%%%%%%%%*=-------:::......................................................=*% ",
" #+.................+*%%%%%%%%%%%%%%*-------::......................................................+* ",
" %*.................+*%%%%%%%%%%%%%%%%#------:::....................................:..:............+*# ",
" *.................+*%%%%%%%%%%%%%%%%%%*------:::................................-..-.-............:+* ",
" *:.................*%%%%%%%%%%%%%%%%%%%%+-----::::................................+.+=.............++% ",
" #=.................*%%%%%%%%%%%%%%%%%%%%%%=-----:::.................................**+............=+* ",
" #*..................*%%%%%%%%%%%%%%%%%%%%%%*------:::.............................-=****:...........++# ",
" *:.................:#%%%#%%%%%%%%%%%%%%%%%%*------::::...............................+*+...........++* ",
" #+..................=%%%=.#%%%%%%%%%%%%%%%%%#+::----::::.............................+.*.:.........=++# ",
" *...................=%%%...#%%%%%%%%%%%%%%%%%+:::----::::...........................-..+..........:++*% ",
" #+...................:%%=....%%%%%%%%%%%%%%%%%=.:::----::::.............................=..........+++# ",
" *.....................#%:....%%%%%%%%%%%%%%%%%...:::---:::::............................:.........+++* ",
" #*.....................*%*...%%%%%%%%%#=..%%%%%....:::---:::::...........................:........=+++# ",
" *:.....................:%%*=%%%%%%%%%%....-%%%%.....::::--::::::.........................:.......:++++ ",
" *.......................*%%%%%%%%%%%%#.....%%%*......::::--::::::................................++++# ",
" #+........................*%%%%%%%%%%%%....:%%%:.......::::--::::::..............................+++++ ",
" *:.........................*%%%%%%%%%%%:...%%%*.........::::--::::::............................+++++# ",
" *..............=**=........+%%%=%%%%%%%%#+%%%#:..........::::--:::::::.........................++++++ ",
" *...........:*@@@@@*-......*%%=:%.%%%%%%%%%%#=............::::--::::::::......................++++++* ##*% ",
" %=.........*@@@@@@@@@*:.....+*#.#%.%%%%%%%%%*=..............::::--::::::::....................+++++++% #**-.# ",
" #-.......*@@@@@@@@@@@@*:......-***.%%#*****+.................:::---:::::::::................-+++++++*#**=....* ",
" *......:*@@@@+@@@@@@@@@*-........+**%*.......................::::---::::::::::............-++++++++**+.......+ ",
" *......*@@@@@+#@@@@@@@@@*:.........:+*........................::::----::::::::::........+*+++++++++*.........- ",
" *.....*@@@@#@%=@@@@@@@@@@*:......................:+**=.........::::----:::::::::::........-+**++++*+..........# ",
" *....-@@@@@#++==@@@@@@@@@@*:..................=*#@@@@@**:.......::::----:::::::::::::........*#***##*:........+ ",
" *....@@@@@@@====+@@@@@@@@@@*:..............=@@@@@@@@@@@@*+......:::::-----:::=::::::::::.....* #*........- ",
" *...=@@@@@@@=++==+@@@@@@@@@@*:.......:=*%@@@@@@@@@@@@@@@@%*......::::------::+:::::::::::::::* *.........**# ",
" *...%@@@@@@+#@@%==*@@@@@@@@@@**=-:+**%@@@@@@@@@@@@@@@@@@@@@*:.....::::-------+:::::::::::::::* *.....*:..%@#* ",
" *...@@@@@@@+#*=====#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*-....:::::------+:::::::::::::::* %-.....**+.*@@%* ",
" *..-@@@@@@#+@*++====#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*:....::::-----+*+-:::::::::::::* *.....+%@@**@@@* ",
" *..=@@@@@@+++++++++==@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*....:::::--+=-*-=+::::::::::::* @=.....*@@@@#@@@*% ",
" *..+@@@@@@++++++++++*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*....:::::---+*+-==-::::::::::* #*@*.....-*@@@@@@@@*% ",
" #..+@@@@@@++++++++++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+#@@@@%+....::::*-=***+-*---::::::::***%@#......*@@@@@@@@@* ",
" ..+@@@@@@++++++++++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%++@@@@@@*:...:::-+********=----::::::*%@@+......=#@@@@@@@@@* ",
" ..=@@@@@@*++++++++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+===@%@@@@@@*....:::+-*****=*-------:::.*#+........*@@@@@@@@@%* ",
" +.-@@@@@@@+++++++*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*======%+@@@@@@#=...:::+:-***--+---------::+.........*@@@@@@@@@@* ",
" #..%@@@@@@%**+++*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#======+==+%@@@@@@@*...::::+--*=-*-----------==.......-+@@@@@@@@@@@* ",
" -.*@@@@@@@@***@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*++===+%@+==@@@@@@@@#:...::::*+*+*------------*+++++++++@@@@@@@@@@@* ",
" *.*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*+++++++@===@@@@@@@@@*...:::::-*--------------*%++++++#@@@@@@@@@@@*# ",
" #:=@@@@@@@@@@@@@@@@@@@@@@%%@@@@@@@@@@@@@@@@@*++++++++@++@@@@@@@@@*....:::::+--------------*@@*+#%@@@@@@@@@@@@#* ",
" *.*@@@@@@@@@@@@@@@@@@@@*##*@@@@@@@@@@@@@@@@#+++++++++++@@@@@@@@@#:...::=::+-------------+%@@@*#@@@@@@@@@@@@#* ",
" @=*@@@@@@@@@@@@@@@@@@@*#%%%%@@@@@@@@@@@@@@@%+++++++++++@@@@@@@@@@+...::=::+-------------*@@@@@#*@@@@@@@@@@*# ",
" *-#@@@@@@@@@@@@@@@@@@@*%%%#@@@@@@@@@@@@@@@@++++++++++%@@@@@@@@@@+....:#:::------------=#@@@@@@#*@@@@@@@@@* ",
" **@@@@@@@@@@@@@@@@@@@#*###@@@@@@@@@@@@@@@@++++++++++@@@@@@@@@@@*....=%#:::-----------*@@@@@@@@#*@@@@@@@@* ",
" #*#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%++++++++*@@@@@@@@@@@*....#%%-::----------=#@@@@@@@@@#*@@@@@@%% ",
" #*@@@@@@@@@@@@@@@@@@@@@@@@@#*#@@@@@@@@@@@@**++++++@@@@@@@@@@@@*.....#-:::----------*%@@@@@@@@@@#*@@@@@*% ",
" **@@@@@@@@@@@@@@@*@@@@@@@%*%##@@@@@@@@@@@@%*****@@@@@@@@@@@@@*.....+:::::--------+#@@@@@@@@@@@@%*%@@@* ",
" **@@@@@@@@@@@@@@@*@@@@@@*%#%#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+.....=:::::-------=*@@@@@@@@@@@@@@@*#@%% ****% ",
" #**##**#@@@@@@@@@@**%@@*%###@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=.....::::::-------*%@@@@@@@@@@@@@@@@%**%@@%@@@@**@ ",
" #*@@@@@@%*%@@@@@@@@@@#*****#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@:......::::::-----*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*# ",
" @*@@@@@@@@@*#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#.......::::::----*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* ",
" #%@@@@@@@@@@*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*.......::::::---+%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* ",
" *@@@@@@@@@@@@*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%........:::::::-*%@@%#*#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# ",
" *@@@@@@@@@@@@@%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=........:::::::*%@@%*####@@@@@@@@@@@@@@@@@@@@@@@@@@@@# ",
" #%@@@@@@@@@@@@*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#.........:::::=*#@@@*######@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ",
" *@@@@@@@@@@@@#*%@@@@@@@@@@@@@@@@@@@@@@@*****#@@@@@@@@@@@@%...........:::*+..=*#*######@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ",
" %#@@@@@@@@@@@%@#*#@@@@@@@@@@@@@@@@@@@**@@@@@%*%@@@@@@@@@%............:-+-......*######@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ",
" ##@@@@@@@@@@@@@@%**%@@@@@@@@@@@@@@@*%@@@@@@@@*%@@@@@@@#:..........=+++........*#####*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ",
" %*@@@@@@@@@@@@@@@****#@@@@@@@@@@@*@@@@@@@@@@@*@@@@@%*.........-*+++:........*%*###*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# ",
" %*% @@@@*+++++*#@@@@@@@*%@@@@@@@@@@@*@@@%*:......-+*++++-........+#@@@***@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* ",
" %*#@ @*+++++++++++**#%*@@@@@@@@@@@@*%**...:=+***+++++-.......-*#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# ",
" @% **###% *-=+++++++++++*@*@@@@@@@@@@@@@********+++++****++==++**%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# ",
" *#*######*:....:=++++**%@@*@@@@@@@@@@@@@*+++++++++++=*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* ",
" %*######*.......-+**%@@@@@*@@@@@@@@@@@@#+++++++++-...#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* ",
" *######********##%*%@@@@@*@@@@@@@@@@@@*+==-........-%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* ",
" %*#####* #* #*@@@@*@@@@@@@@@@@**............=@@@@@@@@@@@@@@@@@@@@@@@@#%@@@@@@@@@@@@@@@@@#@@@@@@@@@@@%# ",
" **###*@ %** *#@@#@@@@@@@@@%*@#*...........=@@@@@@@@@@@@@@@@@@@@@@%* #*%%@@@@@@@@@%%**% *%@@@@@@@@@*% ",
" #***#***# #*#@*@@@@@@@@@@@@#+..........=@@@@@@@@@@@@@@@@@@@@@## #***********# %*%@@@@@@@%* ",
" %%# %**@@@@@@@@@@@@@#*.........:%@@@@@@@@@@@@@@@@@@%*@ #**# **%@@@@#*@ ",
" %*@@@@@@@@@@@@@@*-........*@@@@@@@@@@@@@@@@%*% %****** ",
" #*@@@@@@@@@@@@@@**:......*#*#@@@@@@@@@@%**# ",
" #*@@@@@@@@@@@@@@%**-...:*####@@@@@%#**# ",
" #*@@@@@@@@@@@@@@@@#**+*#####*****#@ ",
" #**@@@@@@@@@@@@@%*****######% ",
" #***#%%@@%##*## #*###### ",
" %##**#%@ *#####* ",
" %*###*# ",
" %***# "
],
[
" ",
" ",
" ",
" ",
" ",
" ",
" #**#@ ",
" #*....:+ ",
" #+.......= ",
" *.........@ ",
" #=.........* ",
" *:.........+ ",
" *:.........* ",
" #=.........* ",
" *........-# ",
" #+......:* ",
" #*-..:+** ",
" ********% ",
" %*******% ",
" #********# ",
" *********** ",
" ****..:***** ",
" %***-....-**** ",
" ****.......+***% ",
" ***=........-***% ",
" ***...........***% ",
" ***............=**# ",
" @**=..............*** #**# ",
" #**................+** #=...-*# ",
" ***.................-**@ #.......*% ",
" **+...................**% .........* ",
" @**.....................+*@ -.........+% ",
" #**......................=*# -.........-* ",
" %*+........................*# =.........:* ",
" **-.......-.................*% *.........=# ",
" **........+..................+# ##***-........* ",
" **......-.*.=.................=# %##**+=....*.......+# ",
" *+.......***...................-* #*+=...........*=...:*# ",
" #*.......=****-..................-* %--.................=*****% ",
" #*........+**.....................:* #+=......................*% ",
" **........:*.-.....................:* =...........................* ",
" *=.......:.-........................:# @#**=.............................:* ",
" *.......:............................:# #**+-................................*# ",
" *.....................................-# #*+....................................* ",
" %+......................................*####*##*%% *+.....................................:* ",
" *-...............................:=****+++==----==+****## *......................................+% ",
" *........=....................+**+=-------::...........-+***%% *......................................* ",
" *.......:+:...............:+*+-------------:...............:+**# @=.....................................-* ",
" *.....:=+++:............=*=.---------------::..................=**%#:.....................................*# ",
" %+........+............*+.------------------::.....................+*......................................* ",
" #-........=..........+=.---------------------:......................*.....................................+* ",
" *:........:........+=.-----------------------::.....................*.....................................*# ",
" #:................+.--------------------------::....................*....................................=* ",
" #...................:-------------------------::....................=....................................+* ",
" *......................::---------------------:::.......................................................=*% ",
" #.........................::-------------------:::......................................:...............+* ",
" %...........................:::-=+++=-----------::......................................+..............++# ",
" *:........+.................-**#####**+--------:::...................................:.*.+............+*% ",
" #=......*.................**%%%%%%%%%%*=-------:::...................................***............++* ",
" %*:...*................=*%%%%%%%%%%%%%%*-------:::.................................:****:.........:++% ",
" %+.+................=*%%%%%%%%%%%%%%%%#------::::.................................-**=..........++*% ",
" *:...............-*%%%%%%%%%%%%%%%%%%#------::::................................+-=.=........:++* ",
" %+................*%%%%%%%%%%%%%%%%%%%%*------::::..............................-..=..:.......+++% ",
" @*................+#%%%%%%%%%%%%%%%%%%%%#+------::::................................=.........=++* ",
" *.................*%%%%%%%%%%%%%%%%%%%%%%*:-----:::::...............................=.........+++* ",
" %+................:*%%%%%%%%%%%%%%%%%%%%%%*=::----:::::..............................:........++++ ",
" *.................=%%%%*%%%%%%%%%%%%%%%%%%%+:::----:::::.....................................=+++* ",
" #+.................=%%%..=%%%%%%%%%%%%%%%%%%=.::::---::::::...................................++++% ",
" *..................=%%%....%%%%%%%%%%%%%%%%%-..::::---::::::.................................+++++ ",
" *+..................:%%+....%%%%%%%%%%%#%%%%%:....:::---:::::::..............................+++++* ",
" *....................*%+....%%%%%%%%=....%%%%......::::--:::::::............................=+++++* ",
" %*....................+%%...%%%%%%%%%.....%%%%.......::::---:::::::.........................-+++++* ",
" *-.....................#%%%%%%%%%%%%%.....%%%*........::::---:::::::.......................-++++++* ",
" *.......................%%%%%%%%%%%%%-....%%%-.........::::---::::::::....................=++++++*% ",
" #*.......................:#%%%%%%%%%%%%:..*%%*............::::--:::::::::.................++++++++* ",
" #+.........................*%%%%%%%%%%%%%%%%#-.............::::---:::::::::...........:-++++++++++# ##*% ",
" *:.........................*%%:+%+%%%%%%%%%*=...............::::---:::::::::::..........-****++++* #**:.# ",
" *.............-****=.......*%%.#%.%%%%%%%#*-.................::::---::::::::::::............*###*# %#**-....* ",
" *...........-#@@@@@#*......-**+%*.%%*****=...................:::::----::::::::::::::........* %#**+.......+ ",
"%*.........-@@@@@@@@@%*........:+***%*:........................:::::-----::::::::::::::::::::+ *+..........- ",
"#+.......-#@@@@@@@@@@@@*:..........-+*...........:*****=........:::::-----:::-:::::::::::::::+# %*+..........# ",
"%=......+*@@@*@@@@@@@@@@*-.....................+*@@@@@@%*+.......:::::------:::::::::::::::::-* #*:........+ ",
"#:.....+*@@@@*+@@@@@@@@@@*+..................#@@@@@@@@@@@%*-......::::--------::::::::::::::::* %*........- ",
"*......*@@@@%@+%@@@@@@@@@@**.............-*@@@@@@@@@@@@@@@@*+......::::-------=-::::::::::::::* *.........**# ",
"*.....+@@@@@+@==%@@@@@@@@@@#*.........=*@@@@@@@@@@@@@@@@@@@@%*.....:::::----+=*=*-::::::::::::* *.....*:..%@%* ",
"*.....@@@@@@+=@==#@@@@@@@@@@%*=....+*#@@@@@@@@@@@@@@@@@@@@@@@@*.....:::::--+-+*--*--::::::::::* %-.....**+.*@@%* ",
"#....#@@@@@@*=@===*@@@@@@@@@@@#***#@@@@@@@@@@@@@@@@@@@@@@@@@@@@*.....::::-+--***--+---::::::::* *.....+%@@**@@@* ",
"%....@@@@@@@+@@@+==+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*....:::::+=*******=----::::::* @=.....*@@@@%@@@*% ",
"#:...@@@@@@@++@=====+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+%@@@@%*....::-+*******+*--------::-* #*@*.....-#@@@@@@@@*% ",
"%=..-@@@@@@+#@@++++==+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*+@@@@@@#+....:::+:+***--*-----------* **%@#......*@@@@@@@@@* ",
" +..+@@@@@@+++++++++++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*==@@@@@@@@*:...:::-:-=**-=-----------=#*%@@+......=#@@@@@@@@@* ",
" *..+@@@@@@++++++++++%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+====@+%@@@@@@*....:::+--*=++-----------+*%#+........*@@@@@@@@@%* ",
" *..+@@@@@@++++++++++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+===%===+@@@@@@@#=...:::::+*+-------------*-:.........*@@@@@@@@@@* ",
" %..=@@@@@@++++++++++@@@@@@@@@@@@@@@@@@@@@@@@@@@@======@===@@@@@@@@@*....:::::---------------*=........-+@@@@@@@@@@@* ",
" ..:@@@@@@*++++++++@@@@@@@@@@@@@@@@@@@@@@@@@@@@++====@@%==@@@@@@@@@%=...:::-::-------------=*++++++++++@@@@@@@@@@@* ",
" -..%@@@@@@+++++++*@@@@@@@@@@@@@@@@@@@@@@@@@@@@+++++++%+@+@@@@@@@@@@*....::-::-------------+%@%++++++#@@@@@@@@@@@*# ",
" ..*@@@@@@@***++*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+++++++*+#+@@@@@@@@@@*....::*:::------------*@@@@*+#%@@@@@@@@@@@@#* ",
" :.*@@@@@@@@#**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+++++++++++@@@@@@@@@@%-....:%:::-----------=#@@@@@*#@@@@@@@@@@@@#* ",
" #.=@@@@@@@@@@@@@@@@@@@@@@#*#@@@@@@@@@@@@@@@@@*++++++++++@@@@@@@@@@@+....%%%#+:----------*%@@@@@@#*@@@@@@@@@@*# ",
" +.*@@@@@@@@@@@@@@@@@@@@*#%%*@@@@@@@@@@@@@@@@%++++++++++@@@@@@@@@@@*....=%*:::---------=*@@@@@@@@#*@@@@@@@@@* ",
" #.+@@@@@@@@@@@@@@@@@@@@*%%%%@@@@@@@@@@@@@@@@@+++++++++*@@@@@@@@@@@*.....#:::::--------*@@@@@@@@@@#*@@@@@@@@* ",
" @*.#@@@@@@@@@@@@@@@@@@@%*%%%*@@@@@@@@@@@@@@@@%++++++++@@@@@@@@@@@@*.....-:::::-------+#@@@@@@@@@@@#*@@@@@@%% ",
" %++@@@@@@@@@@@@@@@@@@@@%***@@@@@@@@@@@@@@@@@@#*****+%@@@@@@@@@@@@*.....:::::::------*@@@@@@@@@@@@@%*@@@@@*% ",
" *=*@@@@@@@@@@@@@@@@@@@@@@@@@@@*#@@@@@@@@@@@@@@#**#@@@@@@@@@@@@@@*......::::::-----*%@@@@@@@@@@@@@@%*%@@@* ",
" *+%@@@@@@@@@@@@@@@@@@@@@@@@@*%%*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+......::::::----*%@@@@@@@@@@@@@@@@@*#@%% @****# ",
" **%**##**#@@@@@@@@#@@@@@@@##%%*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=......:::::::--+#@@@@@@@@@@@@@@@@@@@@**%@@%@@@@**% ",
" **@@@@@@%*%@@@@@@@#*@@@@@*%*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@:.......::::::-=#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*# ",
" @*@@@@@@@@@*#@@@@@@@@***%*#**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#........::::::=#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* ",
" #%@@@@@@@@@@*@@@@@@@@@@@%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@:........:::::+%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# ",
" *@@@@@@@@@@@@*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%.........::::*%@@@@@%#*#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# ",
" *@@@@@@@@@@@@@%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@..........:::*%@@@@@%*####@@@@@@@@@@@@@@@@@@@@@@@@@@@@# ",
" #%@@@@@@@@@@@@*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@:..........:...:*#@@@*######@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ",
" *@@@@@@@@@@@@#@@@@@@@@@@@@@@@@@@@@@@@@@*****#@@@@@@@@@@@@*.........-+...-+..-*#*######@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ",
" ##@@@@@@@@@@@%@@@@@@@@@@@@@@@@@@@@@@@**@@@@@%*%@@@@@@@@%*........++..-++=......*######@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ",
" ##@@@@@@@@@@@*#@@@@@@@@@@@@@@@@@@@@*%@@@@@@@@*%@@@@@@%+......=*+-=++++........*#####*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ",
" %*@@@@@@@@@@@%**#@@@@@@@@@@@@@@@@*@@@@@@@@@@@*@@@@%*:....=**+++++++:........*%*###*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# ",
" %*% @@@%***%@@@@@@@@@@@*%@@@@@@@@@@@*@@%*=.:=***++++++++-........+#@@@***@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* ",
" %*#% @*++++++**%@@@@@%*@@@@@@@@@@@@********++++++++++-.......=*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# ",
" @% **#### *--+++++++++++***@@@@@@@@@@@@@**+++++++++++****++==++**%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%# ",
" *#*#####%*:....:=++++**%@@*@@@@@@@@@@@@@*+++++++++++=*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* ",
" %*######*.......-+**%@@@@@*@@@@@@@@@@@@#+++++++++-...#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* ",
" *######********##%*%@@@@@*@@@@@@@@@@@@*+=--........-%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* ",
" %*#####* #* #*@@@@*@@@@@@@@@@@**............=@@@@@@@@@@@@@@@@@@@@@@@@#%@@@@@@@@@@@@@@@@@#@@@@@@@@@@@%# ",
" **###*@ %** *#@@#@@@@@@@@@%*@#*...........=@@@@@@@@@@@@@@@@@@@@@@%* #*%%@@@@@@@@@%%**% *%@@@@@@@@@*% ",
" #***#***# #*#@*@@@@@@@@@@@@#+..........-@@@@@@@@@@@@@@@@@@@@@## #***********# %*%@@@@@@@%* ",
" %%* #**@@@@@@@@@@@@@#*.........:%@@@@@@@@@@@@@@@@@@%*@ #**# **%@@@@#*@ ",
" %*@@@@@@@@@@@@@@*-........*@@@@@@@@@@@@@@@@%*% %****** ",
" #*@@@@@@@@@@@@@@**:......*#*#@@@@@@@@@@%**# ",
" **@@@@@@@@@@@@@@%**=...:*####@@@@@%#**# ",
" #*@@@@@@@@@@@@@@@@#**+*#####*****#@ ",
" #**@@@@@@@@@@@@@%*****######% ",
" #***#%%@@%##*#% **###### ",
" %##**##@ *#####* ",
" %*###*# ",
" %***% "
],
[
" ",
" ",
" ",
" #*++*# ",
" *=.....= ",
" *-.......= ",
" %*.........* ",
" #-.........* ",
" #..........+ ",
" #..........* ",
" *+.........* ",
" %*........+# ",
" #*......=# ",
" #*+::=**# ",
" @%******# ",
" *******# ",
" %********# ",
" **********# ",
" ****..-****# ",
" #***-....+***# ",
" #***......=***# ",
" ***-.......:***# ",
" @***..........***% ",
" #**-...........*** ",
" ***.............+** ",
" **+..............=** ",
" %**................-** ",
" ***.................:** ",
" **-..................:** ",
" %**.....................** ",
" #*+.......:..............** ",
" **........-...............** ",
" **........=..-.............*# ",
" %*=........+.+...............+# ##*#% ",
" #*.......-+**.................+# *:...=*% ",
" *+.....:-+***-:................+# =.......*% ",
" *-........**+...................*% #........:* ",
" %*........+:*-:...................** :.........* ",
" *+.......=..=.:....................* ..........+# ",
" *:......:...-.......................* :.........+# ",
" %*...........:.......................-# %##+.........*@ ",
" %+.......:...:........................=% ###****+=--:*.........* ",
" *........:.............................+% *:---...............:*.......*% ",
" *........=..............................* +-.........................-*:...=*% ",
" +.......=+.......................:-=+++******##% @#****-:.............................:*#***# ",
" #:.....:-+++:................-+**+++==-----::--=+****#% %**+=...................................*% ",
" #.........+..............-**+--------------::.......:+***%% **.......................................* ",
" *.........:...........-*+::----------------::...........:+**% @*.......................................=# ",
" *.........:.........=+:.--------------------:..............:+*## #+.......................................* ",
" +.................+=.-----------------------:.................-**% *.......................................-* ",
" -................:.-------------------------::..................:** *.......................................*# ",
" #-...................:-----------------------::.....................*+.......................................* ",
" %:.....................::---------------------::....................:-......................................+# ",
" *........................:-------------------::....................=.......................................* ",
" *:.......+................::-----------------::...................+......................................+* ",
" #=.....+..................::=+++==----------::...................+.....................................:* ",
" %*..:+..................=**#%%%#**+---------::........................................................+* ",
" #=+.................-*#%%%%%%%%%%*=-------:::......................................................=*% ",
" #+.................+*%%%%%%%%%%%%%%*-------::......................................................+* ",
" %*.................+*%%%%%%%%%%%%%%%%#------:::....................................:..:............+*# ",
" *.................+*%%%%%%%%%%%%%%%%%%*------:::................................-..-.-............:+* ",
" *:.................*%%%%%%%%%%%%%%%%%%%%+-----::::................................+.+=.............++% ",
" #=.................*%%%%%%%%%%%%%%%%%%%%%%=-----:::.................................**+............=+* ",
" #*..................*%%%%%%%%%%%%%%%%%%%%%%*------:::.............................-=****-...........++# ",
" *:.................:#%%%#%%%%%%%%%%%%%%%%%%*------::::...............................+*+...........++* ",
" #+..................=%%%=.#%%%%%%%%%%%%%%%%%#+::----::::.............................+.*.:.........=++# ",
" *...................=%%%...#%%%%%%%%%%%%%%%%%+:::----::::...........................-..+..........:++*% ",
" #+...................:%%=....%%%%%%%%%%%%%%%%%=.:::----::::.............................=..........+++# ",
" *.....................#%:....%%%%%%%%%%%%%%%%%...:::---:::::............................:.........+++* ",
" #*.....................*%*...%%%%%%%%%#=..%%%%%....:::---:::::...........................:........=+++# ",
" *:.....................-%%*=%%%%%%%%%%....-%%%%.....::::--::::::.........................:.......:++++ ",
" *.......................*%%%%%%%%%%%%#.....%%%*......::::--::::::................................++++# ",
" #+........................*%%%%%%%%%%%%....:%%%:.......::::--::::::..............................+++++ ",
" *:.........................*%%%%%%%%%%%:...%%%*.........::::--::::::............................+++++# ",
" *..............=**=........+%%%=%%%%%%%%#+%%%#:..........::::--:::::::.........................++++++ ",
" *...........:*@@@@@*-......*%%=:%.%%%%%%%%%%#=............::::--::::::::......................++++++* ##*# ",
" %=.........*@@@@@@@@@*:.....+*#.#%.%%%%%%%%%*=..............::::--::::::::....................+++++++% #**-.# ",
" #-.......*@@@@@@@@@@@@*:......-***.%%#*****+.................:::---:::::::::................-+++++++*%**=....* ",
" *......:*@@@@+@@@@@@@@@*-........+**%*.......................::::---::::::::::............-++++++++**+.......+ ",
" *......*@@@@@+#@@@@@@@@@*:.........:+*........................::::----::::::::::........+*+++++++++*.........- ",
" *.....*@@@@#@%=@@@@@@@@@@*:......................:+**=.........::::----:::::::::::........-+**++++*+..........# ",
" *....-@@@@@#++==@@@@@@@@@@*:..................=*#@@@@@**:.......::::----:::::::::::::........*#***##*:........+ ",
" *....@@@@@@@====+@@@@@@@@@@*:..............=@@@@@@@@@@@@*+......:::::-----:::=::::::::::.....* #*........- ",
" *...=@@@@@@@=++==+@@@@@@@@@@*:.......:=*%@@@@@@@@@@@@@@@@%*......::::------::+:::::::::::::::* *.........**# ",
" *...%@@@@@@+#@@%==*@@@@@@@@@@**=-:+**%@@@@@@@@@@@@@@@@@@@@@*:.....::::-------+:::::::::::::::* *.....*:..%@#* ",
" *...@@@@@@@+#*=====#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*-....:::::------+:::::::::::::::* %-.....**+.*@@%* ",
" *..-@@@@@@#+@*++====#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*:....::::-----+*+-:::::::::::::* *.....+%@@**@@@* ",
" *..=@@@@@@+++++++++==@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*....:::::--+=-*-=+::::::::::::* @=.....*@@@@#@@@*% ",
" *..+@@@@@@++++++++++*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*....:::::---+**-==-::::::::::* #*@*.....-*@@@@@@@@*% ",
" #..+@@@@@@++++++++++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+#@@@@%+....::::*-=***+-*---::::::::***%@#......*@@@@@@@@@* ",
" ..+@@@@@@++++++++++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%++@@@@@@*:...:::-*********=----::::::*%@@+......=#@@@@@@@@@* ",
" ..=@@@@@@*++++++++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+===@%@@@@@@*....:::+-*****=*-------:::.*#+........*@@@@@@@@@%* ",
" +.-@@@@@@@+++++++*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*======%+@@@@@@#=...:::+:-***--+---------::+.........*@@@@@@@@@@* ",
" #..%@@@@@@%***++*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#======+==+%@@@@@@@*...::::+--*=-*-----------==.......-+@@@@@@@@@@@* ",
" -.*@@@@@@@@***@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*++===+%@+==@@@@@@@@#:...::::*+*+*------------*+++++++++@@@@@@@@@@@* ",
" *.*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*+++++++@===@@@@@@@@@*...:::::-*--------------*%++++++#@@@@@@@@@@@*# ",
" #:=@@@@@@@@@@@@@@@@@@@@@@%@@@@@@@@@@@@@@@@@@*++++++++@++@@@@@@@@@*....:::::+--------------*@@*+#%@@@@@@@@@@@@#* ",
" *.*@@@@@@@@@@@@@@@@@@@@*##*@@@@@@@@@@@@@@@@#+++++++++++@@@@@@@@@#:...::=::+-------------+%@@@*#@@@@@@@@@@@@#* ",
" @=*@@@@@@@@@@@@@@@@@@@*#%%%%@@@@@@@@@@@@@@@%+++++++++++@@@@@@@@@@+...::=::+-------------*@@@@@#*@@@@@@@@@@*# ",
" *-#@@@@@@@@@@@@@@@@@@@*%%%#@@@@@@@@@@@@@@@@++++++++++%@@@@@@@@@@+....:#:::------------=#@@@@@@#*@@@@@@@@@* ",
" **@@@@@@@@@@@@@@@@@@@#*###@@@@@@@@@@@@@@@@++++++++++@@@@@@@@@@@*....=%#:::-----------*@@@@@@@@#*@@@@@@@@# ",
" #*#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%++++++++*@@@@@@@@@@@*....#%%-::----------=#@@@@@@@@@#*@@@@@@%% ",
" #*@@@@@@@@@@@@@@@@@@@@@@@@@#*#@@@@@@@@@@@@**++++++@@@@@@@@@@@@*.....#-:::----------*%@@@@@@@@@@#*@@@@@*% ",
" **@@@@@@@@@@@@@@@*@@@@@@@%*%##@@@@@@@@@@@@%*****@@@@@@@@@@@@@*.....+:::::--------+#@@@@@@@@@@@@%*%@@@* ",
" **@@@@@@@@@@@@@@@*@@@@@@*%#%#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+.....=:::::-------=*@@@@@@@@@@@@@@@*#@%# ****% ",
" #**##**#@@@@@@@@@@**%@@*%###@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=.....::::::-------*%@@@@@@@@@@@@@@@@%**%@@%@@@@**@ ",
" #*@@@@@@%*%@@@@@@@@@@#*****#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%:......::::::-----*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*# ",
" @*@@@@@@@@@*#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#.......::::::----*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* ",
" #%@@@@@@@@@@*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*.......::::::---+%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* ",
" *@@@@@@@@@@@@*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%........:::::::-*%@@%#*#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# ",
" *@@@@@@@@@@@@@%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=........:::::::*%@@%*####@@@@@@@@@@@@@@@@@@@@@@@@@@@@# ",
" #%@@@@@@@@@@@@*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#.........:::::=*#@@@*######@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ",
" *@@@@@@@@@@@@#*%@@@@@@@@@@@@@@@@@@@@@@@*****#@@@@@@@@@@@@%...........:::*+..=*#*######@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ",
" %#@@@@@@@@@@@%@**#@@@@@@@@@@@@@@@@@@@**@@@@@%*%@@@@@@@@@%............:-+-......*######@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ",
" ##@@@@@@@@@@@@@@%**%@@@@@@@@@@@@@@@*%@@@@@@@@*%@@@@@@@#:..........=+++........*#####*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ",
" #*@@@@@@@@@@@@@@@****#@@@@@@@@@@@*@@@@@@@@@@@*@@@@@%*.........-*+++:........*%*###*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# ",
" %*% @@@@*+++++*#%@@@@@@*%@@@@@@@@@@@*@@@%*:......-+*++++-........+#@@@***@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* ",
" %*#@ @*+++++++++++**#%*@@@@@@@@@@@@*%**...:=+***+++++-.......-*#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# ",
" @% **###% *-=+++++++++++*%*@@@@@@@@@@@@@********+++++****++==++**%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%# ",
" *#*######*:....:=++++**%@@*@@@@@@@@@@@@@*+++++++++++=*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* ",
" %*######*.......-+**%@@@@@*@@@@@@@@@@@@#+++++++++-...#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* ",
" *######********##%*%@@@@@*@@@@@@@@@@@@*+==-........-%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* ",
" %*#####* #* #*@@@@*@@@@@@@@@@@**............=@@@@@@@@@@@@@@@@@@@@@@@@#%@@@@@@@@@@@@@@@@@#@@@@@@@@@@@%# ",
" **###*@ %** *#@@#@@@@@@@@@%*@#*...........=@@@@@@@@@@@@@@@@@@@@@@%* #*%%@@@@@@@@@%%**% *%@@@@@@@@@*% ",
" #***#***# #*#@*@@@@@@@@@@@@#+..........=@@@@@@@@@@@@@@@@@@@@@## #***********# %*%@@@@@@@%* ",
" %%# %**@@@@@@@@@@@@@#*.........:%@@@@@@@@@@@@@@@@@@%*% #**# **%@@@@#*@ ",
" %*@@@@@@@@@@@@@@*-........*@@@@@@@@@@@@@@@@%*% %****** ",
" #*@@@@@@@@@@@@@@**:......*#*#@@@@@@@@@@%**# ",
" #*@@@@@@@@@@@@@@%**=...:*####@@@@@%#**# ",
" #*@@@@@@@@@@@@@@@@#**+*#####*****#@ ",
" #**@@@@@@@@@@@@@%*****######% ",
" #***#%%@@%##*## #*###### ",
" %##**#%@ *#####* ",
" %*###*# ",
" #***% "
],
[
" #**#% ",
" %*=...=# ",
" %*.......+ ",
" *:........# ",
" *.........- ",
" %+.........- ",
" #=.........- ",
" +.........+ ",
" *.........* ",
" #*.......*@ ",
" #*:...-*% ",
" #******# ",
" %******% ",
" ******** ",
" ********* ",
" #****-***** ",
" ****...+**** ",
" #***:....-***% ",
" ***+......:***# ",
" ***........:*** ",
" #**+.........:*** ",
" ***............**# ",
" #**=............:**% ",
" ***..............:**@ ",
" @**=...............:** ",
" %**.................-** ",
" **=..................-*# ",
" %**.......:............=*# ",
" #*=.......=.............=* ",
" **........+..............+*@ ",
" %*+.....-..+..-............+* ",
" **.......+.+.+..............*# ",
" *+........***................*# ",
" %*.......:****+:...............* ",
" *+........+**=.................:* ",
" *........=.---..................-# ",
" #*.......:..-..-..................+% ",
" *:..........-......................* ",
" *.......:...-.......................* ",
" #-.......-...-.......................=# %*# ",
" *........=...:........................* @*=-=** ",
" +.......:+.............................# -.....:*% ",
" #:.....:=+++:...........................-% ........:* ",
" *........:+..............................* =.........*%",
" *.........:.................-=++***********### -.........=#",
" #-......................:+*++-::------------=++***#% +.........-*",
" #....................=*+..------------------::....+**** %*=-*%%##*###*****.........+#",
" *.................-+:.:---------------------::.......:***% %##******::..........................*.........*%",
" *..................:------------------------::..........:**% #**+--..................................:*.......-* ",
" #...................:-----------------------::.............+*#- %*........................................+*.....=* ",
" *....................:----------------------:...............=*# *:........................................=#**++*# ",
" *.......::............:--------------------::................=*# @*.........................................* #@ ",
" *.....+................:------------------::..................+*%%=........................................+# ",
" %:..*..................::----------------::....................**.........................................*% ",
" %++.....................:====------------::....................*........................................+# ",
" #=...................:***###***=---------::...................:-........................................* ",
" *=...................**%%%%%%%%%#*=-------:::..................+........................................+# ",
" #+..................=*%%%%%%%%%%%%%#+-------::..................+........................................* ",
" #+..................+*%%%%%%%%%%%%%%%%+------:::.................:.......................................*% ",
" @*..................=*%%%%%%%%%%%%%%%%%%+------::........................................................-* ",
" @*...................*%%%%%%%%%%%%%%%%%%%%------:::...................................:...................*% ",
" *-..................+#%%%%%%%%%%%%%%%%%%%%%-----:::...................................:..................+* ",
" #+...................*%%%%%%%%%%%%%%%%%%%%%%*-----:::..................................-.................=* ",
" *....................*%%%:%%%%%%%%%%%%%%%%%%*=-----:::.................................=................:+* ",
" *=...................:#%%...%%%%%%%%%%%%%%%%%#+-----::::................................+..-.............+* ",
" %*....................:%%#...:%%%%%%%%%%%%%%%%%*:-----:::..............................:-*.+.............++# ",
" *-.....................#%-....%%%%%%%%%%%%%%%%%*::----::::..............................***.............-+* ",
" @*......................*%-...:%%%%%%%%%%%%%%%%%+:::----::::............................-***+-:..........++% ",
" #=......................+%%..:%%%%%%%%%%%%%%%%%%..:::----::::............................+*+............++* ",
" *........................%%%%%%%%%%%%%#....%%%%%...:::---:::::..........................:.*.=..........++*% ",
" %+........................:%%%%%%%%%%%%-....#%%%%....:::---:::::...........................+..-........=++* ",
" *:.........................+%%%%%%%%%%%:....#%%%......:::---:::::..........................=..........-++*@ ",
" *............=*#%%*+........*%%%%%%%%%%+....%%%#.......:::--::::::.........................-.........:+++% ",
" #*.........+@@@@@@@@@*......:#%%.%%%%%%%%-..-%%%=........:::--::::::........................:........:+++* ",
" #-......:*@@@@@@@@@@@%+.....+#%#.%++%%%%%%%%%%%+..........:::--::::::.......................:........++++% ",
" *......+*@@@@#@@@@@@@@#+.....-*+=%.*%%%%%%%%%#*...........::::--::::::..............................++++##*# ",
" *.....=#@@@@@+#@@@@@@@@*-......-**.%%%*#%%%#*=.............::::--::::::............................+++++*-.# ",
" *.....@@@@@#%%+@@@@@@@@@*:.......:**%*=-+++-................:::---::::::..........................+++++....* ",
" +....@@@@@@**+=*@@@@@@@@@*.........:**.......................:::---:::::::......................:+++++-....+ ",
" %=...+@@@@@@@====@@@@@@@@@@*..................................::::---:::::::....................=++++++.....- ",
" #-...@@@@@@@#=#===@@@@@@@@@#*......................::..........::::---:::::::..................++++++++......# ",
" *:..=@@@@@@@=%@@===@@@@@@@@@*=................-+**#%@#*=.......::::----::::::::..............=+++++++*.......+ ",
" *...*@@@@@@+*+@====*@@@@@@@@@*+.........-++%@@@@@@@@@@@%*:......::::----:::::::::.......-.-=++++++++++.......- ",
" *...%@@@@@@+@**+====%@@@@@@@@@%**+=***%@@@@@@@@@@@@@@@@@@*=......::::----::::::::::......-*+++++++++*.........**# ",
" %...@@@@@@%++++++++==@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*+.....::::-----:::::::::::.......+*+++++**.....*:..%@#* ",
" ..:@@@@@@*++++++++++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*+.....::::-----::::::::::::......-******=.....**+.*@@%* ",
" ..-@@@@@@+++++++++++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*=....::::------::::::::::::::...-# @#*.....+%@@**@@@* ",
" ..-@@@@@@++++++++++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*-....::::-------:::::::::::::::-* @=.....*@@@@%@@@*# ",
" +.-@@@@@@#++++++++*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*....:::::-----=-::::::::::::::=##*@*.....-*@@@@@@@@*# ",
" +.:@@@@@@@++++++++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%*....::::---++*++:::::::::::::=*%@%......*@@@@@@@@@*@ ",
" #..%@@@@@@#++++++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+*@@@@*-...:::::-+--*=-*-:::::::::::+%@+......=#@@@@@@@@@* ",
" +.*@@@@@@@@***#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+++@@@@@@*....::::+--***--+-::::::::::*+........*@@@@@@@@@@* ",
" *.*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*=====@#@@@@@#=...::::++****+-*--:::::::::*........*@@@@@@@@@@*@ ",
" %-+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*=========*+@@@@@@*...::::=********=---::::::.*......-+@@@@@@@@@@@* ",
" *-@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+======+===+@@@@@@@*:...:::+:+***+-*-----:::::.*+++++++@@@@@@@@@@@* ",
" #=*@@@@@@@@@@@@@@@@@@@****@@@@@@@@@@@@@@@@@++++++#@@#=@@@@@@@@@*...:::+:-**=-==-------:::-++++++#@@@@@@@@@@@*# ",
" *+@@@@@@@@@@@@@@@@@@@*%%%*@@@@@@@@@@@@@@@@+++++++%++=@@@@@@@@@*...::::*-+*-=+----------:+%*+#%@@@@@@@@@@@@#* ",
" #+#@@@@@@@@@@@@@@@@@@*%%%%@@@@@@@@@@@@@@@@+++++++%#@+@@@@@@@@@*:...::::=***=------------*@@*#@@@@@@@@@@@@#* ",
" **@@@@@@@@@@@@@@@@@@#*%%#@@@@@@@@@@@@@@@@+++++++++++@@@@@@@@@@=...:::::----------------*@@@#*@@@@@@@@@@*% ",
" **@@@@@@@@@@@@@@@@@@@**@@@@@@@@@@@@@@@@@+++++++++++@@@@@@@@@@+...:::::---------------+%@@@@#*@@@@@@@@@* ",
" %*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+++++++++++@@@@@@@@@@*....::::---------------*@@@@@@#*@@@@@@@@* ",
" **@@@@@@@@@@@@@@*@@@@@@@@***@@@@@@@@@@@@+++++++++@@@@@@@@@@@*....:=::=-------------=#@@@@@@@#*@@@@@@%% ",
" #*@@@@@@@@@@@@@@*@@@@@@*#%#%@@@@@@@@@@@**++++++#@@@@@@@@@@@*....:%+::-------------*@@@@@@@@@%*@@@@@*# ",
" #*@@@@@@@@@@@@@@*%@@@#*%*%%@@@@@@@@@@@@****++#@@@@@@@@@@@@*...=%%%#-:-----------=#@@@@@@@@@@%*%@@@* ",
" #*@@@@@@@@@@@@@@#***%%*%%@@@@@@@@@@@@@@@%##@@@@@@@@@@@@@@+....:%=:::-----------*@@@@@@@@@@@@@*#@%% ****% ",
" %***#**#@@@@@@@@@@@@@@#*#%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+.....#::::----------*%@@@@@@@@@@@@@@%**%@@%@@@@**% ",
" #*@@@@@@%*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%:.....+:::::--------=*@@@@@@@@@@@@@@@@@@@@@@@@@@@@*% ",
" *@@@@@@@@@*#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#......=:::::-------=*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* ",
" #%@@@@@@@@@@*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*......::::::-------*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# ",
" *@@@@@@@@@@@@*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%:......::::::------*%#*#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# ",
" *@@@@@@@@@@@@@**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#.......:::::::----*%*####@@@@@@@@@@@@@@@@@@@@@@@@@@@@* ",
" #%@@@@@@@@@@@@*%**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@-.......:::::::--=*%*######@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ",
" *@@@@@@@@@@@@#@@%**@@@@@@@@@@@@@@@@@@@@*****#@@@@@@@@@@@@@:........:::::::-++*#*######@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ",
" ##@@@@@@@@@@@%@@@%@#*%@@@@@@@@@@@@@@@**@@@@@%*%@@@@@@@@@@-.........:::::::*:...*######@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ",
" ##@@@@@@@@@@@@@@@#@%+*#@@@@@@@@@@@@*%@@@@@@@@*%@@@@@@@@:..........:::::+=.....*#####*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ",
" %*@@@@@@@@@@@@@@@#*++++*%@@@@@@@@*%@@@@@@@@@@*@@@@@@%=...........:::.-......+%*###*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# ",
" #*# @@@@*++++++++*#%%@@*%@@@@@@@@@@@*%@@@%+.............-........+#@@@***@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* ",
" %##% @*+++++++++++++***@@@@@@@@@@@@*%%**...........=*+.......-*#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# ",
" %% #*#### *-=+++++++++++*%#@@@@@@@@@@@@@*+-.....:-=+*****++===+**#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# ",
" *%*#####%*:....:=++++**%@@*@@@@@@@@@@@@@*********++++*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* ",
" %*######*.......-+**%@@@@@*@@@@@@@@@@@@#+++++++++=...#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* ",
" *######*********#%*%@@@@@*@@@@@@@@@@@@*++=-:.......-%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* ",
" #*#####* #*@ #*@@@@*@@@@@@@@@@@**............=@@@@@@@@@@@@@@@@@@@@@@@@#%@@@@@@@@@@@@@@@@@#@@@@@@@@@@@%# ",
" **###*% %** *#@@#%@@@@@@@@%*@#*...........=@@@@@@@@@@@@@@@@@@@@@@%* #*%%@@@@@@@@@%%**% *%@@@@@@@@@*% ",
" #***#***# #*#@*@@@@@@@@@@@@#+..........-@@@@@@@@@@@@@@@@@@@@@%# %***********# #*%@@@@@@@%* ",
" @#% %**@@@@@@@@@@@@@#*.........:%@@@@@@@@@@@@@@@@@@%*% #%%# **%@@@@#*% ",
" %*@@@@@@@@@@@@@@*-........*@@@@@@@@@@@@@@@@%*% %****** ",
" #*@@@@@@@@@@@@@@**:......*#*#@@@@@@@@@@%**% ",
" **@@@@@@@@@@@@@@%**=...:*####@@@@@%#**# ",
" #*@@@@@@@@@@@@@@@@#**+*#####******% ",
" #**@@@@@@@@@@@@@%*****######% ",
" #***#%@@@%%#**# #*###### ",
" %*#**##% *#####* ",
" %*###*% ",
" #***% "
]
]

View File

@@ -0,0 +1,25 @@
import { useEffect, useState } from "react"
import kuromiFrames from "./assets/kuromi-frames.json"
export function Kuromi() {
const [frameIndex, setFrameIndex] = useState(0)
useEffect(() => {
const interval = setInterval(() => {
setFrameIndex((prev) => (prev + 1) % kuromiFrames.length)
}, 300)
return () => clearInterval(interval)
}, [])
const currentFrame = kuromiFrames[frameIndex]
return (
<pre className="leading-none tracking-[0.6em] select-none font-mono text-black dark:text-white scale-[5%]">
{currentFrame.map((line, index) => (
// biome-ignore lint/suspicious/noArrayIndexKey: frame lines don't have unique identifiers
<div key={index}>{line}</div>
))}
</pre>
)
}

View File

@@ -320,7 +320,7 @@ function BrightnessLevelLabel({ deviceName }: { deviceName: ZigbeeDeviceName })
<p
className={cn(
"flex-1 text-right font-bold font-mono tracking-tigher",
step === 0 ? "text-neutral-400" : "text-teal-400",
step === 0 ? "text-neutral-400" : "text-teal-500 dark:text-teal-400",
)}
>
{label}
@@ -346,7 +346,7 @@ export function LightSceneTile({
className={cn(
"w-full gap-2 flex flex-row items-end justify-start h-full border tracking-tigher first:rounded-t-lg last:rounded-b-lg transition-all duration-150 active:transition-none",
activeSceneId === id
? "p-2 border-teal-500 text-teal-500 border-2 font-bold"
? "p-2 border-teal-500 text-teal-500 dark:text-teal-400 border-2 font-bold"
: "p-[9px] text-neutral-400 border-neutral-300 dark:border-neutral-800 active:shadow-inner active:bg-neutral-300 dark:active:bg-teal-500 active:text-neutral-900 font-lighter",
)}
>

View File

@@ -1,5 +1,6 @@
{
"lockfileVersion": 1,
"configVersion": 0,
"workspaces": {
"": {
"name": "monorepo",